mirror of
https://github.com/balzack/databag.git
synced 2025-02-12 03:29:16 +00:00
refactor of conversation detail in webapp
This commit is contained in:
parent
a1549747db
commit
9fbfe85d60
@ -46,6 +46,16 @@ export function encryptChannelSubject(subject, publicKeys) {
|
||||
return { subjectEncrypted, subjectIv, seals };
|
||||
}
|
||||
|
||||
export function updateChannelSubject(subject, contentKey) {
|
||||
const key = CryptoJS.enc.Hex.parse(contentKey);
|
||||
const iv = CryptoJS.lib.WordArray.random(128 / 8);
|
||||
const encrypted = CryptoJS.AES.encrypt(JSON.stringify({ subject }), key, { iv: iv });
|
||||
const subjectEncrypted = encrypted.ciphertext.toString(CryptoJS.enc.Base64)
|
||||
const subjectIv = iv.toString();
|
||||
|
||||
return { subjectEncrypted, subjectIv };
|
||||
}
|
||||
|
||||
export function decryptChannelSubject(subject, contentKey) {
|
||||
const { subjectEncrypted, subjectIv } = JSON.parse(subject);
|
||||
const iv = CryptoJS.enc.Hex.parse(subjectIv);
|
||||
|
@ -4,7 +4,7 @@ import { SelectItem } from './selectItem/SelectItem';
|
||||
import { useCardSelect } from './useCardSelect.hook';
|
||||
import { Logo } from 'logo/Logo';
|
||||
|
||||
export function CardSelect({ filter, unknown, select, selected, markup, emptyMessage }) {
|
||||
export function CardSelect({ filter, unknown, select, selected, markup, emptyMessage, setItem, clearItem }) {
|
||||
|
||||
const { state } = useCardSelect(filter);
|
||||
|
||||
@ -13,7 +13,7 @@ export function CardSelect({ filter, unknown, select, selected, markup, emptyMes
|
||||
{ state.cards?.length > 0 && (
|
||||
<List local={{ emptyText: '' }} itemLayout="horizontal" dataSource={state.cards} gutter="0"
|
||||
renderItem={item => (
|
||||
<SelectItem item={item} select={select} selected={selected} markup={markup} />
|
||||
<SelectItem item={item} select={select} selected={selected} markup={markup} setItem={setItem} clearItem={clearItem} />
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
|
@ -3,7 +3,7 @@ import { SelectItemWrapper, Markup } from './SelectItem.styled';
|
||||
import { useSelectItem } from './useSelectItem.hook';
|
||||
import { Logo } from 'logo/Logo';
|
||||
|
||||
export function SelectItem({ item, select, selected, markup }) {
|
||||
export function SelectItem({ item, select, selected, markup, setItem, clearItem }) {
|
||||
|
||||
const { state } = useSelectItem(item, selected, markup);
|
||||
const profile = item?.data?.cardProfile;
|
||||
@ -19,6 +19,12 @@ export function SelectItem({ item, select, selected, markup }) {
|
||||
if (select) {
|
||||
select(item.id);
|
||||
}
|
||||
if (setItem && !state.selected) {
|
||||
setItem(item.id);
|
||||
}
|
||||
if (clearItem && state.selected) {
|
||||
clearItem(item.id);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
@ -29,7 +35,7 @@ export function SelectItem({ item, select, selected, markup }) {
|
||||
<div class="name">{ profile?.name }</div>
|
||||
<div class="handle">{ handle() }</div>
|
||||
</div>
|
||||
{ select && (
|
||||
{ (select || setItem || clearItem) && (
|
||||
<div class="switch">
|
||||
<Switch checked={state.selected} onChange={onSelect} size="small" />
|
||||
</div>
|
||||
|
@ -132,7 +132,7 @@ export function useChannels() {
|
||||
item.sealKey = sealKey;
|
||||
}
|
||||
|
||||
if (item.title == null || typeof item.title !== 'string') {
|
||||
if (item.title == null || item.title === '' || typeof item.title !== 'string') {
|
||||
item.subject = item.label;
|
||||
}
|
||||
else {
|
||||
|
@ -9,10 +9,38 @@ import { EditSubject } from './editSubject/EditSubject';
|
||||
import { EditMembers } from './editMembers/EditMembers';
|
||||
import { UnlockOutlined, LockFilled } from '@ant-design/icons';
|
||||
|
||||
export function Details({ cardId, channelId, closeDetails, closeConversation, openContact }) {
|
||||
export function Details({ closeDetails, closeConversation, openContact }) {
|
||||
|
||||
const [modal, modalContext] = Modal.useModal();
|
||||
const { state, actions } = useDetails(cardId, channelId);
|
||||
const { state, actions } = useDetails();
|
||||
|
||||
const setMember = async (id) => {
|
||||
try {
|
||||
await actions.setMember(id);
|
||||
}
|
||||
catch(err) {
|
||||
console.log(err);
|
||||
modal.error({
|
||||
title: 'Failed to Set Conversation Member',
|
||||
content: 'Please try again.',
|
||||
bodyStyle: { padding: 16 },
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const clearMember = async (id) => {
|
||||
try {
|
||||
await actions.clearMember(id);
|
||||
}
|
||||
catch(err) {
|
||||
console.log(err);
|
||||
modal.error({
|
||||
title: 'Failed to Clear Conversation Member',
|
||||
content: 'Please try again.',
|
||||
bodyStyle: { padding: 16 },
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const deleteChannel = async () => {
|
||||
modal.confirm({
|
||||
@ -30,7 +58,7 @@ export function Details({ cardId, channelId, closeDetails, closeConversation, op
|
||||
|
||||
const applyDeleteChannel = async () => {
|
||||
try {
|
||||
await actions.deleteChannel();
|
||||
await actions.removeChannel();
|
||||
closeConversation();
|
||||
}
|
||||
catch(err) {
|
||||
@ -58,7 +86,7 @@ export function Details({ cardId, channelId, closeDetails, closeConversation, op
|
||||
|
||||
const applyLeaveChannel = async () => {
|
||||
try {
|
||||
await actions.leaveChannel();
|
||||
await actions.removeChannel();
|
||||
closeConversation();
|
||||
}
|
||||
catch(err) {
|
||||
@ -121,19 +149,24 @@ export function Details({ cardId, channelId, closeDetails, closeConversation, op
|
||||
<div class="content">
|
||||
<div class="description">
|
||||
<div class="logo">
|
||||
<Logo width={72} height={72} radius={4} img={state.img} />
|
||||
<Logo src={state.logo} width={72} height={72} radius={4} img={state.img} />
|
||||
</div>
|
||||
<div class="stats">
|
||||
{ state.host && (
|
||||
<div class="subject" onClick={actions.setEditSubject}>
|
||||
{ state.locked && !state.unlocked && (
|
||||
{ state.sealed && !state.contentKey && (
|
||||
<LockFilled style={{ paddingRight: 4 }} />
|
||||
)}
|
||||
{ state.locked && state.unlocked && (
|
||||
{ state.sealed && state.contentKey && (
|
||||
<UnlockOutlined style={{ paddingRight: 4 }} />
|
||||
)}
|
||||
<span>{ state.subject }</span>
|
||||
{ state.editable && (
|
||||
{ state.title && (
|
||||
<span>{ state.title }</span>
|
||||
)}
|
||||
{ !state.title && (
|
||||
<span>{ state.label }</span>
|
||||
)}
|
||||
{ (!state.sealed || state.contentKey) && (
|
||||
<span class="edit" onClick={actions.setEditSubject}>
|
||||
<EditOutlined style={{ paddingLeft: 4 }}/>
|
||||
</span>
|
||||
@ -142,13 +175,18 @@ export function Details({ cardId, channelId, closeDetails, closeConversation, op
|
||||
)}
|
||||
{ !state.host && (
|
||||
<div class="subject">
|
||||
{ state.locked && !state.unlocked && (
|
||||
{ state.sealed && !state.contentKey && (
|
||||
<LockFilled style={{ paddingRight: 4 }} />
|
||||
)}
|
||||
{ state.locked && state.unlocked && (
|
||||
{ state.sealed && state.contentKey && (
|
||||
<UnlockOutlined style={{ paddingRight: 4 }} />
|
||||
)}
|
||||
<span>{ state.subject }</span>
|
||||
{ state.title && (
|
||||
<span>{ state.title }</span>
|
||||
)}
|
||||
{ !state.title && (
|
||||
<span>{ state.label }</span>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
{ state.host && (
|
||||
@ -163,7 +201,7 @@ export function Details({ cardId, channelId, closeDetails, closeConversation, op
|
||||
{ state.host && (
|
||||
<div class="button" onClick={deleteChannel}>Delete Topic</div>
|
||||
)}
|
||||
{ state.host && !state.locked && (
|
||||
{ state.host && !state.sealed && (
|
||||
<div class="button" onClick={actions.setEditMembers}>Edit Membership</div>
|
||||
)}
|
||||
{ !state.host && (
|
||||
@ -172,21 +210,21 @@ export function Details({ cardId, channelId, closeDetails, closeConversation, op
|
||||
<div class="label">Members</div>
|
||||
<div class="members">
|
||||
<CardSelect filter={(item) => {
|
||||
if(state.contacts.includes(item.id)) {
|
||||
if(state.members.includes(item.id)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}} unknown={state.unknown}
|
||||
markup={cardId} />
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<Modal title="Edit Subject" centered visible={state.editSubject} footer={editSubjectFooter}
|
||||
<Modal title="Edit Subject" centered visible={state.showEditSubject} footer={editSubjectFooter}
|
||||
bodyStyle={{ padding: 16 }} onCancel={actions.clearEditSubject}>
|
||||
<EditSubject state={state} actions={actions} />
|
||||
<EditSubject subject={state.editSubject} setSubject={actions.setSubjectUpdate} />
|
||||
</Modal>
|
||||
<Modal title="Edit Members" centered visible={state.editMembers} footer={editMembersFooter}
|
||||
<Modal title="Edit Members" centered visible={state.showEditMembers} footer={editMembersFooter}
|
||||
bodyStyle={{ padding: 16 }} onCancel={actions.clearEditMembers}>
|
||||
<EditMembers state={state} actions={actions} />
|
||||
<EditMembers members={state.editMembers} setMember={setMember} clearMember={clearMember} />
|
||||
</Modal>
|
||||
</DetailsWrapper>
|
||||
);
|
||||
|
@ -1,14 +1,15 @@
|
||||
import { EditMembersWrapper } from './EditMembers.styled';
|
||||
import { CardSelect } from '../../cardSelect/CardSelect';
|
||||
|
||||
export function EditMembers({ state, actions }) {
|
||||
export function EditMembers({ members, setMember, clearMember }) {
|
||||
|
||||
return (
|
||||
<EditMembersWrapper>
|
||||
<div class="list">
|
||||
<CardSelect
|
||||
select={actions.onMember}
|
||||
selected={state.members}
|
||||
setItem={setMember}
|
||||
clearItem={clearMember}
|
||||
selected={members}
|
||||
filter={(card) => card?.data?.cardDetail?.status === 'connected'}
|
||||
/>
|
||||
</div>
|
||||
|
@ -1,12 +1,12 @@
|
||||
import { Input } from 'antd';
|
||||
import { EditSubjectWrapper } from './EditSubject.styled';
|
||||
|
||||
export function EditSubject({ state, actions }) {
|
||||
export function EditSubject({ subject, setSubject }) {
|
||||
|
||||
return (
|
||||
<EditSubjectWrapper>
|
||||
<Input placeholder="Subject (optional)" spellCheck="false" autocapitalize="word"
|
||||
value={state.subjectUpdate} onChange={(e) => actions.setSubjectUpdate(e.target.value)} />
|
||||
value={subject} onChange={(e) => setSubject(e.target.value)} />
|
||||
</EditSubjectWrapper>
|
||||
);
|
||||
}
|
||||
|
@ -1,190 +1,236 @@
|
||||
import { useContext, useState, useEffect } from 'react';
|
||||
import { useContext, useState, useEffect, useRef } from 'react';
|
||||
import { CardContext } from 'context/CardContext';
|
||||
import { ChannelContext } from 'context/ChannelContext';
|
||||
import { ConversationContext } from 'context/ConversationContext';
|
||||
import { AccountContext } from 'context/AccountContext';
|
||||
import { ProfileContext } from 'context/ProfileContext';
|
||||
import { ViewportContext } from 'context/ViewportContext';
|
||||
import { getCardByGuid } from 'context/cardUtil';
|
||||
import { decryptChannelSubject, updateChannelSubject, getContentKey, getChannelSeals, isUnsealed } from 'context/sealUtil';
|
||||
|
||||
export function useDetails(cardId, channelId) {
|
||||
export function useDetails() {
|
||||
|
||||
const [state, setState] = useState({
|
||||
logo: null,
|
||||
img: null,
|
||||
subject: null,
|
||||
server: null,
|
||||
started: null,
|
||||
host: null,
|
||||
contacts: [],
|
||||
members: new Set(),
|
||||
editSubject: false,
|
||||
editMembers: false,
|
||||
busy: false,
|
||||
subjectUpdate: null,
|
||||
host: false,
|
||||
title: null,
|
||||
label: null,
|
||||
members: [],
|
||||
unknown: 0,
|
||||
|
||||
showEditMembers: false,
|
||||
editMembers: new Set(),
|
||||
|
||||
showEditSubject: false,
|
||||
editSubject: null,
|
||||
|
||||
display: null,
|
||||
locked: false,
|
||||
unlocked: false,
|
||||
editable: false,
|
||||
sealed: false,
|
||||
contentKey: null,
|
||||
seals: null,
|
||||
});
|
||||
|
||||
const conversation = useContext(ConversationContext);
|
||||
const card = useContext(CardContext);
|
||||
const account = useContext(AccountContext);
|
||||
const channel = useContext(ChannelContext);
|
||||
const viewport = useContext(ViewportContext);
|
||||
const viewport = useContext(ViewportContext);
|
||||
const profile = useContext(ProfileContext);
|
||||
|
||||
const cardId = useRef();
|
||||
const channelId = useRef();
|
||||
const key = useRef();
|
||||
const detailRevision = useRef();
|
||||
|
||||
const updateState = (value) => {
|
||||
setState((s) => ({ ...s, ...value }));
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
const { dataType, data } = conversation.state.channel?.data?.channelDetail || {};
|
||||
if (dataType === 'sealed') {
|
||||
try {
|
||||
const { sealKey } = account.state;
|
||||
const seals = getChannelSeals(data);
|
||||
if (isUnsealed(seals, sealKey)) {
|
||||
const decKey = getContentKey(seals, sealKey);
|
||||
updateState({ sealed: true, contentKey: decKey, seals });
|
||||
}
|
||||
else {
|
||||
updateState({ sealed: true, contentKey: null });
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
console.log(err);
|
||||
updateState({ sealed: true, contentKey: null });
|
||||
}
|
||||
}
|
||||
else {
|
||||
updateState({ sealed: false, contentKey: null });
|
||||
}
|
||||
// eslint-disable-next-line
|
||||
}, [account.state.sealKey, conversation.state.channel?.data?.channelDetail]);
|
||||
|
||||
useEffect(() => {
|
||||
updateState({ display: viewport.state.display });
|
||||
}, [viewport]);
|
||||
|
||||
useEffect(() => {
|
||||
let img, subject, subjectUpdate, host, started, contacts, locked, unlocked, editable;
|
||||
let chan;
|
||||
if (cardId) {
|
||||
const cardChan = card.state.cards.get(cardId);
|
||||
if (cardChan) {
|
||||
chan = cardChan.channels.get(channelId);
|
||||
}
|
||||
|
||||
const cardValue = conversation.state.card;
|
||||
const channelValue = conversation.state.channel;
|
||||
|
||||
// extract channel created info
|
||||
let started;
|
||||
let host;
|
||||
const date = new Date(channelValue?.data?.channelDetail?.created * 1000);
|
||||
const now = new Date();
|
||||
if(now.getTime() - date.getTime() < 86400000) {
|
||||
started = date.toLocaleTimeString([], {hour: 'numeric', minute:'2-digit'});
|
||||
}
|
||||
else {
|
||||
chan = channel.state.channels.get(channelId);
|
||||
started = date.toLocaleDateString("en-US");
|
||||
}
|
||||
|
||||
if (chan) {
|
||||
if (chan.contacts?.length === 0) {
|
||||
img = 'solution';
|
||||
subject = 'Notes';
|
||||
}
|
||||
else if (chan.contacts?.length > 1) {
|
||||
img = 'appstore'
|
||||
subject = 'Group';
|
||||
}
|
||||
else {
|
||||
img = 'team';
|
||||
subject = 'Conversation'
|
||||
}
|
||||
if (chan.data.channelDetail.dataType === 'sealed') {
|
||||
editable = false;
|
||||
try {
|
||||
const seals = JSON.parse(chan.data.channelDetail.data).seals;
|
||||
seals.forEach(seal => {
|
||||
if (account.state.sealKey?.public === seal.publicKey) {
|
||||
editable = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
locked = true;
|
||||
unlocked = chan.data.unsealedChannel != null;
|
||||
if (chan.data.unsealedChannel?.subject) {
|
||||
subject = chan.data.unsealedChannel.subject;
|
||||
subjectUpdate = subject;
|
||||
}
|
||||
}
|
||||
else {
|
||||
locked = false;
|
||||
editable = (chan.cardId == null);
|
||||
try {
|
||||
const parsed = JSON.parse(chan.data.channelDetail.data);
|
||||
if (parsed.subject) {
|
||||
subject = parsed.subject;
|
||||
subjectUpdate = subject;
|
||||
}
|
||||
}
|
||||
catch(err) {
|
||||
console.log(err);
|
||||
}
|
||||
}
|
||||
const date = new Date(chan.data.channelDetail.created * 1000);
|
||||
const now = new Date();
|
||||
if(now.getTime() - date.getTime() < 86400000) {
|
||||
started = date.toLocaleTimeString([], {hour: 'numeric', minute:'2-digit'});
|
||||
}
|
||||
else {
|
||||
started = date.toLocaleDateString("en-US");
|
||||
}
|
||||
if (chan.cardId) {
|
||||
host = false;
|
||||
}
|
||||
else {
|
||||
host = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (chan?.contacts ) {
|
||||
contacts = chan.contacts.map((contact) => contact?.id);
|
||||
if (cardValue) {
|
||||
host = false;
|
||||
}
|
||||
else {
|
||||
contacts = [];
|
||||
host = true;
|
||||
}
|
||||
|
||||
let members = new Set(contacts);
|
||||
|
||||
// extract member info
|
||||
let memberCount = 0;
|
||||
let names = [];
|
||||
let img;
|
||||
let logo;
|
||||
let members = [];
|
||||
let unknown = 0;
|
||||
contacts.forEach(id => {
|
||||
if (id == null) {
|
||||
unknown++;
|
||||
if (cardValue) {
|
||||
members.push(cardValue.id);
|
||||
const profile = cardValue.data?.cardProfile;
|
||||
if (profile?.name) {
|
||||
names.push(profile.name);
|
||||
}
|
||||
});
|
||||
if (profile?.imageSet) {
|
||||
img = null;
|
||||
logo = card.actions.getCardImageUrl(cardValue.id);
|
||||
}
|
||||
else {
|
||||
img = 'avatar';
|
||||
logo = null;
|
||||
}
|
||||
memberCount++;
|
||||
}
|
||||
if (channelValue?.data?.channelDetail?.members) {
|
||||
for (let guid of channelValue.data.channelDetail.members) {
|
||||
if (guid !== profile.state.identity.guid) {
|
||||
const contact = getCardByGuid(card.state.cards, guid);
|
||||
if (contact) {
|
||||
members.push(contact.id);
|
||||
}
|
||||
else {
|
||||
unknown++;
|
||||
}
|
||||
|
||||
const profile = contact?.data?.cardProfile;
|
||||
if (profile?.name) {
|
||||
names.push(profile.name);
|
||||
}
|
||||
if (profile?.imageSet) {
|
||||
img = null;
|
||||
logo = card.actions.getCardImageUrl(contact.id);
|
||||
}
|
||||
else {
|
||||
img = 'avatar';
|
||||
logo = null;
|
||||
}
|
||||
memberCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updateState({ img, subject, host, started, contacts, members, unknown, subjectUpdate, locked, unlocked, editable });
|
||||
}, [cardId, channelId, card, channel, account]);
|
||||
let label;
|
||||
if (memberCount === 0) {
|
||||
img = 'solution';
|
||||
label = 'Notes';
|
||||
}
|
||||
else if (memberCount === 1) {
|
||||
label = names.join(',');
|
||||
}
|
||||
else {
|
||||
img = 'appstore';
|
||||
label = names.join(',');
|
||||
}
|
||||
|
||||
if (cardId.current !== cardValue?.id || channelId.current !== channelValue?.id ||
|
||||
detailRevision.current !== channelValue?.data?.detailRevision || key.current !== state.contentKey) {
|
||||
let title;
|
||||
try {
|
||||
const detail = channelValue?.data?.channelDetail;
|
||||
if (detail?.dataType === 'sealed' && state.contentKey) {
|
||||
const unsealed = decryptChannelSubject(detail.data, state.contentKey);
|
||||
title = unsealed.subject;
|
||||
}
|
||||
else if (detail?.dataType === 'superbasic') {
|
||||
const data = JSON.parse(detail.data);
|
||||
title = data.subject;
|
||||
}
|
||||
}
|
||||
catch(err) {
|
||||
console.log(err);
|
||||
}
|
||||
cardId.current = cardValue?.id;
|
||||
channelId.current = channelValue?.id;
|
||||
detailRevision.current = channelValue?.data?.detailRevision;
|
||||
key.current = state.contentKey;
|
||||
updateState({ started, host, title, label, img, logo, unknown, members,
|
||||
editSubject: title, editMembers: new Set(members) });
|
||||
}
|
||||
else {
|
||||
updateState({ started, host, label, img, logo, unknown, members,
|
||||
editMembers: new Set(members) });
|
||||
}
|
||||
// eslint-disable-next-line
|
||||
}, [conversation.state, card.state, state.contentKey]);
|
||||
|
||||
const actions = {
|
||||
setEditSubject: () => {
|
||||
updateState({ editSubject: true });
|
||||
updateState({ showEditSubject: true });
|
||||
},
|
||||
clearEditSubject: () => {
|
||||
updateState({ editSubject: false });
|
||||
updateState({ showEditSubject: false });
|
||||
},
|
||||
setSubjectUpdate: (subjectUpdate) => {
|
||||
updateState({ subjectUpdate });
|
||||
setSubjectUpdate: (editSubject) => {
|
||||
updateState({ editSubject });
|
||||
},
|
||||
setSubject: async () => {
|
||||
if (!state.busy) {
|
||||
try {
|
||||
updateState({ busy: true });
|
||||
if (state.locked) {
|
||||
channel.actions.setChannelSealedSubject(channelId, state.subjectUpdate, account.state.sealKey);
|
||||
}
|
||||
else {
|
||||
channel.actions.setChannelSubject(channelId, state.subjectUpdate);
|
||||
}
|
||||
updateState({ busy: false });
|
||||
}
|
||||
catch(err) {
|
||||
console.log(err);
|
||||
updateState({ busy: false });
|
||||
throw new Error("set channel subject failed");
|
||||
if (state.sealed) {
|
||||
if (state.contentKey) {
|
||||
const updated = updateChannelSubject(state.editSubject, state.contentKey);
|
||||
updated.seals = state.seals;
|
||||
await conversation.actions.setChannelSubject('sealed', updated);
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new Error('operation in progress');
|
||||
const subject = { subject: state.editSubject };
|
||||
await conversation.actions.setChannelSubject('superbasic', subject);
|
||||
}
|
||||
},
|
||||
setEditMembers: () => {
|
||||
updateState({ editMembers: true });
|
||||
updateState({ editMembers: new Set(state.members), showEditMembers: true });
|
||||
},
|
||||
clearEditMembers: () => {
|
||||
updateState({ editMembers: false });
|
||||
updateState({ showEditMembers: false });
|
||||
},
|
||||
onMember: async (card) => {
|
||||
if (state.members.has(card)) {
|
||||
channel.actions.clearChannelCard(channelId, card);
|
||||
}
|
||||
else {
|
||||
channel.actions.setChannelCard(channelId, card);
|
||||
}
|
||||
setMember: async (id) => {
|
||||
await conversation.actions.setChannelCard(id);
|
||||
},
|
||||
deleteChannel: async () => {
|
||||
await channel.actions.removeChannel(channelId);
|
||||
clearMember: async (id) => {
|
||||
await conversation.actions.clearChannelCard(id);
|
||||
},
|
||||
removeChannel: async () => {
|
||||
await conversation.actions.removeChannel();
|
||||
},
|
||||
leaveChannel: async () => {
|
||||
await card.actions.removeChannel(cardId, channelId);
|
||||
}
|
||||
};
|
||||
|
||||
return { state, actions };
|
||||
|
Loading…
Reference in New Issue
Block a user