diff --git a/app/client/web/src/constants/Strings.ts b/app/client/web/src/constants/Strings.ts index 8226bc5e..4120d9c6 100644 --- a/app/client/web/src/constants/Strings.ts +++ b/app/client/web/src/constants/Strings.ts @@ -52,6 +52,7 @@ export const en = { subject: 'Subject', noContacts: 'No Contacts', noTopics: 'No Topics', + noMessages: 'No Messages', noConnected: 'No Connected Contacts', subjectOptional: 'Subject (optional)', members: 'Members', @@ -363,6 +364,7 @@ export const fr = { subject: 'Sujet', noContacts: 'Pas de Contacts', noTopics: 'Pas de Sujets', + noMessages: 'Pas de Messages', noConnected: 'Pas de Contacts Connecter', subjectOptional: 'Sujet (optionnel)', members: 'Membres', @@ -637,8 +639,9 @@ export const sp = { newTopic: 'Nuevo tema', subject: 'Tema', - noContacts: 'Sin contactos', - noTopics: 'Sin temas', + noContacts: 'Sin Contactos', + noTopics: 'Sin Temas', + noMessages: 'Sin Mensajes', noConnected: 'Ningún contacto conectado', subjectOptional: 'Tema (opcional)', members: 'Miembros', @@ -912,8 +915,9 @@ export const pt = { newTopic: 'Novo tópico', subject: 'Assunto', - noContacts: 'Sem contatos', - noTopics: 'Sem tópicos', + noContacts: 'Sem Contatos', + noTopics: 'Sem Tópicos', + noMessages: 'Sem Mensagem', noConnected: 'Nenhum contato conectado', subjectOptional: 'Assunto (opcional)', members: 'Membros', @@ -1189,6 +1193,7 @@ export const de = { subject: 'Betreff', noContacts: 'Keine Kontakte', noTopics: 'Keine Themen', + noMessages: 'Keine Nachrichten', noConnected: 'Keine verbundenen Kontakte', subjectOptional: 'Betreff (optional)', members: 'Mitglieder', @@ -1464,6 +1469,7 @@ export const ru = { subject: 'Тема', noContacts: 'Нет контактов', noTopics: 'Нет тем', + noMessages: 'Нет сообщений', noConnected: 'Нет подключенных контактов', subjectOptional: 'Тема (необязательно)', members: 'Участники', diff --git a/app/client/web/src/settings/Settings.module.css b/app/client/web/src/settings/Settings.module.css index 09e8f132..e091f0fe 100644 --- a/app/client/web/src/settings/Settings.module.css +++ b/app/client/web/src/settings/Settings.module.css @@ -280,7 +280,7 @@ } .empty { - width: 600px; + width: 400px; height: 128px; display: flex; align-items: center; @@ -295,7 +295,7 @@ } } .blocked { - width: 600px; + width: 400px; min-height: 128px; max-height: 256px; border: 1px solid var(--mantine-color-text-7); @@ -312,6 +312,10 @@ padding-bottom: 8px; border-bottom: 1px solid var(--mantine-color-text-8); + &:hover { + background: var(--mantine-color-surface-2); + } + .blockedValue { flex-grow: 1; font-size: 14px; diff --git a/app/client/web/src/settings/Settings.tsx b/app/client/web/src/settings/Settings.tsx index 846b6133..3c7483da 100644 --- a/app/client/web/src/settings/Settings.tsx +++ b/app/client/web/src/settings/Settings.tsx @@ -45,7 +45,7 @@ export function Settings({ showLogout }: { showLogout: boolean }) { const [mfaOpened, { open: mfaOpen, close: mfaClose }] = useDisclosure(false) const [sealOpened, { open: sealOpen, close: sealClose }] = useDisclosure(false) const [blockedContactOpened, { open: blockedContactOpen, close: blockedContactClose }] = useDisclosure(false) - const [blockedTopicOpened, { open: blockedTopicOpen, close: blockedTopicClose }] = useDisclosure(false) + const [blockedChannelOpened, { open: blockedChannelOpen, close: blockedChannelClose }] = useDisclosure(false) const [blockedMessageOpened, { open: blockedMessageOpen, close: blockedMessageClose }] = useDisclosure(false) const [savingLogin, setSavingLogin] = useState(false) const [savingDetails, setSavingDetails] = useState(false) @@ -66,19 +66,62 @@ export function Settings({ showLogout }: { showLogout: boolean }) { blockedContactOpen(); } - const unblockCard = async (cardId: string) => { + const unblockCard = async (blocked: {cardId: string, timestamp: number}) => { try { - await actions.unblockCard(cardId); + await actions.unblockCard(blocked.cardId); } catch (err) { console.log(err); showError(); } } - const blockedCards = state.blockedCards.map(blocked => ( -
- CardID: { blocked.cardId } - unblockCard(blocked.cardId)}> + const blockedCards = state.blockedCards.map((blocked, index) => ( +
+ { actions.getTimestamp(blocked.timestamp) } + unblockCard(blocked)}> +
+ )); + + const showBlockedChannels = async () => { + await actions.loadBlockedChannels(); + blockedChannelOpen(); + } + + const unblockChannel = async (blocked: {cardId: string | null, channelId: string, timestamp: number}) => { + try { + await actions.unblockChannel(blocked.cardId, blocked.channelId); + } catch (err) { + console.log(err); + showError(); + } + } + + const blockedChannels = state.blockedChannels.map((blocked, index) => ( +
+ { actions.getTimestamp(blocked.timestamp) } + unblockChannel(blocked)}> +
+ )); + + + const showBlockedMessages = async () => { + await actions.loadBlockedMessages(); + blockedMessageOpen(); + } + + const unblockMessage = async (blocked: {cardId: string | null, channelId: string, topicId: string, timestamp: number}) => { + try { + await actions.unblockMessage(blocked.cardId, blocked.channelId, blocked.topicId); + } catch (err) { + console.log(err); + showError(); + } + } + + const blockedMessages = state.blockedMessages.map((blocked, index) => ( +
+ { actions.getTimestamp(blocked.timestamp) } + unblockMessage(blocked)}>
)); @@ -461,13 +504,13 @@ export function Settings({ showLogout }: { showLogout: boolean }) {
{state.strings.blockedContacts} -
+
{state.strings.blockedTopics}
-
+
@@ -845,11 +888,39 @@ export function Settings({ showLogout }: { showLogout: boolean }) {
- -
+ + { blockedChannels.length > 0 && ( +
+ { blockedChannels } +
+ )} + { blockedChannels.length === 0 && ( +
+ { state.strings.noTopics } +
+ )} +
+ +
-
+ { blockedMessages.length > 0 && ( +
+ { blockedMessages } +
+ )} + { blockedMessages.length === 0 && ( +
+ { state.strings.noMessages } +
+ )} +
+ +
) diff --git a/app/client/web/src/settings/useSettings.hook.ts b/app/client/web/src/settings/useSettings.hook.ts index a0564c91..6d2e3223 100644 --- a/app/client/web/src/settings/useSettings.hook.ts +++ b/app/client/web/src/settings/useSettings.hook.ts @@ -50,7 +50,9 @@ export function useSettings() { sealConfirm: '', sealDelete: '', secretCopied: false, - blockedCards: [] as {cardId: string}[], + blockedCards: [] as {cardId: string, timestamp: number}[], + blockedChannels: [] as {cardId: string | null, channelId: string, timestamp: number}[], + blockedMessages: [] as {cardId: string | null, channelId: string, topicId: string, timestamp: number}[], }) // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -113,6 +115,30 @@ export function useSettings() { }, [display.state]) const actions = { + loadBlockedMessages: async () => { + const settings = app.state.session.getSettings(); + const blockedMessages = await settings.getBlockedTopics(); + updateState({ blockedMessages }); + }, + unblockMessage: async (cardId: string | null, channelId: string, topicId: string) => { + const content = app.state.session.getContent(); + await content.clearBlockedChannelTopic(cardId, channelId, topicId); + const blockedMessages = state.blockedMessages.filter(blocked => (blocked.cardId != cardId || blocked.channelId != channelId || blocked.topicId != topicId)); + updateState({ blockedMessages }); + }, + loadBlockedChannels: async () => { +console.log("LOAD BLOCKED"); + const settings = app.state.session.getSettings(); + const blockedChannels = await settings.getBlockedChannels(); +console.log("LOADED: ", blockedChannels); + updateState({ blockedChannels }); + }, + unblockChannel: async (cardId: string | null, channelId: string) => { + const content = app.state.session.getContent(); + await content.setBlockedChannel(cardId, channelId, false); + const blockedChannels = state.blockedChannels.filter(blocked => (blocked.cardId != cardId || blocked.channelId != channelId)); + updateState({ blockedChannels }); + }, loadBlockedCards: async () => { const settings = app.state.session.getSettings(); const blockedCards = await settings.getBlockedCards(); @@ -314,6 +340,35 @@ export function useSettings() { const data = dataUrl.split(',')[1] await identity.setProfileImage(data) }, + 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"); + } + } + } } return { state, actions } diff --git a/app/sdk/src/api.ts b/app/sdk/src/api.ts index 844869ff..17eb15d7 100644 --- a/app/sdk/src/api.ts +++ b/app/sdk/src/api.ts @@ -44,9 +44,9 @@ export interface Settings { updateSeal(password: string): Promise; forgetSeal(): Promise; - getBlockedCards(): Promise<{cardId: string}[]>; - getBlockedChannels(): Promise<{cardId: string | null, channelId: string}[]>; - getBlockedTopicis(): Promise<{cardId: string | null, channelId: string, topicId: string}[]>; + getBlockedCards(): Promise<{cardId: string, timestamp: number}[]>; + getBlockedChannels(): Promise<{cardId: string | null, channelId: string, timestamp: number}[]>; + getBlockedTopicis(): Promise<{cardId: string | null, channelId: string, topicId: string, timestamp: number}[]>; addConfigListener(ev: (config: Config) => void): void; removeConfigListener(ev: (config: Config) => void): void; diff --git a/app/sdk/src/contact.ts b/app/sdk/src/contact.ts index b0fc31f9..f700f8e2 100644 --- a/app/sdk/src/contact.ts +++ b/app/sdk/src/contact.ts @@ -199,7 +199,8 @@ export class ContactModule implements Contact { this.blockedCard.add(cardId); entry.card = this.setCard(cardId, entry.item); this.emitCards(); - await this.store.setMarker(this.guid, 'blocked_card', cardId, JSON.stringify({cardId})); + const timestamp = Math.floor(Date.now() / 1000); + await this.store.setMarker(this.guid, 'blocked_card', cardId, JSON.stringify({cardId, timestamp})); } private async clearCardBlocked(cardId: string) { @@ -231,7 +232,8 @@ export class ContactModule implements Contact { this.blockedCardChannel.add(id); channelEntry.channel = this.setChannel(cardId, channelId, channelEntry.item); this.emitChannels(cardId); - await this.store.setMarker(this.guid, 'blocked_card_channel', id, JSON.stringify({ cardId, channelId })); + const timestamp = Math.floor(Date.now() / 1000); + await this.store.setMarker(this.guid, 'blocked_card_channel', id, JSON.stringify({ cardId, channelId, timestamp })); } private async clearChannelBlocked(cardId: string, channelId: string) { @@ -871,6 +873,7 @@ export class ContactModule implements Contact { } public async clearBlockedChannelTopic(cardId: string, channelId: string, topicId: string) { + const { guid } = this; const id = `${cardId}:${channelId}:${topicId}` await this.store.clearMarker(guid, 'blocked_topic', id); if (this.focus) { diff --git a/app/sdk/src/focus.ts b/app/sdk/src/focus.ts index c0390c1d..a1334ecf 100644 --- a/app/sdk/src/focus.ts +++ b/app/sdk/src/focus.ts @@ -822,7 +822,8 @@ export class FocusModule implements Focus { this.blocked.add(id); entry.topic = this.setTopic(topicId, entry.item); this.emitTopics(); - await this.store.setMarker(guid, 'blocked_topic', id, JSON.stringify({ cardId, channelId, topicId })); + const timestamp = Math.floor(Date.now() / 1000); + await this.store.setMarker(guid, 'blocked_topic', id, JSON.stringify({ cardId, channelId, topicId, timestamp })); } } diff --git a/app/sdk/src/settings.ts b/app/sdk/src/settings.ts index f3cc5f72..d245ed11 100644 --- a/app/sdk/src/settings.ts +++ b/app/sdk/src/settings.ts @@ -280,7 +280,7 @@ export class SettingsModule implements Settings { await setAccountLogin(node, secure, token, username, password); } - public async getBlockedCards(): Promise<{cardId: string}[]> { + public async getBlockedCards(): Promise<{cardId: string, timestamp: number}[]> { const { guid } = this; const blockedContacts = await this.store.getMarkers(guid, 'blocked_card'); return blockedContacts.map(marker => { @@ -292,13 +292,28 @@ export class SettingsModule implements Settings { }); } - public async getBlockedChannels(): Promise<{cardId: string | null, channelId: string}[]> { - const blockedChannels = await this.store.getMarkers(guid, 'blocked_card_channel'); - return []; + public async getBlockedChannels(): Promise<{cardId: string | null, channelId: string, timestamp: number}[]> { + const { guid } = this; + const blockedChannels = await this.store.getMarkers(guid, 'blocked_channel'); + const blockedCardChannels = await this.store.getMarkers(guid, 'blocked_card_channel'); + return blockedChannels.concat(blockedCardChannels).map(marker => { + try { + return JSON.parse(marker.value); + } catch (err) { + return {}; + } + }); } - public async getBlockedTopics(): Promise<{cardId: string | null, channelId: string, topicId: string}[]> { + public async getBlockedTopics(): Promise<{cardId: string | null, channelId: string, topicId: string, timestamp: number}[]> { + const { guid } = this; const blockedTopics = await this.store.getMarkers(guid, 'blocked_topic'); - return []; + return blockedTopics.map(marker => { + try { + return JSON.parse(marker.value); + } catch (err) { + return {}; + } + }); } } diff --git a/app/sdk/src/stream.ts b/app/sdk/src/stream.ts index efbe6005..81aaa4c9 100644 --- a/app/sdk/src/stream.ts +++ b/app/sdk/src/stream.ts @@ -509,7 +509,8 @@ export class StreamModule { this.blocked.add(channelId); entry.channel = this.setChannel(channelId, entry.item); this.emitChannels(); - await this.store.setMarker(this.guid, 'blocked_channel', channelId, JSON.stringify({ cardId: null, channelId })); + const timestamp = Math.floor(Date.now() / 1000); + await this.store.setMarker(this.guid, 'blocked_channel', channelId, JSON.stringify({ cardId: null, channelId, timestamp })); } private async clearChannelBlocked(channelId: string) {