mirror of
https://github.com/balzack/databag.git
synced 2025-02-14 12:39:17 +00:00
support editing channel details
This commit is contained in:
parent
1317c6f6d7
commit
2db3178510
@ -9,6 +9,9 @@ export function Logo({ url, width, height, radius, img }) {
|
||||
{ img === 'team' && (
|
||||
<img src={team} alt="direct logo" width={width} height={height} />
|
||||
)}
|
||||
{ img === 'avatar' && (
|
||||
<img src={avatar} alt="anonymous logo" width={width} height={height} />
|
||||
)}
|
||||
{ img === 'appstore' && (
|
||||
<img src={appstore} alt="group logo" width={width} height={height} />
|
||||
)}
|
||||
|
@ -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 }) {
|
||||
<SelectItem item={item} select={select} selected={selected} markup={markup} />
|
||||
)}
|
||||
/>
|
||||
{ unknown > 0 && (
|
||||
<div class="unknown">
|
||||
<Logo img="avatar" width={32} height={32} radius={8} />
|
||||
<div class="message">
|
||||
<span>+ { unknown } unknown</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</CardSelectWrapper>
|
||||
);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
@ -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.',
|
||||
|
@ -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';
|
||||
|
||||
|
@ -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: <ExclamationCircleOutlined />,
|
||||
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: <ExclamationCircleOutlined />,
|
||||
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 = (
|
||||
<ModalFooter>
|
||||
<Button key="back" onClick={actions.clearEditSubject}>Cancel</Button>
|
||||
<Button key="save" type="primary" onClick={saveSubject} loading={state.busy}>Save</Button>
|
||||
</ModalFooter>
|
||||
);
|
||||
|
||||
const editMembersFooter = (
|
||||
<ModalFooter>
|
||||
<Button key="back" onClick={actions.clearEditMembers}>Done</Button>
|
||||
</ModalFooter>
|
||||
);
|
||||
|
||||
return (
|
||||
<DetailsWrapper>
|
||||
@ -20,14 +98,14 @@ console.log(state.contacts);
|
||||
<DoubleRightOutlined />
|
||||
</div>
|
||||
</div>
|
||||
<div class="content" onClick={closeDetails}>
|
||||
<div class="content">
|
||||
<div class="description">
|
||||
<div class="logo">
|
||||
<Logo width={72} height={72} radius={4} img={state.img} />
|
||||
</div>
|
||||
<div class="stats">
|
||||
{ state.host && (
|
||||
<div class="subject edit">
|
||||
<div class="subject edit" onClick={actions.setEditSubject}>
|
||||
<Space>
|
||||
<div>{ state.subject }</div>
|
||||
<EditOutlined />
|
||||
@ -47,27 +125,33 @@ console.log(state.contacts);
|
||||
</div>
|
||||
</div>
|
||||
{ state.host && (
|
||||
<div class="button">Delete Channel</div>
|
||||
<div class="button" onClick={deleteChannel}>Delete Channel</div>
|
||||
)}
|
||||
{ state.host && (
|
||||
<div class="button">Edit Membership</div>
|
||||
<div class="button" onClick={actions.setEditMembers}>Edit Membership</div>
|
||||
)}
|
||||
{ !state.host && (
|
||||
<div class="button">Leave Channel</div>
|
||||
<div class="button" onClick={leaveChannel}>Leave Channel</div>
|
||||
)}
|
||||
<div class="label">Members</div>
|
||||
<div class="members">
|
||||
<CardSelect filter={(item) => {
|
||||
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} />
|
||||
</div>
|
||||
</div>
|
||||
<Modal title="Edit Subject" centered visible={state.editSubject} footer={editSubjectFooter}
|
||||
onCancel={actions.clearEditSubject}>
|
||||
<EditSubject state={state} actions={actions} />
|
||||
</Modal>
|
||||
<Modal title="Edit Members" centered visible={state.editMembers} footer={editMembersFooter}
|
||||
onCancel={actions.clearEditMembers}>
|
||||
<EditMembers state={state} actions={actions} />
|
||||
</Modal>
|
||||
</DetailsWrapper>
|
||||
);
|
||||
}
|
||||
|
@ -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;
|
||||
`
|
||||
|
18
net/web/src/session/details/editMembers/EditMembers.jsx
Normal file
18
net/web/src/session/details/editMembers/EditMembers.jsx
Normal file
@ -0,0 +1,18 @@
|
||||
import { EditMembersWrapper } from './EditMembers.styled';
|
||||
import { CardSelect } from '../../cardSelect/CardSelect';
|
||||
|
||||
export function EditMembers({ state, actions }) {
|
||||
|
||||
return (
|
||||
<EditMembersWrapper>
|
||||
<div class="list">
|
||||
<CardSelect
|
||||
select={actions.onMember}
|
||||
selected={state.members}
|
||||
filter={(card) => card?.data?.cardDetail?.status === 'connected'}
|
||||
/>
|
||||
</div>
|
||||
</EditMembersWrapper>
|
||||
);
|
||||
}
|
||||
|
@ -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};
|
||||
}
|
||||
|
||||
`
|
13
net/web/src/session/details/editSubject/EditSubject.jsx
Normal file
13
net/web/src/session/details/editSubject/EditSubject.jsx
Normal file
@ -0,0 +1,13 @@
|
||||
import { Input } from 'antd';
|
||||
import { EditSubjectWrapper } from './EditSubject.styled';
|
||||
|
||||
export function EditSubject({ state, actions }) {
|
||||
|
||||
return (
|
||||
<EditSubjectWrapper>
|
||||
<Input placeholder="Subject (optional)" spellCheck="false" autocapitalize="word"
|
||||
defaultValue={state.subject} onChange={(e) => actions.setSubjectUpdate(e.target.value)} />
|
||||
</EditSubjectWrapper>
|
||||
);
|
||||
}
|
||||
|
@ -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;
|
||||
`
|
@ -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 };
|
||||
|
Loading…
Reference in New Issue
Block a user