mirror of
https://github.com/balzack/databag.git
synced 2025-05-05 07:55:15 +00:00
rendering details screen
This commit is contained in:
parent
275629a4a0
commit
257568e729
@ -7,11 +7,16 @@ export const en = {
|
|||||||
encrypted: 'Encrypted',
|
encrypted: 'Encrypted',
|
||||||
unknown: 'Unknown',
|
unknown: 'Unknown',
|
||||||
sealed: 'Sealed',
|
sealed: 'Sealed',
|
||||||
|
notSealed: 'Not Sealed',
|
||||||
notes: 'Notes',
|
notes: 'Notes',
|
||||||
server: 'Server',
|
server: 'Server',
|
||||||
token: 'Token',
|
token: 'Token',
|
||||||
delayMessage: 'Key generation can take several minutes.',
|
delayMessage: 'Key generation can take several minutes.',
|
||||||
|
|
||||||
|
membership: 'Membership',
|
||||||
|
channelGuest: 'Topic Guest',
|
||||||
|
channelHost: 'Topic Host',
|
||||||
|
created: 'Created',
|
||||||
code: 'en',
|
code: 'en',
|
||||||
settings: 'Settings',
|
settings: 'Settings',
|
||||||
contacts: 'Contacts',
|
contacts: 'Contacts',
|
||||||
@ -44,6 +49,7 @@ export const en = {
|
|||||||
unsetSealing: 'Unset Sealing Key',
|
unsetSealing: 'Unset Sealing Key',
|
||||||
newTopic: 'New Topic',
|
newTopic: 'New Topic',
|
||||||
|
|
||||||
|
subject: 'Subject',
|
||||||
noContacts: 'No Contacts',
|
noContacts: 'No Contacts',
|
||||||
noTopics: 'No Topics',
|
noTopics: 'No Topics',
|
||||||
noConnected: 'No Connected Contacts',
|
noConnected: 'No Connected Contacts',
|
||||||
@ -272,11 +278,16 @@ export const fr = {
|
|||||||
encrypted: 'Crypté',
|
encrypted: 'Crypté',
|
||||||
unknown: 'Inconnu',
|
unknown: 'Inconnu',
|
||||||
sealed: 'Scellé',
|
sealed: 'Scellé',
|
||||||
|
notSealed: 'Non Scellé',
|
||||||
notes: 'Notes',
|
notes: 'Notes',
|
||||||
server: 'Serveur',
|
server: 'Serveur',
|
||||||
token: 'Code',
|
token: 'Code',
|
||||||
delayMessage: 'La génération de clé peut prendre plusieurs minutes.',
|
delayMessage: 'La génération de clé peut prendre plusieurs minutes.',
|
||||||
|
|
||||||
|
membership: 'Adhésion',
|
||||||
|
channelHost: 'Hôte du Sujet',
|
||||||
|
channelGuest: 'Invité du Sujet',
|
||||||
|
created: 'Créé',
|
||||||
flagMessage: 'Signaler le message',
|
flagMessage: 'Signaler le message',
|
||||||
flagMessagePrompt: 'Êtes-vous sûr de vouloir signaler le message à l\'administrateur?',
|
flagMessagePrompt: 'Êtes-vous sûr de vouloir signaler le message à l\'administrateur?',
|
||||||
flag: 'Signaler',
|
flag: 'Signaler',
|
||||||
@ -340,6 +351,7 @@ export const fr = {
|
|||||||
unsetSealing: 'Clé de sécurité non définie',
|
unsetSealing: 'Clé de sécurité non définie',
|
||||||
newTopic: 'Nouveau Sujet',
|
newTopic: 'Nouveau Sujet',
|
||||||
|
|
||||||
|
subject: 'Sujet',
|
||||||
noContacts: 'Pas de Contacts',
|
noContacts: 'Pas de Contacts',
|
||||||
noTopics: 'Pas de Sujets',
|
noTopics: 'Pas de Sujets',
|
||||||
noConnected: 'Pas de Contacts Connecter',
|
noConnected: 'Pas de Contacts Connecter',
|
||||||
@ -538,11 +550,16 @@ export const sp = {
|
|||||||
encrypted: 'Cifrado',
|
encrypted: 'Cifrado',
|
||||||
unknown: 'Desconocido',
|
unknown: 'Desconocido',
|
||||||
sealed: 'Sellado',
|
sealed: 'Sellado',
|
||||||
|
notSealed: 'No Sellado',
|
||||||
notes: 'Notas',
|
notes: 'Notas',
|
||||||
server: 'Server',
|
server: 'Server',
|
||||||
token: 'Código',
|
token: 'Código',
|
||||||
delayMessage: 'La generación de claves puede tardar varios minutos.',
|
delayMessage: 'La generación de claves puede tardar varios minutos.',
|
||||||
|
|
||||||
|
membership: 'Afiliación',
|
||||||
|
channelHost: 'Anfitrión del Tema',
|
||||||
|
channelGuest: 'Invitado de Tema',
|
||||||
|
created: 'Creado',
|
||||||
flagMessage: 'Marcar mensaje',
|
flagMessage: 'Marcar mensaje',
|
||||||
flagMessagePrompt: '¿Está seguro de que desea marcar el mensaje para el administrador?',
|
flagMessagePrompt: '¿Está seguro de que desea marcar el mensaje para el administrador?',
|
||||||
flag: 'Marcar',
|
flag: 'Marcar',
|
||||||
@ -606,6 +623,7 @@ export const sp = {
|
|||||||
unsetSealing: 'Clave de seguridad no definida',
|
unsetSealing: 'Clave de seguridad no definida',
|
||||||
newTopic: 'Nuevo tema',
|
newTopic: 'Nuevo tema',
|
||||||
|
|
||||||
|
subject: 'Tema',
|
||||||
noContacts: 'Sin contactos',
|
noContacts: 'Sin contactos',
|
||||||
noTopics: 'Sin temas',
|
noTopics: 'Sin temas',
|
||||||
noConnected: 'Ningún contacto conectado',
|
noConnected: 'Ningún contacto conectado',
|
||||||
@ -803,11 +821,16 @@ export const pt = {
|
|||||||
encrypted: 'Criptografado',
|
encrypted: 'Criptografado',
|
||||||
unknown: 'Desconhecido',
|
unknown: 'Desconhecido',
|
||||||
sealed: 'Selado',
|
sealed: 'Selado',
|
||||||
|
notSealed: 'Não Selado',
|
||||||
notes: 'Notas',
|
notes: 'Notas',
|
||||||
server: 'Servidor',
|
server: 'Servidor',
|
||||||
token: 'Code',
|
token: 'Code',
|
||||||
delayMessage: 'A geração da chave pode levar vários minutos.',
|
delayMessage: 'A geração da chave pode levar vários minutos.',
|
||||||
|
|
||||||
|
membership: 'Associação',
|
||||||
|
channelHost: 'Anfitrião do Tópico',
|
||||||
|
channelGuest: 'Convidado do Tópico',
|
||||||
|
created: 'Criado',
|
||||||
flagMessage: 'Sinalizar mensagem',
|
flagMessage: 'Sinalizar mensagem',
|
||||||
flagMessagePrompt: 'Tem certeza de que deseja sinalizar a mensagem para o administrador?',
|
flagMessagePrompt: 'Tem certeza de que deseja sinalizar a mensagem para o administrador?',
|
||||||
flag: 'Sinalizar',
|
flag: 'Sinalizar',
|
||||||
@ -871,6 +894,7 @@ export const pt = {
|
|||||||
unsetSealing: 'Chave de segurança não definida',
|
unsetSealing: 'Chave de segurança não definida',
|
||||||
newTopic: 'Novo tópico',
|
newTopic: 'Novo tópico',
|
||||||
|
|
||||||
|
subject: 'Assunto',
|
||||||
noContacts: 'Sem contatos',
|
noContacts: 'Sem contatos',
|
||||||
noTopics: 'Sem tópicos',
|
noTopics: 'Sem tópicos',
|
||||||
noConnected: 'Nenhum contato conectado',
|
noConnected: 'Nenhum contato conectado',
|
||||||
@ -1068,11 +1092,16 @@ export const de = {
|
|||||||
encrypted: 'Verschlüsselt',
|
encrypted: 'Verschlüsselt',
|
||||||
unknown: 'Unbekannt',
|
unknown: 'Unbekannt',
|
||||||
sealed: 'Versiegelt',
|
sealed: 'Versiegelt',
|
||||||
|
notSealed: 'Nicht Versiegelt',
|
||||||
notes: 'Notizen',
|
notes: 'Notizen',
|
||||||
server: 'Servierer',
|
server: 'Servierer',
|
||||||
token: 'Token',
|
token: 'Token',
|
||||||
delayMessage: 'Die Schlüsselgenerierung kann mehrere Minuten dauern.',
|
delayMessage: 'Die Schlüsselgenerierung kann mehrere Minuten dauern.',
|
||||||
|
membership: 'Mitgliedschaft',
|
||||||
|
|
||||||
|
channelHost: 'Themenhost',
|
||||||
|
channelGuest: 'Thema Gast',
|
||||||
|
created: 'Erstellt',
|
||||||
flagMessage: 'Nachricht melden',
|
flagMessage: 'Nachricht melden',
|
||||||
flagMessagePrompt: 'Sind Sie sicher, dass Sie die Nachricht an den Administrator melden möchten?',
|
flagMessagePrompt: 'Sind Sie sicher, dass Sie die Nachricht an den Administrator melden möchten?',
|
||||||
flag: 'Melden',
|
flag: 'Melden',
|
||||||
@ -1136,6 +1165,7 @@ export const de = {
|
|||||||
unsetSealing: 'Sicherheitsschlüssel nicht festgelegt',
|
unsetSealing: 'Sicherheitsschlüssel nicht festgelegt',
|
||||||
newTopic: 'Neues Thema',
|
newTopic: 'Neues Thema',
|
||||||
|
|
||||||
|
subject: 'Betreff',
|
||||||
noContacts: 'Keine Kontakte',
|
noContacts: 'Keine Kontakte',
|
||||||
noTopics: 'Keine Themen',
|
noTopics: 'Keine Themen',
|
||||||
noConnected: 'Keine verbundenen Kontakte',
|
noConnected: 'Keine verbundenen Kontakte',
|
||||||
@ -1333,11 +1363,16 @@ export const ru = {
|
|||||||
encrypted: 'Зашифрованный',
|
encrypted: 'Зашифрованный',
|
||||||
unknown: 'Неизвестно',
|
unknown: 'Неизвестно',
|
||||||
sealed: 'Запечатано',
|
sealed: 'Запечатано',
|
||||||
|
notSealed: 'Не Запечатано',
|
||||||
notes: 'Заметки',
|
notes: 'Заметки',
|
||||||
server: 'Сервер',
|
server: 'Сервер',
|
||||||
token: 'Токен',
|
token: 'Токен',
|
||||||
delayMessage: 'Генерация ключа может занять несколько минут.',
|
delayMessage: 'Генерация ключа может занять несколько минут.',
|
||||||
|
created: 'Созданный',
|
||||||
|
|
||||||
|
membership: 'Членство',
|
||||||
|
channelHost: 'Ведущий темы',
|
||||||
|
channelGuest: 'Тема Гость',
|
||||||
flagMessage: 'Пожаловаться на сообщение',
|
flagMessage: 'Пожаловаться на сообщение',
|
||||||
flagMessagePrompt: 'Вы уверены, что хотите пожаловаться на сообщение администратору?',
|
flagMessagePrompt: 'Вы уверены, что хотите пожаловаться на сообщение администратору?',
|
||||||
flag: 'Пожаловаться',
|
flag: 'Пожаловаться',
|
||||||
@ -1401,6 +1436,7 @@ export const ru = {
|
|||||||
unsetSealing: 'Ключ безопасности не установлен',
|
unsetSealing: 'Ключ безопасности не установлен',
|
||||||
newTopic: 'Новая тема',
|
newTopic: 'Новая тема',
|
||||||
|
|
||||||
|
subject: 'Тема',
|
||||||
noContacts: 'Нет контактов',
|
noContacts: 'Нет контактов',
|
||||||
noTopics: 'Нет тем',
|
noTopics: 'Нет тем',
|
||||||
noConnected: 'Нет подключенных контактов',
|
noConnected: 'Нет подключенных контактов',
|
||||||
|
@ -5,4 +5,166 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
min-width: 0;
|
||||||
|
|
||||||
|
.membership {
|
||||||
|
padding-top: 32px;
|
||||||
|
font-size: 12px;
|
||||||
|
|
||||||
|
.members {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.body {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
min-width: 0;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.disconnected {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 16px;
|
||||||
|
padding-top: 32px;
|
||||||
|
color: var(--mantine-color-red-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
gap: 12px;
|
||||||
|
padding-top: 16px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
padding-left: 16px;
|
||||||
|
padding-right: 16px;
|
||||||
|
padding-top: 32px;
|
||||||
|
padding-bottom: 16px;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
.action {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
cursor: pointer;
|
||||||
|
height: fit-content;
|
||||||
|
|
||||||
|
.actionLabel {
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--mantine-color-dbgreen-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.attributes {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
padding-left: 16px;
|
||||||
|
padding-right: 16px;
|
||||||
|
gap: 6px;
|
||||||
|
padding-top: 16px;
|
||||||
|
padding-bottom: 24px;
|
||||||
|
|
||||||
|
.attribute {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
align-items: center;
|
||||||
|
padding-left: 4px;
|
||||||
|
|
||||||
|
.subjectLabel {
|
||||||
|
}
|
||||||
|
|
||||||
|
.subjectValue {
|
||||||
|
font-size: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subjectPlaceholder {
|
||||||
|
font-size: 28px;
|
||||||
|
color: var(--mantine-color-text-7);
|
||||||
|
}
|
||||||
|
|
||||||
|
.attributeLabel {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.attributeValue {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.label {
|
||||||
|
font-size: 24px;
|
||||||
|
padding: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.divider {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
width: 100%;
|
||||||
|
border-bottom: 1px solid var(--mantine-color-text-7);
|
||||||
|
padding-left: 16px;
|
||||||
|
padding-right: 16px;
|
||||||
|
height: 48px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subject {
|
||||||
|
padding-bottom: 8px;
|
||||||
|
|
||||||
|
.subjectControls {
|
||||||
|
display: flex;
|
||||||
|
gap: 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subjectLabel {
|
||||||
|
display: flex;
|
||||||
|
gap: 16px;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.guestSubject {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.guestPlaceholder {
|
||||||
|
display: flex;
|
||||||
|
font-style: italic;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subjectValue {
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subjectPlaceholder {
|
||||||
|
font-size: 20px;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
width: 100%;
|
||||||
|
height: 48px;
|
||||||
|
padding-top: 8px;
|
||||||
|
padding-bottom: 8px;
|
||||||
|
padding-right: 16px;
|
||||||
|
padding-left: 16px;
|
||||||
|
border-bottom: 1px solid var(--mantine-color-text-8);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cards {
|
||||||
|
min-width: 0;
|
||||||
|
width: 100%;
|
||||||
|
flex-shink: 1;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,159 @@
|
|||||||
import React, { useState } from 'react'
|
import React, { useState } from 'react'
|
||||||
import { useDetails } from './useDetails.hook'
|
import { useDetails } from './useDetails.hook'
|
||||||
import classes from './Details.module.css'
|
import classes from './Details.module.css'
|
||||||
import { IconX } from '@tabler/icons-react'
|
import { IconUserCog, IconEyeOff, IconAlertHexagon, IconMessageX, IconLogout2, IconHome, IconServer, IconShield, IconShieldOff, IconCalendarClock, IconExclamationCircle, IconX, IconEdit, IconDeviceFloppy, IconArrowBack, IconLabel } from '@tabler/icons-react'
|
||||||
|
import { Divider, Text, Textarea, Image, TextInput, ActionIcon } from '@mantine/core'
|
||||||
|
import { Card } from '../card/Card';
|
||||||
|
|
||||||
export function Details({ close }: { close?: () => void }) {
|
export function Details({ close }: { close?: () => void }) {
|
||||||
const { state, actions } = useDetails()
|
const { state, actions } = useDetails()
|
||||||
|
|
||||||
|
const undo = () => {
|
||||||
|
actions.undoSubject();
|
||||||
|
}
|
||||||
|
|
||||||
|
const save = () => {
|
||||||
|
console.log('save subject');
|
||||||
|
}
|
||||||
|
|
||||||
|
const cards = state.channelCards.map((card, index) => (
|
||||||
|
<Card className={classes.card} key={index} imageUrl={card.imageUrl} name={card.name} placeHolder={state.strings.name}
|
||||||
|
handle={card.handle} node={card.node}/>
|
||||||
|
))
|
||||||
|
|
||||||
|
|
||||||
|
console.log(state.hostCard, state.channelCards, state.unknownContacts);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classes.details}>
|
<div className={classes.details}>
|
||||||
{close && <IconX size={30} className={classes.close} onClick={close} />}
|
<div className={classes.header}>
|
||||||
|
{close && <IconX size={30} className={classes.match} />}
|
||||||
|
<Text className={classes.label}>{ state.strings.details }</Text>
|
||||||
|
{close && <IconX size={30} className={classes.close} onClick={close} />}
|
||||||
|
</div>
|
||||||
|
{ state.access && (
|
||||||
|
<div className={classes.body}>
|
||||||
|
<div className={classes.attributes}>
|
||||||
|
{ state.host && (
|
||||||
|
<div className={classes.subject}>
|
||||||
|
<div className={classes.subjectLabel}>
|
||||||
|
<TextInput size="lg" placeholder={state.strings.subject} value={state.editSubject} onChange={(event) => actions.setEditSubject(event.currentTarget.value)}
|
||||||
|
leftSectionPointerEvents="none" leftSection={<IconLabel />}
|
||||||
|
rightSectionPointerEvents="all" rightSectionWidth={64} rightSection={
|
||||||
|
<div className={classes.subjectControls}>
|
||||||
|
{ state.editSubject != state.subject && (
|
||||||
|
<ActionIcon key="undo" variant="subtle" onClick={undo}><IconArrowBack /></ActionIcon>
|
||||||
|
)}
|
||||||
|
{ state.editSubject != state.subject && (
|
||||||
|
<ActionIcon key="save" variant="subtle" onClick={save}><IconDeviceFloppy /></ActionIcon>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{ !state.host && state.subject && (
|
||||||
|
<div className={classes.attribute}>
|
||||||
|
<IconLabel size={28} className={classes.subjectValue} />
|
||||||
|
<Text className={classes.subjectValue}>{ state.subject }</Text>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{ !state.host && !state.subject && (
|
||||||
|
<div className={classes.attribute}>
|
||||||
|
<IconLabel size={28} className={classes.subjectPlaceholder} />
|
||||||
|
<Text className={classes.subjectPlaceholder}>{ state.strings.subject }</Text>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<div className={classes.attribute}>
|
||||||
|
<IconCalendarClock size={20}/>
|
||||||
|
<Text className={classes.attributeValue}>{ state.created }</Text>
|
||||||
|
</div>
|
||||||
|
{ state.sealed && (
|
||||||
|
<div className={classes.attribute}>
|
||||||
|
<IconShield size={20} />
|
||||||
|
<Text className={classes.attributeValue}>{ state.strings.sealed }</Text>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{ !state.sealed && (
|
||||||
|
<div className={classes.attribute}>
|
||||||
|
<IconShieldOff size={20} />
|
||||||
|
<Text className={classes.attributeValue}>{ state.strings.notSealed }</Text>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{ state.host && (
|
||||||
|
<div className={classes.attribute}>
|
||||||
|
<IconHome size={20} />
|
||||||
|
<Text className={classes.attributeValue}>{ state.strings.channelHost }</Text>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{ !state.host && (
|
||||||
|
<div className={classes.attribute}>
|
||||||
|
<IconServer size={20} />
|
||||||
|
<Text className={classes.attributeValue}>{ state.strings.channelGuest }</Text>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<Divider className={classes.divider} />
|
||||||
|
{ !state.host && (
|
||||||
|
<div className={classes.actions}>
|
||||||
|
<div className={classes.action}>
|
||||||
|
<ActionIcon variant="subtle" size="lg">
|
||||||
|
<IconLogout2 size="lg" />
|
||||||
|
</ActionIcon>
|
||||||
|
<Text className={classes.actionLabel}>{state.strings.leave}</Text>
|
||||||
|
</div>
|
||||||
|
<div className={classes.action}>
|
||||||
|
<ActionIcon variant="subtle" size="lg">
|
||||||
|
<IconEyeOff size="lg" />
|
||||||
|
</ActionIcon>
|
||||||
|
<Text className={classes.actionLabel}>{state.strings.block}</Text>
|
||||||
|
</div>
|
||||||
|
<div className={classes.action}>
|
||||||
|
<ActionIcon variant="subtle" size="lg">
|
||||||
|
<IconAlertHexagon size="lg" />
|
||||||
|
</ActionIcon>
|
||||||
|
<Text className={classes.actionLabel}>{state.strings.report}</Text>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{ state.host && (
|
||||||
|
<div className={classes.actions}>
|
||||||
|
<div className={classes.action}>
|
||||||
|
<ActionIcon variant="subtle" size="lg" >
|
||||||
|
<IconMessageX size="lg" />
|
||||||
|
</ActionIcon>
|
||||||
|
<Text className={classes.actionLabel}>{state.strings.remove}</Text>
|
||||||
|
</div>
|
||||||
|
<div className={classes.action}>
|
||||||
|
<ActionIcon variant="subtle" size="lg" >
|
||||||
|
<IconUserCog size="lg" />
|
||||||
|
</ActionIcon>
|
||||||
|
<Text className={classes.actionLabel}>{state.strings.members}</Text>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<div className={classes.membership}>
|
||||||
|
<Text className={classes.members}>{ state.strings.membership }</Text>
|
||||||
|
</div>
|
||||||
|
<Divider className={classes.divider} size="md" />
|
||||||
|
<div className={classes.cards}>
|
||||||
|
{ state.hostCard && (
|
||||||
|
<Card className={classes.card} imageUrl={state.hostCard.imageUrl} name={state.hostCard.name} placeHolder={state.strings.name}
|
||||||
|
handle={state.hostCard.handle} node={state.hostCard.node} actions={[<IconHome key="host" size={20} />]} />
|
||||||
|
)}
|
||||||
|
{ cards }
|
||||||
|
{ state.unknownContacts > 0 && (
|
||||||
|
<Text className={classes.unknown}>{ state.strings.unknown }: {state.unknownContacts}</Text>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{ !state.access && (
|
||||||
|
<div className={classes.disconnected}>
|
||||||
|
<IconExclamationCircle />
|
||||||
|
<Text>{ state.strings.syncError }</Text>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,27 @@
|
|||||||
import { useState, useContext, useEffect } from 'react'
|
import { useState, useContext, useEffect } from 'react'
|
||||||
|
import { AppContext } from '../context/AppContext'
|
||||||
|
import { DisplayContext } from '../context/DisplayContext'
|
||||||
|
import { ContextType } from '../context/ContextType'
|
||||||
|
import { FocusDetail, Card, Profile } from 'databag-client-sdk';
|
||||||
|
|
||||||
export function useDetails() {
|
export function useDetails() {
|
||||||
|
const display = useContext(DisplayContext) as ContextType
|
||||||
|
const app = useContext(AppContext) as ContextType
|
||||||
const [state, setState] = useState({
|
const [state, setState] = useState({
|
||||||
|
access: false,
|
||||||
|
host: false,
|
||||||
|
sealed: false,
|
||||||
|
locked: false,
|
||||||
|
strings: display.state.strings,
|
||||||
|
timeFormat: display.state.timeFormat,
|
||||||
|
dateFormat: display.state.dateFormat,
|
||||||
|
subject: '',
|
||||||
|
editSubject: '',
|
||||||
|
created: '',
|
||||||
|
profile: null as null | Porfile,
|
||||||
|
cards: [] as Card[],
|
||||||
|
hostCard: null as null | Card,
|
||||||
|
channelCards: [] as Card[],
|
||||||
})
|
})
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
@ -9,7 +29,98 @@ export function useDetails() {
|
|||||||
setState((s) => ({ ...s, ...value }))
|
setState((s) => ({ ...s, ...value }))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getTimestamp = (created: number) => {
|
||||||
|
const now = Math.floor((new Date()).getTime() / 1000)
|
||||||
|
const date = new Date(created * 1000);
|
||||||
|
const offset = now - created;
|
||||||
|
if(offset < 43200) {
|
||||||
|
if (state.timeFormat === '12h') {
|
||||||
|
return date.toLocaleTimeString("en-US", {hour: 'numeric', minute:'2-digit'});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return date.toLocaleTimeString("en-GB", {hour: 'numeric', minute:'2-digit'});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (offset < 31449600) {
|
||||||
|
if (state.dateFormat === 'mm/dd') {
|
||||||
|
return date.toLocaleDateString("en-US", {day: 'numeric', month:'numeric'});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return date.toLocaleDateString("en-GB", {day: 'numeric', month:'numeric'});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (state.dateFormat === 'mm/dd') {
|
||||||
|
return date.toLocaleDateString("en-US");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return date.toLocaleDateString("en-GB");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const { strings, timeFormat, dateFormat } = display.state;
|
||||||
|
updateState({ strings, timeFormat, dateFormat });
|
||||||
|
}, [display.state]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const cards = Array.from(state.cards.values());
|
||||||
|
const hostCard = cards.find(entry => entry.cardId == state.cardId);
|
||||||
|
const profileRemoved = state.detail?.members ? state.detail.members.filter(member => state.profile?.guid != member.guid) : [];
|
||||||
|
const contactCards = profileRemoved.map(member => state.cards.get(member.guid));
|
||||||
|
const channelCards = contactCards.filter(member => Boolean(member));
|
||||||
|
const unknownContacts = contactCards.length - channelCards.length;
|
||||||
|
updateState({ hostCard, channelCards, unknownContacts });
|
||||||
|
}, [state.detail, state.cards, state.profile, state.cardId]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const focus = app.state.focus;
|
||||||
|
const { contact, identity } = app.state.session || { };
|
||||||
|
if (focus && contact && identity) {
|
||||||
|
const setCards = (cards: Card[]) => {
|
||||||
|
const contacts = new Map<string, Card>();
|
||||||
|
cards.forEach(card => {
|
||||||
|
contacts.set(card.guid, card);
|
||||||
|
});
|
||||||
|
updateState({ cards: contacts });
|
||||||
|
}
|
||||||
|
const setProfile = (profile: Profile) => {
|
||||||
|
updateState({ profile });
|
||||||
|
}
|
||||||
|
const setDetail = (focused: { cardId: string | null, channelId: string, detail: FocusDetail | null }) => {
|
||||||
|
|
||||||
|
const detail = focused ? focused.detail : null;
|
||||||
|
const cardId = focused.cardId;
|
||||||
|
const access = Boolean(detail);
|
||||||
|
const sealed = detail?.sealed;
|
||||||
|
const locked = detail?.locked;
|
||||||
|
const host = cardId == null;
|
||||||
|
const subject = detail?.data?.subject ? detail.data.subject : '';
|
||||||
|
const created = detail?.created ? getTimestamp(detail.created) : '';
|
||||||
|
updateState({ detail, editSubject: subject, subject, cardId, access, sealed, locked, host, created });
|
||||||
|
}
|
||||||
|
focus.addDetailListener(setDetail);
|
||||||
|
contact.addCardListener(setCards);
|
||||||
|
identity.addProfileListener(setProfile);
|
||||||
|
return () => {
|
||||||
|
focus.removeDetailListener(setDetail);
|
||||||
|
contact.removeCardListener(setCards);
|
||||||
|
identity.removeProfileListener(setProfile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [app.state.focus, state.timeFormat, state.dateFormat]);
|
||||||
|
|
||||||
const actions = {
|
const actions = {
|
||||||
|
setEditSubject: (editSubject: string) => {
|
||||||
|
updateState({ editSubject });
|
||||||
|
},
|
||||||
|
undoSubject: () => {
|
||||||
|
updateState({ editSubject: state.subject });
|
||||||
|
},
|
||||||
|
saveSubject: () => {
|
||||||
|
console.log('saving subject');
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
return { state, actions }
|
return { state, actions }
|
||||||
|
@ -270,14 +270,14 @@ export function Profile({ params, close }: { params: ProfileParams; close?: () =
|
|||||||
{state.statusLabel === 'unknownStatus' && (
|
{state.statusLabel === 'unknownStatus' && (
|
||||||
<div className={classes.actions}>
|
<div className={classes.actions}>
|
||||||
<div className={classes.action} onClick={applySave}>
|
<div className={classes.action} onClick={applySave}>
|
||||||
<ActionIcon variant="subtle" loading={saving}>
|
<ActionIcon variant="subtle" loading={saving} size="lg">
|
||||||
<IconDeviceFloppy />
|
<IconDeviceFloppy size="lg" />
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
<Text className={classes.actionLabel}>{state.strings.save}</Text>
|
<Text className={classes.actionLabel}>{state.strings.save}</Text>
|
||||||
</div>
|
</div>
|
||||||
<div className={classes.action} onClick={confirmReport}>
|
<div className={classes.action} onClick={confirmReport}>
|
||||||
<ActionIcon variant="subtle" loading={reporting}>
|
<ActionIcon variant="subtle" loading={reporting} size="lg">
|
||||||
<IconAlertHexagon />
|
<IconAlertHexagon size="lg" />
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
<Text className={classes.actionLabel}>{state.strings.report}</Text>
|
<Text className={classes.actionLabel}>{state.strings.report}</Text>
|
||||||
</div>
|
</div>
|
||||||
@ -286,26 +286,26 @@ export function Profile({ params, close }: { params: ProfileParams; close?: () =
|
|||||||
{state.statusLabel === 'savedStatus' && (
|
{state.statusLabel === 'savedStatus' && (
|
||||||
<div className={classes.actions}>
|
<div className={classes.actions}>
|
||||||
<div className={classes.action} onClick={applyConnect}>
|
<div className={classes.action} onClick={applyConnect}>
|
||||||
<ActionIcon variant="subtle" loading={connecting}>
|
<ActionIcon variant="subtle" loading={connecting} size="lg">
|
||||||
<IconRoute2 />
|
<IconRoute2 size="lg" />
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
<Text className={classes.actionLabel}>{state.strings.connect}</Text>
|
<Text className={classes.actionLabel}>{state.strings.connect}</Text>
|
||||||
</div>
|
</div>
|
||||||
<div className={classes.action} onClick={confirmRemove}>
|
<div className={classes.action} onClick={confirmRemove}>
|
||||||
<ActionIcon variant="subtle" loading={removing}>
|
<ActionIcon variant="subtle" loading={removing} size="lg">
|
||||||
<IconUserX />
|
<IconUserX size="lg" />
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
<Text className={classes.actionLabel}>{state.strings.remove}</Text>
|
<Text className={classes.actionLabel}>{state.strings.remove}</Text>
|
||||||
</div>
|
</div>
|
||||||
<div className={classes.action} onClick={confirmBlock}>
|
<div className={classes.action} onClick={confirmBlock}>
|
||||||
<ActionIcon variant="subtle" loading={blocking}>
|
<ActionIcon variant="subtle" loading={blocking} size="lg">
|
||||||
<IconEyeOff />
|
<IconEyeOff size="lg" />
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
<Text className={classes.actionLabel}>{state.strings.block}</Text>
|
<Text className={classes.actionLabel}>{state.strings.block}</Text>
|
||||||
</div>
|
</div>
|
||||||
<div className={classes.action} onClick={confirmReport}>
|
<div className={classes.action} onClick={confirmReport}>
|
||||||
<ActionIcon variant="subtle" loading={reporting}>
|
<ActionIcon variant="subtle" loading={reporting} size="lg">
|
||||||
<IconAlertHexagon />
|
<IconAlertHexagon size="lg" />
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
<Text className={classes.actionLabel}>{state.strings.report}</Text>
|
<Text className={classes.actionLabel}>{state.strings.report}</Text>
|
||||||
</div>
|
</div>
|
||||||
@ -314,44 +314,44 @@ export function Profile({ params, close }: { params: ProfileParams; close?: () =
|
|||||||
{state.statusLabel === 'pendingStatus' && (
|
{state.statusLabel === 'pendingStatus' && (
|
||||||
<div className={classes.actions}>
|
<div className={classes.actions}>
|
||||||
<div className={classes.action} onClick={applyConfirm}>
|
<div className={classes.action} onClick={applyConfirm}>
|
||||||
<ActionIcon variant="subtle" loading={confirming}>
|
<ActionIcon variant="subtle" loading={confirming} size="lg">
|
||||||
<IconDeviceFloppy />
|
<IconDeviceFloppy size="lg" />
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
<Text className={classes.actionLabel}>{state.strings.save}</Text>
|
<Text className={classes.actionLabel}>{state.strings.save}</Text>
|
||||||
</div>
|
</div>
|
||||||
<div className={classes.action} onClick={applyAccept}>
|
<div className={classes.action} onClick={applyAccept}>
|
||||||
<ActionIcon variant="subtle" loading={accepting}>
|
<ActionIcon variant="subtle" loading={accepting} size="lg">
|
||||||
<IconUserCheck />
|
<IconUserCheck size="lg" />
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
<Text className={classes.actionLabel}>{state.strings.accept}</Text>
|
<Text className={classes.actionLabel}>{state.strings.accept}</Text>
|
||||||
</div>
|
</div>
|
||||||
<div className={classes.action} onClick={confirmIgnore}>
|
<div className={classes.action} onClick={confirmIgnore}>
|
||||||
<ActionIcon variant="subtle" loading={ignoring}>
|
<ActionIcon variant="subtle" loading={ignoring} size="lg">
|
||||||
<IconVolumeOff />
|
<IconVolumeOff size="lg" />
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
<Text className={classes.actionLabel}>{state.strings.ignore}</Text>
|
<Text className={classes.actionLabel}>{state.strings.ignore}</Text>
|
||||||
</div>
|
</div>
|
||||||
<div className={classes.action} onClick={confirmDeny}>
|
<div className={classes.action} onClick={confirmDeny}>
|
||||||
<ActionIcon variant="subtle" loading={denying}>
|
<ActionIcon variant="subtle" loading={denying} size="lg">
|
||||||
<IconArrowsCross />
|
<IconArrowsCross size="lg" />
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
<Text className={classes.actionLabel}>{state.strings.deny}</Text>
|
<Text className={classes.actionLabel}>{state.strings.deny}</Text>
|
||||||
</div>
|
</div>
|
||||||
<div className={classes.action} onClick={confirmRemove}>
|
<div className={classes.action} onClick={confirmRemove}>
|
||||||
<ActionIcon variant="subtle" loading={removing}>
|
<ActionIcon variant="subtle" loading={removing} size="lg">
|
||||||
<IconUserX />
|
<IconUserX size="lg" />
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
<Text className={classes.actionLabel}>{state.strings.remove}</Text>
|
<Text className={classes.actionLabel}>{state.strings.remove}</Text>
|
||||||
</div>
|
</div>
|
||||||
<div className={classes.action} onClick={confirmBlock}>
|
<div className={classes.action} onClick={confirmBlock}>
|
||||||
<ActionIcon variant="subtle" loading={blocking}>
|
<ActionIcon variant="subtle" loading={blocking} size="lg">
|
||||||
<IconEyeOff />
|
<IconEyeOff size="lg" />
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
<Text className={classes.actionLabel}>{state.strings.block}</Text>
|
<Text className={classes.actionLabel}>{state.strings.block}</Text>
|
||||||
</div>
|
</div>
|
||||||
<div className={classes.action} onClick={confirmReport}>
|
<div className={classes.action} onClick={confirmReport}>
|
||||||
<ActionIcon variant="subtle" loading={reporting}>
|
<ActionIcon variant="subtle" loading={reporting} size="lg">
|
||||||
<IconAlertHexagon />
|
<IconAlertHexagon size="lg" />
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
<Text className={classes.actionLabel}>{state.strings.report}</Text>
|
<Text className={classes.actionLabel}>{state.strings.report}</Text>
|
||||||
</div>
|
</div>
|
||||||
@ -360,38 +360,38 @@ export function Profile({ params, close }: { params: ProfileParams; close?: () =
|
|||||||
{state.statusLabel === 'requestedStatus' && (
|
{state.statusLabel === 'requestedStatus' && (
|
||||||
<div className={classes.actions} onClick={applyAccept}>
|
<div className={classes.actions} onClick={applyAccept}>
|
||||||
<div className={classes.action}>
|
<div className={classes.action}>
|
||||||
<ActionIcon variant="subtle" loading={accepting}>
|
<ActionIcon variant="subtle" loading={accepting} size="lg">
|
||||||
<IconUserCheck />
|
<IconUserCheck size="lg" />
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
<Text className={classes.actionLabel}>{state.strings.accept}</Text>
|
<Text className={classes.actionLabel}>{state.strings.accept}</Text>
|
||||||
</div>
|
</div>
|
||||||
<div className={classes.action} onClick={confirmIgnore}>
|
<div className={classes.action} onClick={confirmIgnore}>
|
||||||
<ActionIcon variant="subtle" loading={ignoring}>
|
<ActionIcon variant="subtle" loading={ignoring} size="lg">
|
||||||
<IconVolumeOff />
|
<IconVolumeOff size="lg" />
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
<Text className={classes.actionLabel}>{state.strings.ignore}</Text>
|
<Text className={classes.actionLabel}>{state.strings.ignore}</Text>
|
||||||
</div>
|
</div>
|
||||||
<div className={classes.action} onClick={confirmDeny}>
|
<div className={classes.action} onClick={confirmDeny}>
|
||||||
<ActionIcon variant="subtle" loading={denying}>
|
<ActionIcon variant="subtle" loading={denying} size="lg">
|
||||||
<IconArrowsCross />
|
<IconArrowsCross size="lg" />
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
<Text className={classes.actionLabel}>{state.strings.deny}</Text>
|
<Text className={classes.actionLabel}>{state.strings.deny}</Text>
|
||||||
</div>
|
</div>
|
||||||
<div className={classes.action} onClick={confirmRemove}>
|
<div className={classes.action} onClick={confirmRemove}>
|
||||||
<ActionIcon variant="subtle" loading={removing}>
|
<ActionIcon variant="subtle" loading={removing} size="lg">
|
||||||
<IconUserX />
|
<IconUserX size="lg" />
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
<Text className={classes.actionLabel}>{state.strings.remove}</Text>
|
<Text className={classes.actionLabel}>{state.strings.remove}</Text>
|
||||||
</div>
|
</div>
|
||||||
<div className={classes.action} onClick={confirmBlock}>
|
<div className={classes.action} onClick={confirmBlock}>
|
||||||
<ActionIcon variant="subtle" loading={blocking}>
|
<ActionIcon variant="subtle" loading={blocking} size="lg">
|
||||||
<IconEyeOff />
|
<IconEyeOff size="lg" />
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
<Text className={classes.actionLabel}>{state.strings.block}</Text>
|
<Text className={classes.actionLabel}>{state.strings.block}</Text>
|
||||||
</div>
|
</div>
|
||||||
<div className={classes.action} onClick={confirmReport}>
|
<div className={classes.action} onClick={confirmReport}>
|
||||||
<ActionIcon variant="subtle" loading={reporting}>
|
<ActionIcon variant="subtle" loading={reporting} size="lg">
|
||||||
<IconAlertHexagon />
|
<IconAlertHexagon size="lg" />
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
<Text className={classes.actionLabel}>{state.strings.report}</Text>
|
<Text className={classes.actionLabel}>{state.strings.report}</Text>
|
||||||
</div>
|
</div>
|
||||||
@ -400,26 +400,26 @@ export function Profile({ params, close }: { params: ProfileParams; close?: () =
|
|||||||
{state.statusLabel === 'connectingStatus' && (
|
{state.statusLabel === 'connectingStatus' && (
|
||||||
<div className={classes.actions}>
|
<div className={classes.actions}>
|
||||||
<div className={classes.action} onClick={applyCancel}>
|
<div className={classes.action} onClick={applyCancel}>
|
||||||
<ActionIcon variant="subtle" loading={canceling}>
|
<ActionIcon variant="subtle" loading={canceling} size="lg">
|
||||||
<IconCancel />
|
<IconCancel size="lg" />
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
<Text className={classes.actionLabel}>{state.strings.cancel}</Text>
|
<Text className={classes.actionLabel}>{state.strings.cancel}</Text>
|
||||||
</div>
|
</div>
|
||||||
<div className={classes.action} onClick={confirmRemove}>
|
<div className={classes.action} onClick={confirmRemove}>
|
||||||
<ActionIcon variant="subtle" loading={removing}>
|
<ActionIcon variant="subtle" loading={removing} size="lg">
|
||||||
<IconUserX />
|
<IconUserX size="lg" />
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
<Text className={classes.actionLabel}>{state.strings.remove}</Text>
|
<Text className={classes.actionLabel}>{state.strings.remove}</Text>
|
||||||
</div>
|
</div>
|
||||||
<div className={classes.action} onClick={confirmBlock}>
|
<div className={classes.action} onClick={confirmBlock}>
|
||||||
<ActionIcon variant="subtle" loading={blocking}>
|
<ActionIcon variant="subtle" loading={blocking} size="lg">
|
||||||
<IconEyeOff />
|
<IconEyeOff size="lg" />
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
<Text className={classes.actionLabel}>{state.strings.block}</Text>
|
<Text className={classes.actionLabel}>{state.strings.block}</Text>
|
||||||
</div>
|
</div>
|
||||||
<div className={classes.action} onClick={confirmReport}>
|
<div className={classes.action} onClick={confirmReport}>
|
||||||
<ActionIcon variant="subtle" loading={reporting}>
|
<ActionIcon variant="subtle" loading={reporting} size="lg">
|
||||||
<IconAlertHexagon />
|
<IconAlertHexagon size="lg" />
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
<Text className={classes.actionLabel}>{state.strings.report}</Text>
|
<Text className={classes.actionLabel}>{state.strings.report}</Text>
|
||||||
</div>
|
</div>
|
||||||
@ -428,26 +428,26 @@ export function Profile({ params, close }: { params: ProfileParams; close?: () =
|
|||||||
{state.statusLabel === 'connectedStatus' && (
|
{state.statusLabel === 'connectedStatus' && (
|
||||||
<div className={classes.actions}>
|
<div className={classes.actions}>
|
||||||
<div className={classes.action} onClick={confirmDisconnect}>
|
<div className={classes.action} onClick={confirmDisconnect}>
|
||||||
<ActionIcon variant="subtle" loading={disconnecting}>
|
<ActionIcon variant="subtle" loading={disconnecting} size="lg">
|
||||||
<IconRouteX2 />
|
<IconRouteX2 size="lg" />
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
<Text className={classes.actionLabel}>{state.strings.disconnect}</Text>
|
<Text className={classes.actionLabel}>{state.strings.disconnect}</Text>
|
||||||
</div>
|
</div>
|
||||||
<div className={classes.action} onClick={confirmRemove}>
|
<div className={classes.action} onClick={confirmRemove}>
|
||||||
<ActionIcon variant="subtle" loading={removing}>
|
<ActionIcon variant="subtle" loading={removing} size="lg">
|
||||||
<IconUserX />
|
<IconUserX size="lg" />
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
<Text className={classes.actionLabel}>{state.strings.remove}</Text>
|
<Text className={classes.actionLabel}>{state.strings.remove}</Text>
|
||||||
</div>
|
</div>
|
||||||
<div className={classes.action} onClick={confirmBlock}>
|
<div className={classes.action} onClick={confirmBlock}>
|
||||||
<ActionIcon variant="subtle" loading={blocking}>
|
<ActionIcon variant="subtle" loading={blocking} size="lg">
|
||||||
<IconEyeOff />
|
<IconEyeOff size="lg" />
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
<Text className={classes.actionLabel}>{state.strings.block}</Text>
|
<Text className={classes.actionLabel}>{state.strings.block}</Text>
|
||||||
</div>
|
</div>
|
||||||
<div className={classes.action} onClick={confirmReport}>
|
<div className={classes.action} onClick={confirmReport}>
|
||||||
<ActionIcon variant="subtle" loading={reporting}>
|
<ActionIcon variant="subtle" loading={reporting} size="lg">
|
||||||
<IconAlertHexagon />
|
<IconAlertHexagon size="lg" />
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
<Text className={classes.actionLabel}>{state.strings.report}</Text>
|
<Text className={classes.actionLabel}>{state.strings.report}</Text>
|
||||||
</div>
|
</div>
|
||||||
@ -456,32 +456,32 @@ export function Profile({ params, close }: { params: ProfileParams; close?: () =
|
|||||||
{state.statusLabel === 'offsyncStatus' && (
|
{state.statusLabel === 'offsyncStatus' && (
|
||||||
<div className={classes.actions}>
|
<div className={classes.actions}>
|
||||||
<div className={classes.action} onClick={applyResync}>
|
<div className={classes.action} onClick={applyResync}>
|
||||||
<ActionIcon variant="subtle" loading={resyncing}>
|
<ActionIcon variant="subtle" loading={resyncing} size="lg">
|
||||||
<IconRefresh />
|
<IconRefresh size="lg" />
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
<Text className={classes.actionLabel}>{state.strings.resync}</Text>
|
<Text className={classes.actionLabel}>{state.strings.resync}</Text>
|
||||||
</div>
|
</div>
|
||||||
<div className={classes.action} onClick={confirmDisconnect}>
|
<div className={classes.action} onClick={confirmDisconnect}>
|
||||||
<ActionIcon variant="subtle" loading={disconnecting}>
|
<ActionIcon variant="subtle" loading={disconnecting} size="lg">
|
||||||
<IconRouteX2 />
|
<IconRouteX2 size="lg" />
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
<Text className={classes.actionLabel}>{state.strings.disconnect}</Text>
|
<Text className={classes.actionLabel}>{state.strings.disconnect}</Text>
|
||||||
</div>
|
</div>
|
||||||
<div className={classes.action} onClick={confirmRemove}>
|
<div className={classes.action} onClick={confirmRemove}>
|
||||||
<ActionIcon variant="subtle" loading={removing}>
|
<ActionIcon variant="subtle" loading={removing} size="lg">
|
||||||
<IconUserX />
|
<IconUserX size="lg" />
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
<Text className={classes.actionLabel}>{state.strings.remove}</Text>
|
<Text className={classes.actionLabel}>{state.strings.remove}</Text>
|
||||||
</div>
|
</div>
|
||||||
<div className={classes.action} onClick={confirmBlock}>
|
<div className={classes.action} onClick={confirmBlock}>
|
||||||
<ActionIcon variant="subtle" loading={blocking}>
|
<ActionIcon variant="subtle" loading={blocking} size="lg">
|
||||||
<IconEyeOff />
|
<IconEyeOff size="lg" />
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
<Text className={classes.actionLabel}>{state.strings.block}</Text>
|
<Text className={classes.actionLabel}>{state.strings.block}</Text>
|
||||||
</div>
|
</div>
|
||||||
<div className={classes.action} onClick={confirmReport}>
|
<div className={classes.action} onClick={confirmReport}>
|
||||||
<ActionIcon variant="subtle" loading={reporting}>
|
<ActionIcon variant="subtle" loading={reporting} size="lg">
|
||||||
<IconAlertHexagon />
|
<IconAlertHexagon size="lg" />
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
<Text className={classes.actionLabel}>{state.strings.report}</Text>
|
<Text className={classes.actionLabel}>{state.strings.report}</Text>
|
||||||
</div>
|
</div>
|
||||||
@ -492,14 +492,3 @@ export function Profile({ params, close }: { params: ProfileParams; close?: () =
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
//save - DeviceFloppy - save
|
|
||||||
//cancel - Cancel - cancel
|
|
||||||
//block - EyeOff - block
|
|
||||||
//report - AlertHexagon - report
|
|
||||||
//resync - Refresh - resync
|
|
||||||
//deny - ArrowsCross - deny
|
|
||||||
//ignore - VolumeOff - ignore
|
|
||||||
//accept - UserCheck - accept
|
|
||||||
//connect - Route2 - connect
|
|
||||||
//disconnect - RouteX2 - disconnect
|
|
||||||
//remove - UserX - remove
|
|
||||||
|
@ -164,7 +164,7 @@ export function Session() {
|
|||||||
<Profile params={profileParams} />
|
<Profile params={profileParams} />
|
||||||
</div>
|
</div>
|
||||||
</Drawer>
|
</Drawer>
|
||||||
<Drawer opened={details} onClose={closeDetails} withCloseButton={false} size="xs" padding="0" position="right">
|
<Drawer opened={details} onClose={closeDetails} withCloseButton={false} size="xs" padding="0" position="right" trapFocus={false}>
|
||||||
<div style={{ height: '100vh' }}>
|
<div style={{ height: '100vh' }}>
|
||||||
<Details />
|
<Details />
|
||||||
</div>
|
</div>
|
||||||
|
13424
app/client/web/yarn.lock
13424
app/client/web/yarn.lock
File diff suppressed because it is too large
Load Diff
@ -556,7 +556,7 @@ export class ContactModule implements Contact {
|
|||||||
entry.item.unsealedDetail = null;
|
entry.item.unsealedDetail = null;
|
||||||
await this.unsealChannelDetail(cardId, id, entry.item);
|
await this.unsealChannelDetail(cardId, id, entry.item);
|
||||||
if (this.focus) {
|
if (this.focus) {
|
||||||
const { dataType, data, enableImage, enableAudio, enableVideo, enableBinary, members } = detail;
|
const { dataType, data, enableImage, enableAudio, enableVideo, enableBinary, members, created } = detail;
|
||||||
const sealed = dataType === 'sealed';
|
const sealed = dataType === 'sealed';
|
||||||
const channelData = sealed ? entry.item.unsealedDetail : data;
|
const channelData = sealed ? entry.item.unsealedDetail : data;
|
||||||
const focusDetail = {
|
const focusDetail = {
|
||||||
@ -568,6 +568,7 @@ export class ContactModule implements Contact {
|
|||||||
enableAudio,
|
enableAudio,
|
||||||
enableVideo,
|
enableVideo,
|
||||||
enableBinary,
|
enableBinary,
|
||||||
|
created,
|
||||||
members: members.map(guid => ({ guid })),
|
members: members.map(guid => ({ guid })),
|
||||||
}
|
}
|
||||||
this.focus.setDetail(cardId, id, focusDetail);
|
this.focus.setDetail(cardId, id, focusDetail);
|
||||||
@ -715,7 +716,7 @@ export class ContactModule implements Contact {
|
|||||||
this.focus = new FocusModule(this.log, this.store, this.crypto, this.media, cardId, channelId, this.guid, { node, secure: !insecure, token: `${guid}.${token}` }, channelKey, sealEnabled, revision, markRead, flagTopic);
|
this.focus = new FocusModule(this.log, this.store, this.crypto, this.media, cardId, channelId, this.guid, { node, secure: !insecure, token: `${guid}.${token}` }, channelKey, sealEnabled, revision, markRead, flagTopic);
|
||||||
|
|
||||||
// set current detail
|
// set current detail
|
||||||
const { dataType, data, enableImage, enableAudio, enableVideo, enableBinary, members } = channelEntry.item.detail;
|
const { dataType, data, enableImage, enableAudio, enableVideo, enableBinary, members, created } = channelEntry.item.detail;
|
||||||
const sealed = dataType === 'sealed';
|
const sealed = dataType === 'sealed';
|
||||||
const channelData = sealed ? channelEntry.item.unsealedDetail : data;
|
const channelData = sealed ? channelEntry.item.unsealedDetail : data;
|
||||||
const focusDetail = {
|
const focusDetail = {
|
||||||
@ -727,6 +728,7 @@ export class ContactModule implements Contact {
|
|||||||
enableAudio,
|
enableAudio,
|
||||||
enableVideo,
|
enableVideo,
|
||||||
enableBinary,
|
enableBinary,
|
||||||
|
created,
|
||||||
members: members.map(guid => ({ guid })),
|
members: members.map(guid => ({ guid })),
|
||||||
}
|
}
|
||||||
this.focus.setDetail(cardId, channelId, focusDetail);
|
this.focus.setDetail(cardId, channelId, focusDetail);
|
||||||
@ -1122,7 +1124,7 @@ export class ContactModule implements Contact {
|
|||||||
const { data } = await this.crypto.aesDecrypt(subjectEncrypted, subjectIv, item.channelKey);
|
const { data } = await this.crypto.aesDecrypt(subjectEncrypted, subjectIv, item.channelKey);
|
||||||
item.unsealedDetail = data;
|
item.unsealedDetail = data;
|
||||||
if (this.focus) {
|
if (this.focus) {
|
||||||
const { dataType, enableImage, enableAudio, enableVideo, enableBinary, members } = item.detail;
|
const { dataType, enableImage, enableAudio, enableVideo, enableBinary, members, created } = item.detail;
|
||||||
const focusDetail = {
|
const focusDetail = {
|
||||||
sealed: true,
|
sealed: true,
|
||||||
locked: false,
|
locked: false,
|
||||||
@ -1132,6 +1134,7 @@ export class ContactModule implements Contact {
|
|||||||
enableAudio,
|
enableAudio,
|
||||||
enableVideo,
|
enableVideo,
|
||||||
enableBinary,
|
enableBinary,
|
||||||
|
created,
|
||||||
members: members.map(guid => ({ guid })),
|
members: members.map(guid => ({ guid })),
|
||||||
}
|
}
|
||||||
this.focus.setDetail(cardId, channelId, focusDetail);
|
this.focus.setDetail(cardId, channelId, focusDetail);
|
||||||
|
@ -152,7 +152,7 @@ export class StreamModule {
|
|||||||
await this.unsealChannelDetail(id, entry.item);
|
await this.unsealChannelDetail(id, entry.item);
|
||||||
entry.channel = this.setChannel(id, entry.item);
|
entry.channel = this.setChannel(id, entry.item);
|
||||||
if (this.focus) {
|
if (this.focus) {
|
||||||
const { dataType, data, enableImage, enableAudio, enableVideo, enableBinary, members } = detail;
|
const { dataType, data, enableImage, enableAudio, enableVideo, enableBinary, members, created } = detail;
|
||||||
const sealed = dataType === 'sealed';
|
const sealed = dataType === 'sealed';
|
||||||
const channelData = sealed ? entry.item.unsealedDetail : data;
|
const channelData = sealed ? entry.item.unsealedDetail : data;
|
||||||
const focusDetail = {
|
const focusDetail = {
|
||||||
@ -164,6 +164,7 @@ export class StreamModule {
|
|||||||
enableAudio,
|
enableAudio,
|
||||||
enableVideo,
|
enableVideo,
|
||||||
enableBinary,
|
enableBinary,
|
||||||
|
created,
|
||||||
members: members.map(guid => ({ guid })),
|
members: members.map(guid => ({ guid })),
|
||||||
}
|
}
|
||||||
this.focus.setDetail(null, id, focusDetail);
|
this.focus.setDetail(null, id, focusDetail);
|
||||||
@ -440,7 +441,7 @@ export class StreamModule {
|
|||||||
this.focus = new FocusModule(this.log, this.store, this.crypto, this.media, null, channelId, this.guid, { node, secure, token }, channelKey, sealEnabled, revision, markRead, flagTopic);
|
this.focus = new FocusModule(this.log, this.store, this.crypto, this.media, null, channelId, this.guid, { node, secure, token }, channelKey, sealEnabled, revision, markRead, flagTopic);
|
||||||
|
|
||||||
if (entry) {
|
if (entry) {
|
||||||
const { dataType, data, enableImage, enableAudio, enableVideo, enableBinary, members } = entry.item.detail;
|
const { dataType, data, enableImage, enableAudio, enableVideo, enableBinary, members, created } = entry.item.detail;
|
||||||
const sealed = dataType === 'sealed';
|
const sealed = dataType === 'sealed';
|
||||||
const channelData = sealed ? entry.item.unsealedDetail : data;
|
const channelData = sealed ? entry.item.unsealedDetail : data;
|
||||||
const focusDetail = {
|
const focusDetail = {
|
||||||
@ -452,6 +453,7 @@ export class StreamModule {
|
|||||||
enableAudio,
|
enableAudio,
|
||||||
enableVideo,
|
enableVideo,
|
||||||
enableBinary,
|
enableBinary,
|
||||||
|
created,
|
||||||
members: members.map(guid => ({ guid })),
|
members: members.map(guid => ({ guid })),
|
||||||
}
|
}
|
||||||
this.focus.setDetail(null, channelId, focusDetail);
|
this.focus.setDetail(null, channelId, focusDetail);
|
||||||
@ -605,7 +607,7 @@ export class StreamModule {
|
|||||||
const { data } = await this.crypto.aesDecrypt(subjectEncrypted, subjectIv, item.channelKey);
|
const { data } = await this.crypto.aesDecrypt(subjectEncrypted, subjectIv, item.channelKey);
|
||||||
item.unsealedDetail = data;
|
item.unsealedDetail = data;
|
||||||
if (this.focus) {
|
if (this.focus) {
|
||||||
const { dataType, enableImage, enableAudio, enableVideo, enableBinary, members } = item.detail;
|
const { dataType, enableImage, enableAudio, enableVideo, enableBinary, members, created } = item.detail;
|
||||||
const focusDetail = {
|
const focusDetail = {
|
||||||
sealed: true,
|
sealed: true,
|
||||||
locked: false,
|
locked: false,
|
||||||
@ -615,6 +617,7 @@ export class StreamModule {
|
|||||||
enableAudio,
|
enableAudio,
|
||||||
enableVideo,
|
enableVideo,
|
||||||
enableBinary,
|
enableBinary,
|
||||||
|
created,
|
||||||
members: members.map(guid => ({ guid })),
|
members: members.map(guid => ({ guid })),
|
||||||
}
|
}
|
||||||
this.focus.setDetail(null, channelId, focusDetail);
|
this.focus.setDetail(null, channelId, focusDetail);
|
||||||
|
@ -75,6 +75,7 @@ export type FocusDetail = {
|
|||||||
enableAudio: boolean;
|
enableAudio: boolean;
|
||||||
enableVideo: boolean;
|
enableVideo: boolean;
|
||||||
enableBinary: boolean;
|
enableBinary: boolean;
|
||||||
|
created: number;
|
||||||
members: Member[];
|
members: Member[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user