modal for new topic in webapp

This commit is contained in:
balzack 2024-11-13 13:02:09 -08:00
parent fef6c7b1dd
commit aa49b1ef19
5 changed files with 124 additions and 14 deletions

View File

@ -26,11 +26,12 @@ export function Content({select}: {select: (focus: Focus) => void}) {
action: () => setAlert(false),
},
});
const cards = (state.sealSet && sealed) ? state.sealable : state.connected;
const addTopic = async () => {
setAdding(true);
try {
await actions.addTopic(sealed, subject, members);
await actions.addTopic(sealed, subject, members.filter(id => Boolean(cards.find(card => card.cardId === id))));
setAdd(false);
setSubject('');
setMembers([]);
@ -43,8 +44,6 @@ export function Content({select}: {select: (focus: Focus) => void}) {
setAdding(false);
};
const cards = sealed ? state.sealable : state.connected;
return (
<View style={styles.container}>
<SafeAreaView style={styles.header}>

View File

@ -25,12 +25,12 @@ export function useContent() {
layout: null,
guid: '',
connected: [] as Card[],
connectedAndSealable: [] as Cards[],
sealable: [] as Cards[],
sorted: [] as Channel[],
filtered: [] as ChannelParams[],
filter: '',
topic: '',
sealable: false,
sealSet: false,
});
const compare = (a: Card, b: Card) => {

View File

@ -82,9 +82,52 @@
flex-direction: column;
gap: 16px;
.members {
padding-left: 4px;
font-size: 12px;
color: var(--mantine-color-text-6);
}
.addMembers {
width: 100%;
height: 200px;
min-height: 128px;
max-height: 256px;
background: var(--mantine-color-surface-0);
overflow: scroll;
border: 1px solid var(--mantine-color-text-8);
border-radius: 2px;
.noContacts {
display: flex;
width: 100%;
height: 128px;
align-items: center;
justify-content: center;
.noContactsLabel {
color: var(--mantine-color-text-6);
}
}
.card {
width: 100%;
height: 48px;
padding-top: 8px;
padding-bottom: 8px;
padding-right: 16px;
padding-left: 16px;
border-bottom: 1px solid var(--mantine-color-text-8);
}
}
.addControls {
display: flex;
flex-direction: row;
align-items: center;
gap: 16px;
.addSealed {
flex-grow: 1;
}
}
}

View File

@ -1,18 +1,65 @@
import React, {useState} from 'react';
import { useContent } from './useContent.hook'
import { Modal, TextInput, Button } from '@mantine/core'
import { Modal, Text, Switch, 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'
import { Card } from '../card/Card';
import { modals } from '@mantine/modals'
export function Content({ select }: { select: (focus: Focus) => void }) {
const { state, actions } = useContent()
const [add, setAdd] = useState(false);
const [adding, setAdding] = useState(false);
const [sealed, setSealed] = useState(false);
const [subject, setSubject] = useState('');
const [added, setAdded] = useState([]);
const cards = (state.sealSet && sealed) ? state.sealable : state.connected;
const addTopic = async () => {
setAdding(true);
try {
await actions.addTopic(sealed, subject, added.filter(id => Boolean(cards.find(card => card.cardId === id))))
setAdd(false);
setSealed(false);
setAdded([]);
setSubject('');
}
catch (err) {
console.log(err);
showError();
}
setAdding(false);
}
const showError = () => {
modals.openConfirmModal({
title: state.strings.operationFailed,
withCloseButton: true,
overlayProps: {
backgroundOpacity: 0.55,
blur: 3,
},
children: <Text>{state.strings.tryAgain}</Text>,
cancelProps: { display: 'none' },
confirmProps: { display: 'none' },
})
}
const contacts = cards.map((card, idx) => {
const enable = (<Switch key="add" className={classes.addMember} size="sm" checked={Boolean(added.find(id => id === card.cardId))} onChange={(ev) => {
if (ev.currentTarget.checked) {
setAdded([ ...added, card.cardId ]);
} else {
setAdded(added.filter(id => id !== card.cardId))
}
}} />)
return (
<Card key={idx} className={classes.card} imageUrl={card.imageUrl} name={card.name} handle={card.handle} node={card.node} placeholder={state.strings.name} actions={[enable]} />
)
});
const channels = state.filtered.map((channel, idx) => {
return (
<Channel
@ -59,7 +106,7 @@ export function Content({ select }: { select: (focus: Focus) => void }) {
</Button>
</div>
)}
<Modal title={state.strings.newTopic} opened={add} onClose={() => setAdd(false)} overlayProps={{ backgroundOpacity: 0.55, blur: 3 }} centered>
<Modal title={state.strings.newTopic} opened={add} onClose={() => setAdd(false)} overlayProps={{ backgroundOpacity: 0.65, blur: 3 }} centered>
<div className={classes.addContainer}>
<TextInput
className={classes.input}
@ -67,11 +114,32 @@ export function Content({ select }: { select: (focus: Focus) => void }) {
leftSectionPointerEvents="none"
leftSection={<IconLabel size={20} />}
placeholder={state.strings.subjectOptional}
value={state.filter}
onChange={(event) => actions.setFilter(event.currentTarget.value)}
value={subject}
onChange={(event) => setSubject(event.currentTarget.value)}
/>
<div className={classes.addMembers}>
<div>
<Text className={classes.members}>{ state.strings.members }</Text>
<div className={classes.addMembers}>
{ cards.length === 0 && (
<div className={classes.noContacts}>
<Text className={classes.noContactsLabel}>{ state.strings.noContacts }</Text>
</div>
)}
{ contacts }
</div>
</div>
<div className={classes.addControls}>
<div className={classes.addSealed}>
{ state.sealSet && (
<Switch label={state.strings.sealedTopic} size="md" labelPosition="left" onChange={(ev) => setSealed(ev.currentTarget.checked)} />
)}
</div>
<Button variant="default" onClick={() => setAdd(false)}>
{state.strings.cancel}
</Button>
<Button variant="filled" onClick={addTopic} loading={adding}>
{state.strings.create}
</Button>
</div>
</div>
</Modal>

View File

@ -25,12 +25,12 @@ export function useContent() {
layout: null,
guid: '',
connected: [] as Card[],
connectedAndSealable: [] as Cards[],
sealable: [] as Cards[],
sorted: [] as Channel[],
filtered: [] as ChannelParams[],
filter: '',
topic: '',
sealable: false,
sealSet: false,
});
const compare = (a: Card, b: Card) => {