diff --git a/app/client/web/src/contacts/Contacts.module.css b/app/client/web/src/contacts/Contacts.module.css
index 7bf78525..f9b00768 100644
--- a/app/client/web/src/contacts/Contacts.module.css
+++ b/app/client/web/src/contacts/Contacts.module.css
@@ -78,7 +78,7 @@
padding-bottom: 8px;
padding-right: 16px;
padding-left: 16px;
- border-bottom: 1px solid var(--mantine-color-text-9);
+ border-bottom: 1px solid var(--mantine-color-text-8);
&:hover {
background: var(--mantine-color-surface-4);
diff --git a/app/client/web/src/content/Content.module.css b/app/client/web/src/content/Content.module.css
index 7fa4a992..de1985be 100644
--- a/app/client/web/src/content/Content.module.css
+++ b/app/client/web/src/content/Content.module.css
@@ -15,7 +15,7 @@
padding-left: 16px;
padding-right: 16px;
padding-bottom: 8px;
- border-bottom: 2px solid var(--mantine-color-text-9);
+ border-bottom: 2px solid var(--mantine-color-text-7);
width: 100%;
.input {
@@ -37,7 +37,7 @@
display: flex;
align-items: center;
justify-content: center;
- border-top: 2px solid var(--mantine-color-text-9);
+ border-top: 2px solid var(--mantine-color-text-7);
.add {
padding-left: 48px;
@@ -68,7 +68,7 @@
padding-bottom: 8px;
padding-right: 16px;
padding-left: 16px;
- border-bottom: 1px solid var(--mantine-color-text-9);
+ border-bottom: 1px solid var(--mantine-color-text-8);
&:hover {
background: var(--mantine-color-surface-4);
@@ -76,3 +76,15 @@
}
}
}
+
+.addContainer {
+ display: flex;
+ flex-direction: column;
+ gap: 16px;
+
+ .addMembers {
+ width: 100%;
+ height: 200px;
+ background: var(--mantine-color-surface-0);
+ }
+}
diff --git a/app/client/web/src/content/Content.tsx b/app/client/web/src/content/Content.tsx
index e50d5aae..def44adb 100644
--- a/app/client/web/src/content/Content.tsx
+++ b/app/client/web/src/content/Content.tsx
@@ -1,13 +1,17 @@
-import React from 'react';
+import React, {useState} from 'react';
import { useContent } from './useContent.hook'
-import { TextInput, Button } from '@mantine/core'
-import { IconSearch, IconMessagePlus } from '@tabler/icons-react'
+import { Modal, TextInput, Button } from '@mantine/core'
+import { IconSearch, IconMessagePlus, IconLabel } from '@tabler/icons-react'
import classes from './Content.module.css'
import { Channel } from '../channel/Channel'
import { Focus } from 'databag-client-sdk'
export function Content({ select }: { select: (focus: Focus) => void }) {
const { state, actions } = useContent()
+ const [add, setAdd] = useState(false);
+
+ const addTopic = async () => {
+ }
const channels = state.filtered.map((channel, idx) => {
return (
@@ -41,7 +45,7 @@ export function Content({ select }: { select: (focus: Focus) => void }) {
onChange={(event) => actions.setFilter(event.currentTarget.value)}
/>
{state.layout === 'small' && (
- } onClick={actions.addChannel}>
+ } onClick={() => setAdd(true)}>
{state.strings.add}
)}
@@ -50,11 +54,27 @@ export function Content({ select }: { select: (focus: Focus) => void }) {
{channels.length !== 0 &&
{channels}
}
{state.layout === 'large' && (
- } onClick={actions.addChannel}>
+ } onClick={() => setAdd(true)}>
{state.strings.add}
)}
+ setAdd(false)} overlayProps={{ backgroundOpacity: 0.55, blur: 3 }} centered>
+
+
}
+ placeholder={state.strings.subjectOptional}
+ value={state.filter}
+ onChange={(event) => actions.setFilter(event.currentTarget.value)}
+ />
+
+
+
+
+
)
}
diff --git a/app/client/web/src/content/useContent.hook.ts b/app/client/web/src/content/useContent.hook.ts
index 8e3787c9..5d992d96 100644
--- a/app/client/web/src/content/useContent.hook.ts
+++ b/app/client/web/src/content/useContent.hook.ts
@@ -1,180 +1,243 @@
-import { useState, useContext, useEffect, useRef } from 'react'
-import { AppContext } from '../context/AppContext'
-import { DisplayContext } from '../context/DisplayContext'
-import { ContextType } from '../context/ContextType'
-import { Channel, Card, Profile } from 'databag-client-sdk'
-import { notes, unknown, iii_group, iiii_group, iiiii_group, group } from '../constants/Icons'
+import {useState, useContext, useEffect, useRef} from 'react';
+import {AppContext} from '../context/AppContext';
+import {DisplayContext} from '../context/DisplayContext';
+import {ContextType} from '../context/ContextType';
+import {Channel, Card, Profile, Config} from 'databag-client-sdk';
+import {notes, unknown, iii_group, iiii_group, iiiii_group, group} from '../constants/Icons';
type ChannelParams = {
- cardId: string
- channelId: string
- sealed: boolean
- hosted: boolean
- unread: boolean
- imageUrl: string
- subject: (string | null)[]
- message: string
-}
+ cardId: string;
+ channelId: string;
+ sealed: boolean;
+ hosted: boolean;
+ unread: boolean;
+ imageUrl: string;
+ subject: (string | null)[];
+ message: string;
+};
export function useContent() {
- const cardChannels = useRef(new Map())
- const app = useContext(AppContext) as ContextType
- const display = useContext(DisplayContext) as ContextType
+ const cardChannels = useRef(new Map());
+ const app = useContext(AppContext) as ContextType;
+ const display = useContext(DisplayContext) as ContextType;
const [state, setState] = useState({
strings: display.state.strings,
layout: null,
guid: '',
- cards: [] as Card[],
+ connected: [] as Card[],
+ connectedAndSealable: [] as Cards[],
sorted: [] as Channel[],
filtered: [] as ChannelParams[],
filter: '',
- })
+ topic: '',
+ sealable: false,
+ });
+
+ const compare = (a: Card, b: Card) => {
+ const aval = `${a.handle}/${a.node}`;
+ const bval = `${b.handle}/${b.node}`;
+ if (aval < bval) {
+ return state.sortAsc ? 1 : -1;
+ } else if (aval > bval) {
+ return state.sortAsc ? -1 : 1;
+ }
+ return 0;
+ };
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const updateState = (value: any) => {
- setState((s) => ({ ...s, ...value }))
- }
+ setState(s => ({...s, ...value}));
+ };
useEffect(() => {
- const { layout } = display.state
- updateState({ layout })
- }, [display.state])
+ const {layout} = display.state;
+ updateState({layout});
+ }, [display.state]);
useEffect(() => {
- const channels = state.sorted.map((channel) => {
- const { cardId, channelId, unread, sealed, members, data, lastTopic } = channel
- const contacts = [] as (Card | undefined)[]
+ const channels = state.sorted.map(channel => {
+ const {cardId, channelId, unread, sealed, members, dataType, data, lastTopic} = channel;
+ const contacts = [] as (Card | undefined)[];
if (cardId) {
- const card = state.cards.find((contact) => contact.cardId === cardId)
+ const card = state.cards.find(contact => contact.cardId === cardId);
if (card) {
- contacts.push(card)
+ contacts.push(card);
}
}
- const guests = members.filter((contact) => contact.guid !== state.guid)
+ const guests = members.filter(contact => contact.guid !== state.guid);
const guestCards = guests
- .map((contact) => state.cards.find((card) => card.guid === contact.guid))
+ .map(contact => state.cards.find(card => card.guid === contact.guid))
.sort((a, b) => {
if (!a && !b) {
- return 0
+ return 0;
} else if (!a) {
- return 1
+ return 1;
} else if (!b) {
- return -1
+ return -1;
} else if (a.handle > b.handle) {
- return 1
+ return 1;
} else {
- return 0
+ return 0;
}
- })
- contacts.push(...guestCards)
+ });
+ contacts.push(...guestCards);
const buildSubject = () => {
if (contacts.length === 0) {
- return []
+ return [];
}
- return contacts.map((contact) => (contact ? contact.handle : null))
- }
+ return contacts.map(contact => (contact ? contact.handle : null));
+ };
const selectImage = () => {
if (contacts.length == 0) {
- return notes
+ return notes;
} else if (contacts.length == 1) {
if (contacts[0]) {
- return contacts[0].imageUrl
+ return contacts[0].imageUrl;
} else {
- return unknown
+ return unknown;
}
} else if (contacts.length == 2) {
- return iii_group
+ return iii_group;
} else if (contacts.length == 3) {
- return iiii_group
+ return iiii_group;
} else if (contacts.length == 4) {
- return iiiii_group
+ return iiiii_group;
} else {
- return group
+ return group;
+ }
+ };
+
+ const getMessage = () => {
+ if (!lastTopic || !lastTopic.status) {
+ return '';
+ }
+ if (lastTopic.dataType === 'superbasictopic') {
+ if (lastTopic.data?.text) {
+ return lastTopic.data.text;
+ } else {
+ return ''
+ }
+ } else if (lastTopic.dataType === 'sealedtopic') {
+ if (lastTopic.data) {
+ if (lastTopic.data.message?.text) {
+ return lastTopic.data.message.text;
+ } else {
+ return '';
+ }
+ } else {
+ return null;
+ }
}
}
- const hosted = cardId == null
- const subject = data?.subject ? [data.subject] : buildSubject()
- const message = lastTopic ? (lastTopic.data ? lastTopic.data.text : null) : ''
- const imageUrl = selectImage()
+ const hosted = cardId == null;
+ const subject = data?.subject ? [data.subject] : buildSubject();
+ const message = getMessage();
+ const imageUrl = selectImage();
- return { cardId, channelId, sealed, hosted, unread, imageUrl, subject, message }
- })
+ return {cardId, channelId, sealed, hosted, unread, imageUrl, subject, message};
+ });
- const search = state.filter?.toLowerCase()
- const filtered = channels.filter((item) => {
+ const search = state.filter?.toLowerCase();
+ const filtered = channels.filter(item => {
if (search) {
- if (item.subject?.find((value) => value?.toLowerCase().includes(search))) {
- return true
+ if (item.subject?.find(value => value?.toLowerCase().includes(search))) {
+ return true;
}
if (item.message?.toLowerCase().includes(search)) {
- return true
+ return true;
}
- return false
+ return false;
}
- return true
- })
+ return true;
+ });
- updateState({ filtered })
- }, [state.sorted, state.cards, state.guid, state.filter])
+ updateState({filtered});
+ }, [state.sorted, state.cards, state.guid, state.filter]);
useEffect(() => {
+ const setConfig = (config: Config) => {
+ const { sealSet, sealUnlocked } = config;
+ updateState({ sealSet: sealSet && sealUnlocked });
+ };
const setProfile = (profile: Profile) => {
- const { guid } = profile
- updateState({ guid })
- }
+ const {guid} = profile;
+ updateState({guid});
+ };
const setCards = (cards: Card[]) => {
- updateState({ cards })
- }
- const setChannels = ({ channels, cardId }: { channels: Channel[], cardId: string | null }) => {
- cardChannels.current.set(cardId, channels)
- const merged = [] as Channel[]
- cardChannels.current.forEach((values) => {
- merged.push(...values)
- })
- const sorted = merged.sort((a, b) => {
- const aUpdated = a?.lastTopic?.created
- const bUpdated = b?.lastTopic?.created
- if (aUpdated == bUpdated) {
- return 0
- } else if (!aUpdated) {
- return 1
- } else if (!bUpdated) {
- return -1
- } else if (aUpdated < bUpdated) {
- return 1
- } else {
- return -1
+ const sorted = cards.sort(compare);
+ const connected = [];
+ const sealable = [];
+ sorted.forEach(card => {
+ if (card.status === 'connected') {
+ connected.push(card);
+ if (card.sealable) {
+ sealable.push(card);
+ }
}
- })
- updateState({ sorted })
- }
+ });
+ updateState({cards, connected, sealable});
+ };
+ const setChannels = ({channels, cardId}: {channels: Channel[]; cardId: string | null}) => {
+ cardChannels.current.set(cardId, channels);
+ const merged = [] as Channel[];
+ cardChannels.current.forEach(values => {
+ merged.push(...values);
+ });
+ const sorted = merged.sort((a, b) => {
+ const aUpdated = a?.lastTopic?.created;
+ const bUpdated = b?.lastTopic?.created;
+ if (aUpdated == bUpdated) {
+ return 0;
+ } else if (!aUpdated) {
+ return 1;
+ } else if (!bUpdated) {
+ return -1;
+ } else if (aUpdated < bUpdated) {
+ return 1;
+ } else {
+ return -1;
+ }
+ });
+ updateState({sorted});
+ };
- const { identity, contact, content } = app.state.session
- identity.addProfileListener(setProfile)
- contact.addCardListener(setCards)
- content.addChannelListener(setChannels)
+ const {identity, contact, content, settings} = app.state.session;
+ identity.addProfileListener(setProfile);
+ contact.addCardListener(setCards);
+ content.addChannelListener(setChannels);
+ settings.addConfigListener(setConfig);
return () => {
- identity.removeProfileListener(setProfile)
- contact.removeCardListener(setCards)
- content.removeChannelListener(setChannels)
- }
- }, [])
+ identity.removeProfileListener(setProfile);
+ contact.removeCardListener(setCards);
+ content.removeChannelListener(setChannels);
+ settings.removeConfigListener(setConfig);
+ };
+ }, []);
const actions = {
- addChannel: () => {
- console.log('add channel');
- },
setFilter: (filter: string) => {
- updateState({ filter })
+ updateState({filter});
+ },
+ setTopic: (topic: string) => {
+ updateState({topic});
},
getFocus: (cardId: string | null, channelId: string) => {
- return app.state.session.setFocus(cardId, channelId)
+ return app.state.session.setFocus(cardId, channelId);
},
- }
+ addTopic: async (sealed: boolean, subject: string, contacts: string[]) => {
+ const content = app.state.session.getContent();
+ await new Promise(r => setTimeout(r, 2000));
+ if (sealed) {
+ await content.addChannel(true, 'sealed', {subject}, contacts);
+ } else {
+ await content.addChannel(false, 'superbasic', {subject}, contacts);
+ }
+ },
+ };
- return { state, actions }
+ return {state, actions};
}