mirror of
https://github.com/balzack/databag.git
synced 2025-05-04 07:25:15 +00:00
modal for new topic in webapp
This commit is contained in:
parent
fef6c7b1dd
commit
aa49b1ef19
@ -26,11 +26,12 @@ export function Content({select}: {select: (focus: Focus) => void}) {
|
|||||||
action: () => setAlert(false),
|
action: () => setAlert(false),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
const cards = (state.sealSet && sealed) ? state.sealable : state.connected;
|
||||||
|
|
||||||
const addTopic = async () => {
|
const addTopic = async () => {
|
||||||
setAdding(true);
|
setAdding(true);
|
||||||
try {
|
try {
|
||||||
await actions.addTopic(sealed, subject, members);
|
await actions.addTopic(sealed, subject, members.filter(id => Boolean(cards.find(card => card.cardId === id))));
|
||||||
setAdd(false);
|
setAdd(false);
|
||||||
setSubject('');
|
setSubject('');
|
||||||
setMembers([]);
|
setMembers([]);
|
||||||
@ -43,8 +44,6 @@ export function Content({select}: {select: (focus: Focus) => void}) {
|
|||||||
setAdding(false);
|
setAdding(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const cards = sealed ? state.sealable : state.connected;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={styles.container}>
|
<View style={styles.container}>
|
||||||
<SafeAreaView style={styles.header}>
|
<SafeAreaView style={styles.header}>
|
||||||
|
@ -25,12 +25,12 @@ export function useContent() {
|
|||||||
layout: null,
|
layout: null,
|
||||||
guid: '',
|
guid: '',
|
||||||
connected: [] as Card[],
|
connected: [] as Card[],
|
||||||
connectedAndSealable: [] as Cards[],
|
sealable: [] as Cards[],
|
||||||
sorted: [] as Channel[],
|
sorted: [] as Channel[],
|
||||||
filtered: [] as ChannelParams[],
|
filtered: [] as ChannelParams[],
|
||||||
filter: '',
|
filter: '',
|
||||||
topic: '',
|
topic: '',
|
||||||
sealable: false,
|
sealSet: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
const compare = (a: Card, b: Card) => {
|
const compare = (a: Card, b: Card) => {
|
||||||
|
@ -82,9 +82,52 @@
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 16px;
|
gap: 16px;
|
||||||
|
|
||||||
|
.members {
|
||||||
|
padding-left: 4px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--mantine-color-text-6);
|
||||||
|
}
|
||||||
|
|
||||||
.addMembers {
|
.addMembers {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 200px;
|
min-height: 128px;
|
||||||
|
max-height: 256px;
|
||||||
background: var(--mantine-color-surface-0);
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,18 +1,65 @@
|
|||||||
import React, {useState} from 'react';
|
import React, {useState} from 'react';
|
||||||
import { useContent } from './useContent.hook'
|
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 { IconSearch, IconMessagePlus, IconLabel } from '@tabler/icons-react'
|
||||||
import classes from './Content.module.css'
|
import classes from './Content.module.css'
|
||||||
import { Channel } from '../channel/Channel'
|
import { Channel } from '../channel/Channel'
|
||||||
import { Focus } from 'databag-client-sdk'
|
import { Focus } from 'databag-client-sdk'
|
||||||
|
import { Card } from '../card/Card';
|
||||||
|
import { modals } from '@mantine/modals'
|
||||||
|
|
||||||
export function Content({ select }: { select: (focus: Focus) => void }) {
|
export function Content({ select }: { select: (focus: Focus) => void }) {
|
||||||
const { state, actions } = useContent()
|
const { state, actions } = useContent()
|
||||||
const [add, setAdd] = useState(false);
|
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 () => {
|
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) => {
|
const channels = state.filtered.map((channel, idx) => {
|
||||||
return (
|
return (
|
||||||
<Channel
|
<Channel
|
||||||
@ -59,7 +106,7 @@ export function Content({ select }: { select: (focus: Focus) => void }) {
|
|||||||
</Button>
|
</Button>
|
||||||
</div>
|
</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}>
|
<div className={classes.addContainer}>
|
||||||
<TextInput
|
<TextInput
|
||||||
className={classes.input}
|
className={classes.input}
|
||||||
@ -67,11 +114,32 @@ export function Content({ select }: { select: (focus: Focus) => void }) {
|
|||||||
leftSectionPointerEvents="none"
|
leftSectionPointerEvents="none"
|
||||||
leftSection={<IconLabel size={20} />}
|
leftSection={<IconLabel size={20} />}
|
||||||
placeholder={state.strings.subjectOptional}
|
placeholder={state.strings.subjectOptional}
|
||||||
value={state.filter}
|
value={subject}
|
||||||
onChange={(event) => actions.setFilter(event.currentTarget.value)}
|
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>
|
||||||
</div>
|
</div>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
@ -25,12 +25,12 @@ export function useContent() {
|
|||||||
layout: null,
|
layout: null,
|
||||||
guid: '',
|
guid: '',
|
||||||
connected: [] as Card[],
|
connected: [] as Card[],
|
||||||
connectedAndSealable: [] as Cards[],
|
sealable: [] as Cards[],
|
||||||
sorted: [] as Channel[],
|
sorted: [] as Channel[],
|
||||||
filtered: [] as ChannelParams[],
|
filtered: [] as ChannelParams[],
|
||||||
filter: '',
|
filter: '',
|
||||||
topic: '',
|
topic: '',
|
||||||
sealable: false,
|
sealSet: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
const compare = (a: Card, b: Card) => {
|
const compare = (a: Card, b: Card) => {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user