mirror of
https://github.com/balzack/databag.git
synced 2025-02-15 21:19:16 +00:00
support adding new channels
This commit is contained in:
parent
0c29f66d1a
commit
ee6a9e4103
@ -30,6 +30,8 @@ const Colors = {
|
|||||||
statsDivider: '#afafaf',
|
statsDivider: '#afafaf',
|
||||||
channel: '#f2f2f2',
|
channel: '#f2f2f2',
|
||||||
card: '#eeeeee',
|
card: '#eeeeee',
|
||||||
|
|
||||||
|
selectHover: '#fafafa',
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Colors;
|
export default Colors;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { BottomNavWrapper } from './BottomNav.styled';
|
import { BottomNavWrapper } from './BottomNav.styled';
|
||||||
import { CommentOutlined, TeamOutlined, UserOutlined } from '@ant-design/icons';
|
import { CommentOutlined, ContactsOutlined, UserOutlined } from '@ant-design/icons';
|
||||||
|
|
||||||
export function BottomNav({ state, actions }) {
|
export function BottomNav({ state, actions }) {
|
||||||
|
|
||||||
@ -82,8 +82,8 @@ export function BottomNav({ state, actions }) {
|
|||||||
{ (state.cards || state.contact) && !state.profile && (
|
{ (state.cards || state.contact) && !state.profile && (
|
||||||
<div class="nav-item">
|
<div class="nav-item">
|
||||||
<div class="nav-active">
|
<div class="nav-active">
|
||||||
<div class="nav-div-left">
|
<div class="nav-div-left bump">
|
||||||
<TeamOutlined />
|
<ContactsOutlined />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -91,8 +91,8 @@ export function BottomNav({ state, actions }) {
|
|||||||
{ ((!state.cards && !state.contact) || state.profile) && (
|
{ ((!state.cards && !state.contact) || state.profile) && (
|
||||||
<div class="nav-item" onClick={() => setCards()}>
|
<div class="nav-item" onClick={() => setCards()}>
|
||||||
<div class="nav-inactive">
|
<div class="nav-inactive">
|
||||||
<div class="nav-div-left">
|
<div class="nav-div-left bump">
|
||||||
<TeamOutlined />
|
<ContactsOutlined />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -22,6 +22,10 @@ export const BottomNavWrapper = styled.div`
|
|||||||
padding-bottom: 8px;
|
padding-bottom: 8px;
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
|
.bump {
|
||||||
|
font-size: 26px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-active {
|
.nav-active {
|
||||||
@ -31,6 +35,10 @@ export const BottomNavWrapper = styled.div`
|
|||||||
padding-top: 8px;
|
padding-top: 8px;
|
||||||
padding-bottom: 8px;
|
padding-bottom: 8px;
|
||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
|
|
||||||
|
.bump {
|
||||||
|
font-size: 30px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-div-right {
|
.nav-div-right {
|
||||||
|
21
net/web/src/session/cardSelect/CardSelect.jsx
Normal file
21
net/web/src/session/cardSelect/CardSelect.jsx
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import { useState } from 'react';
|
||||||
|
import { List } from 'antd';
|
||||||
|
import { CardSelectWrapper } from './CardSelect.styled';
|
||||||
|
import { SelectItem } from './selectItem/SelectItem';
|
||||||
|
import { useCardSelect } from './useCardSelect.hook';
|
||||||
|
|
||||||
|
export function CardSelect({ filter, unknown, select, selected }) {
|
||||||
|
|
||||||
|
const { state, actions } = useCardSelect(filter);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<CardSelectWrapper>
|
||||||
|
<List local={{ emptyText: '' }} itemLayout="horizontal" dataSource={state.cards} gutter="0"
|
||||||
|
renderItem={item => (
|
||||||
|
<SelectItem item={item} select={select} selected={selected} />
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</CardSelectWrapper>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
8
net/web/src/session/cardSelect/CardSelect.styled.js
Normal file
8
net/web/src/session/cardSelect/CardSelect.styled.js
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import styled from 'styled-components';
|
||||||
|
import Colors from 'constants/Colors';
|
||||||
|
|
||||||
|
export const CardSelectWrapper = styled.div`
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
`;
|
34
net/web/src/session/cardSelect/selectItem/SelectItem.jsx
Normal file
34
net/web/src/session/cardSelect/selectItem/SelectItem.jsx
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
import { Switch } from 'antd';
|
||||||
|
import { SelectItemWrapper } from './SelectItem.styled';
|
||||||
|
import { useSelectItem } from './useSelectItem.hook';
|
||||||
|
import { Logo } from 'logo/Logo';
|
||||||
|
|
||||||
|
export function SelectItem({ item, select, selected }) {
|
||||||
|
|
||||||
|
const { state, actions } = useSelectItem(item, selected);
|
||||||
|
const profile = item?.data?.cardProfile;
|
||||||
|
const detail = item?.data?.cardDetail;
|
||||||
|
|
||||||
|
const handle = () => {
|
||||||
|
if (profile?.node) {
|
||||||
|
return profile.handle + '@' + profile.node;
|
||||||
|
}
|
||||||
|
return profile?.handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SelectItemWrapper onClick={() => select(item.id)}>
|
||||||
|
<Logo url={state.logo} width={32} height={32} radius={8} />
|
||||||
|
<div class="details">
|
||||||
|
<div class="name">{ profile?.name }</div>
|
||||||
|
<div class="handle">{ handle() }</div>
|
||||||
|
</div>
|
||||||
|
{ select && (
|
||||||
|
<div class="switch">
|
||||||
|
<Switch checked={state.selected} onChange={() => select(item.id)} size="small" />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</SelectItemWrapper>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,43 @@
|
|||||||
|
import styled from 'styled-components';
|
||||||
|
import Colors from 'constants/Colors';
|
||||||
|
|
||||||
|
export const SelectItemWrapper = styled.div`
|
||||||
|
height: 48px;
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding-left: 8px;
|
||||||
|
padding-right: 8px;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: ${Colors.selectHover};
|
||||||
|
}
|
||||||
|
|
||||||
|
.details {
|
||||||
|
flex-grow: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
padding-left: 16px;
|
||||||
|
justify-content: center;
|
||||||
|
min-width: 0;
|
||||||
|
|
||||||
|
.name {
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
font-size: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.handle {
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.switch {
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
`
|
@ -0,0 +1,31 @@
|
|||||||
|
import { useContext, useState, useEffect } from 'react';
|
||||||
|
import { CardContext } from 'context/CardContext';
|
||||||
|
|
||||||
|
export function useSelectItem(item, selected) {
|
||||||
|
|
||||||
|
const [state, setState] = useState({
|
||||||
|
logo: null,
|
||||||
|
selected: false,
|
||||||
|
busy: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
const card = useContext(CardContext);
|
||||||
|
|
||||||
|
const updateState = (value) => {
|
||||||
|
setState((s) => ({ ...s, ...value }));
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
updateState({ selected: selected.has(item.id) });
|
||||||
|
}, [selected]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
updateState({ logo: card.actions.getImageUrl(item.id) });
|
||||||
|
}, [card, item]);
|
||||||
|
|
||||||
|
const actions = {
|
||||||
|
};
|
||||||
|
|
||||||
|
return { state, actions };
|
||||||
|
}
|
||||||
|
|
27
net/web/src/session/cardSelect/useCardSelect.hook.js
Normal file
27
net/web/src/session/cardSelect/useCardSelect.hook.js
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import { useContext, useState, useEffect } from 'react';
|
||||||
|
import { CardContext } from 'context/CardContext';
|
||||||
|
|
||||||
|
export function useCardSelect(filter) {
|
||||||
|
|
||||||
|
const [state, setState] = useState({
|
||||||
|
cards: [],
|
||||||
|
});
|
||||||
|
|
||||||
|
const card = useContext(CardContext);
|
||||||
|
|
||||||
|
const updateState = (value) => {
|
||||||
|
setState((s) => ({ ...s, ...value }));
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
let contacts = Array.from(card.state.cards.values());
|
||||||
|
let filtered = contacts.filter(filter);
|
||||||
|
updateState({ cards: filtered });
|
||||||
|
}, [card]);
|
||||||
|
|
||||||
|
const actions = {
|
||||||
|
};
|
||||||
|
|
||||||
|
return { state, actions };
|
||||||
|
}
|
||||||
|
|
@ -1,15 +1,37 @@
|
|||||||
import { Input, List } from 'antd';
|
import { Modal, Input, List, Button } from 'antd';
|
||||||
import { ChannelsWrapper } from './Channels.styled';
|
import { ChannelsWrapper, AddFooter } from './Channels.styled';
|
||||||
import { CommentOutlined, SearchOutlined } from '@ant-design/icons';
|
import { CommentOutlined, SearchOutlined } from '@ant-design/icons';
|
||||||
import { useChannels } from './useChannels.hook';
|
import { useChannels } from './useChannels.hook';
|
||||||
import { ChannelItem } from './channelItem/ChannelItem';
|
import { ChannelItem } from './channelItem/ChannelItem';
|
||||||
|
import { AddChannel } from './addChannel/AddChannel';
|
||||||
|
|
||||||
export function Channels({ open }) {
|
export function Channels({ open }) {
|
||||||
|
|
||||||
const { state, actions } = useChannels();
|
const { state, actions } = useChannels();
|
||||||
|
|
||||||
|
const addChannel = async () => {
|
||||||
|
try {
|
||||||
|
await actions.addChannel();
|
||||||
|
actions.clearShowAdd();
|
||||||
|
}
|
||||||
|
catch(err) {
|
||||||
|
console.log(err);
|
||||||
|
Modal.error({
|
||||||
|
title: 'Failed to Create Channel',
|
||||||
|
content: 'Please try again.',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const addFooter = (
|
||||||
|
<AddFooter>
|
||||||
|
<Button key="back" onClick={actions.clearShowAdd}>Cancel</Button>
|
||||||
|
<Button key="save" type="primary" loading={state.busy} onClick={addChannel}>Save</Button>
|
||||||
|
</AddFooter>
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ChannelsWrapper onClick={open} >
|
<ChannelsWrapper>
|
||||||
<div class="search">
|
<div class="search">
|
||||||
<div class="filter">
|
<div class="filter">
|
||||||
<Input bordered={false} allowClear={true} placeholder="Channels" prefix={<SearchOutlined />}
|
<Input bordered={false} allowClear={true} placeholder="Channels" prefix={<SearchOutlined />}
|
||||||
@ -17,7 +39,7 @@ export function Channels({ open }) {
|
|||||||
</div>
|
</div>
|
||||||
{ state.display === 'small' && (
|
{ state.display === 'small' && (
|
||||||
<div class="inline">
|
<div class="inline">
|
||||||
<div class="add">
|
<div class="add" onClick={actions.setShowAdd}>
|
||||||
<CommentOutlined />
|
<CommentOutlined />
|
||||||
<div class="label">New</div>
|
<div class="label">New</div>
|
||||||
</div>
|
</div>
|
||||||
@ -27,18 +49,22 @@ export function Channels({ open }) {
|
|||||||
<div class="view">
|
<div class="view">
|
||||||
<List local={{ emptyText: '' }} itemLayout="horizontal" dataSource={state.channels} gutter="0"
|
<List local={{ emptyText: '' }} itemLayout="horizontal" dataSource={state.channels} gutter="0"
|
||||||
renderItem={item => (
|
renderItem={item => (
|
||||||
<ChannelItem item={item} />
|
<ChannelItem item={item} openChannel={open} />
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{ state.display !== 'small' && (
|
{ state.display !== 'small' && (
|
||||||
<div class="bar">
|
<div class="bar">
|
||||||
<div class="add">
|
<div class="add" onClick={actions.setShowAdd}>
|
||||||
<CommentOutlined />
|
<CommentOutlined />
|
||||||
<div class="label">New Channel</div>
|
<div class="label">New Channel</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
<Modal title="New Channel" centered visible={state.showAdd} footer={addFooter}
|
||||||
|
onCancel={actions.clearShowAdd}>
|
||||||
|
<AddChannel state={state} actions={actions} />
|
||||||
|
</Modal>
|
||||||
</ChannelsWrapper>
|
</ChannelsWrapper>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -77,3 +77,12 @@ export const ChannelsWrapper = styled.div`
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
export const AddFooter = styled.div`
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: flex-end;
|
||||||
|
align-items: center;
|
||||||
|
`
|
||||||
|
|
||||||
|
29
net/web/src/session/channels/addChannel/AddChannel.jsx
Normal file
29
net/web/src/session/channels/addChannel/AddChannel.jsx
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import { useState } from 'react';
|
||||||
|
import { Input, Select } from 'antd';
|
||||||
|
import { AddChannelWrapper } from './AddChannel.styled';
|
||||||
|
import { CardSelect } from '../../cardSelect/CardSelect';
|
||||||
|
|
||||||
|
export function AddChannel({ state, actions }) {
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AddChannelWrapper>
|
||||||
|
<Input placeholder="Subject (optional)" spellCheck="false" autocapitalize="word"
|
||||||
|
value={state.subject} onChange={(e) => actions.setSubject(e.target.value)} />
|
||||||
|
<div class="members">
|
||||||
|
<span>Channel Members: </span>
|
||||||
|
{ state.members.size !== 0 && (
|
||||||
|
<span>{ state.members.size }</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div class="list">
|
||||||
|
<CardSelect
|
||||||
|
select={actions.onMember}
|
||||||
|
selected={state.members}
|
||||||
|
filter={(card) => card?.data?.cardDetail?.status === 'connected'}
|
||||||
|
unknown={0}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</AddChannelWrapper>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
26
net/web/src/session/channels/addChannel/AddChannel.styled.js
Normal file
26
net/web/src/session/channels/addChannel/AddChannel.styled.js
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import styled from 'styled-components';
|
||||||
|
import Colors from 'constants/Colors';
|
||||||
|
|
||||||
|
export const AddChannelWrapper = styled.div`
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
.members {
|
||||||
|
margin-top: 16px;
|
||||||
|
width: 100%;
|
||||||
|
padding-left: 8px;
|
||||||
|
color: ${Colors.grey};
|
||||||
|
}
|
||||||
|
|
||||||
|
.list {
|
||||||
|
width: 100%;
|
||||||
|
min-height: 100px;
|
||||||
|
max-height: 200px;
|
||||||
|
overflow: scroll;
|
||||||
|
border: 1px solid ${Colors.divider};
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
|
@ -0,0 +1,28 @@
|
|||||||
|
import { MemberOptionWrapper } from './MemberOption.styled';
|
||||||
|
import { useMemberOption } from './useMemberOption.hook';
|
||||||
|
import { Logo } from 'logo/Logo';
|
||||||
|
|
||||||
|
export function MemberOption({ item, close }) {
|
||||||
|
|
||||||
|
const { state, actions } = useMemberOption(item);
|
||||||
|
const profile = item?.data?.cardProfile;
|
||||||
|
const detail = item?.data?.cardDetail;
|
||||||
|
|
||||||
|
const handle = () => {
|
||||||
|
if (profile?.node) {
|
||||||
|
return profile.handle + '@' + profile.node;
|
||||||
|
}
|
||||||
|
return profile?.handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<MemberOptionWrapper onClick={close}>
|
||||||
|
<Logo url={state.logo} width={32} height={32} radius={8} />
|
||||||
|
<div class="details">
|
||||||
|
<div class="name">{ profile?.name }</div>
|
||||||
|
<div class="handle">{ handle() }</div>
|
||||||
|
</div>
|
||||||
|
</MemberOptionWrapper>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,31 @@
|
|||||||
|
import styled from 'styled-components';
|
||||||
|
|
||||||
|
export const MemberOptionWrapper = styled.div`
|
||||||
|
height: 48px;
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.details {
|
||||||
|
flex-grow: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
padding-left: 16px;
|
||||||
|
justify-content: center;
|
||||||
|
min-width: 0;
|
||||||
|
|
||||||
|
.name {
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
font-size: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.handle {
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
@ -0,0 +1,25 @@
|
|||||||
|
import { useContext, useState, useEffect } from 'react';
|
||||||
|
import { CardContext } from 'context/CardContext';
|
||||||
|
|
||||||
|
export function useMemberOption(item) {
|
||||||
|
|
||||||
|
const [state, setState] = useState({
|
||||||
|
logo: null,
|
||||||
|
});
|
||||||
|
|
||||||
|
const card = useContext(CardContext);
|
||||||
|
|
||||||
|
const updateState = (value) => {
|
||||||
|
setState((s) => ({ ...s, ...value }));
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
updateState({ logo: card.actions.getImageUrl(item.id) });
|
||||||
|
}, [card, item]);
|
||||||
|
|
||||||
|
const actions = {
|
||||||
|
};
|
||||||
|
|
||||||
|
return { state, actions };
|
||||||
|
}
|
||||||
|
|
@ -2,10 +2,10 @@ import { ChannelItemWrapper } from './ChannelItem.styled';
|
|||||||
import { Logo } from 'logo/Logo';
|
import { Logo } from 'logo/Logo';
|
||||||
import { AppstoreFilled, SolutionOutlined } from '@ant-design/icons';
|
import { AppstoreFilled, SolutionOutlined } from '@ant-design/icons';
|
||||||
|
|
||||||
export function ChannelItem({ item }) {
|
export function ChannelItem({ item, openChannel }) {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ChannelItemWrapper>
|
<ChannelItemWrapper onClick={openChannel}>
|
||||||
{ item.contacts.length === 0 && (
|
{ item.contacts.length === 0 && (
|
||||||
<div class="item">
|
<div class="item">
|
||||||
<div class="logo">
|
<div class="logo">
|
||||||
|
@ -12,8 +12,11 @@ export function useChannels() {
|
|||||||
const [state, setState] = useState({
|
const [state, setState] = useState({
|
||||||
display: null,
|
display: null,
|
||||||
channels: [],
|
channels: [],
|
||||||
busy: false }
|
showAdd: false,
|
||||||
);
|
busy: false,
|
||||||
|
members: new Set(),
|
||||||
|
subject: null,
|
||||||
|
});
|
||||||
|
|
||||||
const card = useContext(CardContext);
|
const card = useContext(CardContext);
|
||||||
const channel = useContext(ChannelContext);
|
const channel = useContext(ChannelContext);
|
||||||
@ -26,9 +29,46 @@ export function useChannels() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const actions = {
|
const actions = {
|
||||||
|
addChannel: async () => {
|
||||||
|
if (!state.busy) {
|
||||||
|
try {
|
||||||
|
updateState({ busy: true });
|
||||||
|
let cards = Array.from(state.members.values());
|
||||||
|
await channel.actions.addChannel(cards, state.subject, null);
|
||||||
|
updateState({ busy: false });
|
||||||
|
}
|
||||||
|
catch(err) {
|
||||||
|
console.log(err);
|
||||||
|
updateState({ busy: false });
|
||||||
|
throw new Error("failed to create new channel");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new Error("operation in progress");
|
||||||
|
}
|
||||||
|
},
|
||||||
onFilter: (value) => {
|
onFilter: (value) => {
|
||||||
setFilter(value.toUpperCase());
|
setFilter(value.toUpperCase());
|
||||||
},
|
},
|
||||||
|
setShowAdd: () => {
|
||||||
|
updateState({ showAdd: true });
|
||||||
|
},
|
||||||
|
clearShowAdd: () => {
|
||||||
|
updateState({ showAdd: false, members: new Set(), subject: null });
|
||||||
|
},
|
||||||
|
onMember: (string) => {
|
||||||
|
let members = new Set(state.members);
|
||||||
|
if (members.has(string)) {
|
||||||
|
members.delete(string);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
members.add(string);
|
||||||
|
}
|
||||||
|
updateState({ members });
|
||||||
|
},
|
||||||
|
setSubject: (subject) => {
|
||||||
|
updateState({ subject });
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const setUpdated = (chan) => {
|
const setUpdated = (chan) => {
|
||||||
|
@ -6,11 +6,11 @@ export function ProfileDetails({ state, actions }) {
|
|||||||
<ProfileDetailsWrapper>
|
<ProfileDetailsWrapper>
|
||||||
<div class="info">
|
<div class="info">
|
||||||
<Input placeholder="Name" spellCheck="false" onChange={(e) => actions.setEditName(e.target.value)}
|
<Input placeholder="Name" spellCheck="false" onChange={(e) => actions.setEditName(e.target.value)}
|
||||||
defaultValue={state.editName} autocapitalizate="word" />
|
defaultValue={state.editName} autocapitalize="word" />
|
||||||
</div>
|
</div>
|
||||||
<div class="info">
|
<div class="info">
|
||||||
<Input placeholder="Location" spellCheck="false" onChange={(e) => actions.setEditLocation(e.target.value)}
|
<Input placeholder="Location" spellCheck="false" onChange={(e) => actions.setEditLocation(e.target.value)}
|
||||||
defaultValue={state.editLocation} autocapitalizate="word" />
|
defaultValue={state.editLocation} autocapitalize="word" />
|
||||||
</div>
|
</div>
|
||||||
<div class="info">
|
<div class="info">
|
||||||
<Input.TextArea placeholder="Description" onChange={(e) => actions.setEditDescription(e.target.value)}
|
<Input.TextArea placeholder="Description" onChange={(e) => actions.setEditDescription(e.target.value)}
|
||||||
|
Loading…
Reference in New Issue
Block a user