From 2db3178510e4d02596c9f74aeadf3b0bf1feaf0e Mon Sep 17 00:00:00 2001 From: Roland Osborne Date: Sat, 20 Aug 2022 23:10:22 -0700 Subject: [PATCH] support editing channel details --- net/web/src/logo/Logo.jsx | 3 + net/web/src/session/cardSelect/CardSelect.jsx | 9 ++ .../session/cardSelect/CardSelect.styled.js | 13 +++ net/web/src/session/channels/Channels.jsx | 2 - .../channels/addChannel/AddChannel.jsx | 3 +- net/web/src/session/details/Details.jsx | 108 ++++++++++++++++-- net/web/src/session/details/Details.styled.js | 8 ++ .../details/editMembers/EditMembers.jsx | 18 +++ .../details/editMembers/EditMembers.styled.js | 18 +++ .../details/editSubject/EditSubject.jsx | 13 +++ .../details/editSubject/EditSubject.styled.js | 8 ++ .../src/session/details/useDetails.hook.js | 76 +++++++++++- 12 files changed, 258 insertions(+), 21 deletions(-) create mode 100644 net/web/src/session/details/editMembers/EditMembers.jsx create mode 100644 net/web/src/session/details/editMembers/EditMembers.styled.js create mode 100644 net/web/src/session/details/editSubject/EditSubject.jsx create mode 100644 net/web/src/session/details/editSubject/EditSubject.styled.js diff --git a/net/web/src/logo/Logo.jsx b/net/web/src/logo/Logo.jsx index bb4c9b64..dde73aea 100644 --- a/net/web/src/logo/Logo.jsx +++ b/net/web/src/logo/Logo.jsx @@ -9,6 +9,9 @@ export function Logo({ url, width, height, radius, img }) { { img === 'team' && ( direct logo )} + { img === 'avatar' && ( + anonymous logo + )} { img === 'appstore' && ( group logo )} diff --git a/net/web/src/session/cardSelect/CardSelect.jsx b/net/web/src/session/cardSelect/CardSelect.jsx index 9ff6719c..be17e333 100644 --- a/net/web/src/session/cardSelect/CardSelect.jsx +++ b/net/web/src/session/cardSelect/CardSelect.jsx @@ -3,6 +3,7 @@ import { List } from 'antd'; import { CardSelectWrapper } from './CardSelect.styled'; import { SelectItem } from './selectItem/SelectItem'; import { useCardSelect } from './useCardSelect.hook'; +import { Logo } from 'logo/Logo'; export function CardSelect({ filter, unknown, select, selected, markup }) { @@ -15,6 +16,14 @@ export function CardSelect({ filter, unknown, select, selected, markup }) { )} /> + { unknown > 0 && ( +
+ +
+ + { unknown } unknown +
+
+ )} ); } diff --git a/net/web/src/session/cardSelect/CardSelect.styled.js b/net/web/src/session/cardSelect/CardSelect.styled.js index 4b11f14b..77ebb3c8 100644 --- a/net/web/src/session/cardSelect/CardSelect.styled.js +++ b/net/web/src/session/cardSelect/CardSelect.styled.js @@ -5,4 +5,17 @@ export const CardSelectWrapper = styled.div` display: flex; flex-direction: column; justify-content: center; + + .unknown { + height: 48px; + width: 100%; + padding-left: 8px; + padding-right: 8px; + display: flex; + align-items: center; + + .message { + padding-left: 16px; + } + } `; diff --git a/net/web/src/session/channels/Channels.jsx b/net/web/src/session/channels/Channels.jsx index 0011cc01..cb629ef5 100644 --- a/net/web/src/session/channels/Channels.jsx +++ b/net/web/src/session/channels/Channels.jsx @@ -13,11 +13,9 @@ export function Channels({ open }) { try { const id = await actions.addChannel(); actions.clearShowAdd(); - console.log(id); open(id); } catch(err) { - console.log(err); Modal.error({ title: 'Failed to Create Channel', content: 'Please try again.', diff --git a/net/web/src/session/channels/addChannel/AddChannel.jsx b/net/web/src/session/channels/addChannel/AddChannel.jsx index c6092404..b38f2036 100644 --- a/net/web/src/session/channels/addChannel/AddChannel.jsx +++ b/net/web/src/session/channels/addChannel/AddChannel.jsx @@ -1,5 +1,4 @@ -import { useState } from 'react'; -import { Input, Select } from 'antd'; +import { Input } from 'antd'; import { AddChannelWrapper } from './AddChannel.styled'; import { CardSelect } from '../../cardSelect/CardSelect'; diff --git a/net/web/src/session/details/Details.jsx b/net/web/src/session/details/Details.jsx index 1b7e45b2..c3433838 100644 --- a/net/web/src/session/details/Details.jsx +++ b/net/web/src/session/details/Details.jsx @@ -1,16 +1,94 @@ -import { Space } from 'antd'; -import { DetailsWrapper } from './Details.styled'; +import { Space, Button, Modal } from 'antd'; +import { DetailsWrapper, ModalFooter } from './Details.styled'; import { DoubleRightOutlined } from '@ant-design/icons'; import { useDetails } from './useDetails.hook'; import { Logo } from 'logo/Logo'; -import { EditOutlined } from '@ant-design/icons'; +import { EditOutlined, ExclamationCircleOutlined } from '@ant-design/icons'; import { CardSelect } from '../cardSelect/CardSelect'; +import { EditSubject } from './editSubject/EditSubject'; +import { EditMembers } from './editMembers/EditMembers'; export function Details({ cardId, channelId, closeDetails, closeConversation, openContact }) { const { state, actions } = useDetails(cardId, channelId); -console.log(state.contacts); + const deleteChannel = async () => { + Modal.confirm({ + title: 'Are you sure you want to delete the channel?', + icon: , + okText: "Yes, Delete", + cancelText: "No, Cancel", + onOk() { + applyDeleteChannel(); + }, + onCancel() {}, + }); + } + + const applyDeleteChannel = async () => { + try { + await actions.deleteChannel(); + closeConversation(); + } + catch(err) { + Modal.error({ + title: 'Failed to Delete Channel', + content: 'Please try again.', + }); + } + } + + const leaveChannel = async () => { + Modal.confirm({ + title: 'Are you sure you want to leave the channel?', + icon: , + okText: "Yes, Leave", + cancelText: "No, Cancel", + onOk() { + applyLeaveChannel(); + }, + onCancel() {}, + }); + } + + const applyLeaveChannel = async () => { + try { + await actions.leaveChannel(); + closeConversation(); + } + catch(err) { + Modal.error({ + title: 'Failed to Leave Channel', + content: 'Please try again.', + }); + } + } + + const saveSubject = async () => { + try { + const id = await actions.setSubject(); + actions.clearEditSubject(); + } + catch(err) { + Modal.error({ + title: 'Failed to Update Subject', + content: 'Please try again.', + }); + } + }; + + const editSubjectFooter = ( + + + + + ); + + const editMembersFooter = ( + + + + ); return ( @@ -20,14 +98,14 @@ console.log(state.contacts); -
+
{ state.host && ( -
+
{ state.subject }
@@ -47,27 +125,33 @@ console.log(state.contacts);
{ state.host && ( -
Delete Channel
+
Delete Channel
)} { state.host && ( -
Edit Membership
+
Edit Membership
)} { !state.host && ( -
Leave Channel
+
Leave Channel
)}
Members
{ - console.log("CHECK: ", item.id, state.contacts); if(state.contacts.includes(item.id)) { - console.log("YES"); return true; } return false; - }} unknown={0} + }} unknown={state.unknown} markup={cardId} />
+ + + + + + ); } diff --git a/net/web/src/session/details/Details.styled.js b/net/web/src/session/details/Details.styled.js index 5824089a..a0cfc9bc 100644 --- a/net/web/src/session/details/Details.styled.js +++ b/net/web/src/session/details/Details.styled.js @@ -112,3 +112,11 @@ export const DetailsWrapper = styled.div` } } ` + +export const ModalFooter = styled.div` + width: 100%; + display: flex; + flex-direction: row; + justify-content: flex-end; + align-items: center; +` diff --git a/net/web/src/session/details/editMembers/EditMembers.jsx b/net/web/src/session/details/editMembers/EditMembers.jsx new file mode 100644 index 00000000..d552d9b1 --- /dev/null +++ b/net/web/src/session/details/editMembers/EditMembers.jsx @@ -0,0 +1,18 @@ +import { EditMembersWrapper } from './EditMembers.styled'; +import { CardSelect } from '../../cardSelect/CardSelect'; + +export function EditMembers({ state, actions }) { + + return ( + +
+ card?.data?.cardDetail?.status === 'connected'} + /> +
+
+ ); +} + diff --git a/net/web/src/session/details/editMembers/EditMembers.styled.js b/net/web/src/session/details/editMembers/EditMembers.styled.js new file mode 100644 index 00000000..c265ab80 --- /dev/null +++ b/net/web/src/session/details/editMembers/EditMembers.styled.js @@ -0,0 +1,18 @@ +import styled from 'styled-components'; +import Colors from 'constants/Colors'; + +export const EditMembersWrapper = styled.div` + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + + .list { + width: 100%; + min-height: 100px; + max-height: 200px; + overflow: scroll; + border: 1px solid ${Colors.divider}; + } + +` diff --git a/net/web/src/session/details/editSubject/EditSubject.jsx b/net/web/src/session/details/editSubject/EditSubject.jsx new file mode 100644 index 00000000..3ad34ac7 --- /dev/null +++ b/net/web/src/session/details/editSubject/EditSubject.jsx @@ -0,0 +1,13 @@ +import { Input } from 'antd'; +import { EditSubjectWrapper } from './EditSubject.styled'; + +export function EditSubject({ state, actions }) { + + return ( + + actions.setSubjectUpdate(e.target.value)} /> + + ); +} + diff --git a/net/web/src/session/details/editSubject/EditSubject.styled.js b/net/web/src/session/details/editSubject/EditSubject.styled.js new file mode 100644 index 00000000..f0f56891 --- /dev/null +++ b/net/web/src/session/details/editSubject/EditSubject.styled.js @@ -0,0 +1,8 @@ +import styled from 'styled-components'; + +export const EditSubjectWrapper = styled.div` + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; +` diff --git a/net/web/src/session/details/useDetails.hook.js b/net/web/src/session/details/useDetails.hook.js index c91e9ff3..34e04568 100644 --- a/net/web/src/session/details/useDetails.hook.js +++ b/net/web/src/session/details/useDetails.hook.js @@ -9,10 +9,15 @@ export function useDetails(cardId, channelId) { img: null, subject: null, server: null, - startedDate: null, - startedTime: null, + started: null, host: null, contacts: [], + members: new Set(), + editSubject: false, + editMembers: false, + busy: false, + subjectUpdate: null, + unknown: 0, }); const card = useContext(CardContext); @@ -23,7 +28,7 @@ export function useDetails(cardId, channelId) { } useEffect(() => { - let img, subject, host, started; + let img, subject, host, started, contacts let chan; if (cardId) { const cardChan = card.state.cards.get(cardId); @@ -67,11 +72,72 @@ export function useDetails(cardId, channelId) { host = true; } } - updateState({ img, subject, host, started, - contacts: chan.contacts.map((contact) => contact?.id) }); + + if (chan?.contacts ) { + contacts = chan.contacts.map((contact) => contact?.id); + } + else { + contacts = []; + } + + let members = new Set(contacts); + let unknown = 0; + contacts.forEach(id => { + if (id == null) { + unknown++; + } + }); + + updateState({ img, subject, host, started, contacts, members, unknown }); }, [cardId, channelId, card, channel]); const actions = { + setEditSubject: () => { + updateState({ editSubject: true }); + }, + clearEditSubject: () => { + updateState({ editSubject: false }); + }, + setSubjectUpdate: (subjectUpdate) => { + updateState({ subjectUpdate }); + }, + setSubject: async () => { + if (!state.busy) { + try { + updateState({ busy: true }); + channel.actions.setChannelSubject(channelId, state.subjectUpdate); + updateState({ busy: false }); + } + catch(err) { + console.log(err); + updateState({ busy: false }); + throw new Error("set channel subject failed"); + } + } + else { + throw new Error('operation in progress'); + } + }, + setEditMembers: () => { + updateState({ editMembers: true }); + }, + clearEditMembers: () => { + updateState({ editMembers: false }); + }, + onMember: async (card) => { + if (state.members.has(card)) { + channel.actions.clearChannelCard(channelId, card); + } + else { + channel.actions.setChannelCard(channelId, card); + } + }, + deleteChannel: async () => { + await channel.actions.removeChannel(channelId); + }, + leaveChannel: async () => { + await card.actions.removeChannel(cardId, channelId); + } }; return { state, actions };