fix(announcements): improved sending flow
Build and Push Docker image / build-and-push (push) Successful in 6m10s
Details
Build and Push Docker image / build-and-push (push) Successful in 6m10s
Details
This commit is contained in:
parent
7eb38a1ef7
commit
73afba37ac
|
@ -1,7 +1,6 @@
|
||||||
import {Button, Group, Modal, ModalProps, Text} from "@mantine/core";
|
import {Button, Group, Modal, ModalProps, Text} from "@mantine/core";
|
||||||
import {useDisclosure} from "@mantine/hooks";
|
import {useDisclosure} from "@mantine/hooks";
|
||||||
import {IconAlertTriangle} from "@tabler/icons-react";
|
import {IconAlertTriangle} from "@tabler/icons-react";
|
||||||
import {useState} from "react";
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -13,19 +12,17 @@ import {useState} from "react";
|
||||||
* @param onCancel - the function to call when the user cancels (optional)
|
* @param onCancel - the function to call when the user cancels (optional)
|
||||||
* @param props - additional props for the modal
|
* @param props - additional props for the modal
|
||||||
*/
|
*/
|
||||||
export const useConfirmModal = <T, >(
|
export const useConfirmModal = (
|
||||||
{title, description, onConfirm, onCancel, ...props}: {
|
{title, description, onConfirm, onCancel, ...props}: {
|
||||||
title?: string,
|
title?: string,
|
||||||
description: string,
|
description: string,
|
||||||
onConfirm: (t?: T) => void,
|
onConfirm: () => void,
|
||||||
onCancel?: () => void
|
onCancel?: () => void
|
||||||
} & Omit<ModalProps, "opened" | "onClose">
|
} & Omit<ModalProps, "opened" | "onClose">
|
||||||
) => {
|
) => {
|
||||||
|
|
||||||
const [showConfirmModal, handler] = useDisclosure(false)
|
const [showConfirmModal, handler] = useDisclosure(false)
|
||||||
|
|
||||||
const [data, setData] = useState<T | undefined>(undefined)
|
|
||||||
|
|
||||||
const ConfirmModal = () => {
|
const ConfirmModal = () => {
|
||||||
return <>
|
return <>
|
||||||
<Modal
|
<Modal
|
||||||
|
@ -48,15 +45,13 @@ export const useConfirmModal = <T, >(
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
handler.close()
|
handler.close()
|
||||||
onCancel?.()
|
onCancel?.()
|
||||||
setData(undefined)
|
|
||||||
}}>
|
}}>
|
||||||
Abbrechen
|
Abbrechen
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
handler.close()
|
handler.close()
|
||||||
onConfirm(data)
|
onConfirm()
|
||||||
setData(undefined)
|
|
||||||
}}
|
}}
|
||||||
size={"xs"}
|
size={"xs"}
|
||||||
leftSection={<IconAlertTriangle/>}
|
leftSection={<IconAlertTriangle/>}
|
||||||
|
@ -72,9 +67,8 @@ export const useConfirmModal = <T, >(
|
||||||
|
|
||||||
return {
|
return {
|
||||||
showConfirmModal,
|
showConfirmModal,
|
||||||
toggleConfirmModal: (t?: T) => {
|
toggleConfirmModal: () => {
|
||||||
handler.toggle()
|
handler.toggle()
|
||||||
setData(t)
|
|
||||||
},
|
},
|
||||||
ConfirmModal
|
ConfirmModal
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import {FieldEntriesFilter, FieldEntryFilter} from "@/components/formUtil/FromIn
|
||||||
import {Button, Group, Popover, Switch, Text} from "@mantine/core";
|
import {Button, Group, Popover, Switch, Text} from "@mantine/core";
|
||||||
import {IconFilter, IconFilterOff, IconFilterPlus} from "@tabler/icons-react";
|
import {IconFilter, IconFilterOff, IconFilterPlus} from "@tabler/icons-react";
|
||||||
import {FilterField} from "@/components/formUtil/FormFilter/FilterField.tsx";
|
import {FilterField} from "@/components/formUtil/FormFilter/FilterField.tsx";
|
||||||
|
import {useEffect} from "react";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* todo
|
* todo
|
||||||
|
@ -60,7 +61,7 @@ const createDefaultFilter = (field: FormSchemaField): FieldEntryFilter => {
|
||||||
* @see assembleFilter
|
* @see assembleFilter
|
||||||
* @see FormBuilder
|
* @see FormBuilder
|
||||||
*
|
*
|
||||||
* @param schema The schema to render
|
* @param schema The schema to render. Make sure that the schema is memoized!
|
||||||
* @param label The label for the filter button
|
* @param label The label for the filter button
|
||||||
* @param defaultValue The default value for the filter
|
* @param defaultValue The default value for the filter
|
||||||
* @param onChange The function to call when the filter changes
|
* @param onChange The function to call when the filter changes
|
||||||
|
@ -72,7 +73,6 @@ export default function FormFilter({schema, label, defaultValue, onChange}: {
|
||||||
onChange?: (filter: FieldEntriesFilter) => void,
|
onChange?: (filter: FieldEntriesFilter) => void,
|
||||||
}) {
|
}) {
|
||||||
|
|
||||||
|
|
||||||
const formValues = useForm({
|
const formValues = useForm({
|
||||||
initialValues: defaultValue ?? {} as FieldEntriesFilter,
|
initialValues: defaultValue ?? {} as FieldEntriesFilter,
|
||||||
onValuesChange: (values) => {
|
onValuesChange: (values) => {
|
||||||
|
@ -88,6 +88,21 @@ export default function FormFilter({schema, label, defaultValue, onChange}: {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// this removes all filter values not present in schema, this is necessary because the schema might change
|
||||||
|
// and the filter values might not be valid anymore
|
||||||
|
const values = formValues.values
|
||||||
|
const newValues: FieldEntriesFilter = {}
|
||||||
|
Object.keys(values).forEach(key => {
|
||||||
|
if (schema.fields.find(f => f.id === key)) {
|
||||||
|
newValues[key] = values[key]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
formValues.setValues(newValues)
|
||||||
|
console.log("Schema changed", values, newValues)
|
||||||
|
// eslint-disable-next-line
|
||||||
|
}, [schema])
|
||||||
|
|
||||||
return <>
|
return <>
|
||||||
<Popover width={300} position="bottom" withArrow shadow="md">
|
<Popover width={300} position="bottom" withArrow shadow="md">
|
||||||
<Popover.Target>
|
<Popover.Target>
|
||||||
|
|
|
@ -58,7 +58,7 @@ export default function Announcements() {
|
||||||
</Center>
|
</Center>
|
||||||
) : announcements.length === 0 ? <div className={classes.text}>
|
) : announcements.length === 0 ? <div className={classes.text}>
|
||||||
<Text ta={"center"} size={"xs"} c={"dimmed"}>
|
<Text ta={"center"} size={"xs"} c={"dimmed"}>
|
||||||
"Noch keine Ankündigungen"
|
Noch keine Ankündigungen
|
||||||
</Text>
|
</Text>
|
||||||
</div> : null
|
</div> : null
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,6 +62,7 @@ export default function MessageEntriesModal({opened, event, onClose, query}: {
|
||||||
},
|
},
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
showSuccessNotification("Nachrichten wurden versendet")
|
showSuccessNotification("Nachrichten wurden versendet")
|
||||||
|
formValues.reset()
|
||||||
onClose()
|
onClose()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -35,6 +35,7 @@ import EventEntries from "@/pages/events/e/:eventId/EventLists/Search/EventEntri
|
||||||
import {useEventRights} from "@/pages/events/util.ts";
|
import {useEventRights} from "@/pages/events/util.ts";
|
||||||
import DownloadDataModal from "@/pages/events/e/:eventId/EventLists/Search/DownloadDataModal.tsx";
|
import DownloadDataModal from "@/pages/events/e/:eventId/EventLists/Search/DownloadDataModal.tsx";
|
||||||
import MessageEntriesModal from "@/pages/events/e/:eventId/EventLists/Search/MessageEntriesModal.tsx";
|
import MessageEntriesModal from "@/pages/events/e/:eventId/EventLists/Search/MessageEntriesModal.tsx";
|
||||||
|
import {useMemo} from "react";
|
||||||
|
|
||||||
export default function ListSearch({event}: { event: EventModel }) {
|
export default function ListSearch({event}: { event: EventModel }) {
|
||||||
|
|
||||||
|
@ -118,12 +119,32 @@ export default function ListSearch({event}: { event: EventModel }) {
|
||||||
initialPageParam: 1,
|
initialPageParam: 1,
|
||||||
})
|
})
|
||||||
|
|
||||||
// this string informs the user about the current list selection
|
// this string informs the user about the current list selection
|
||||||
const listInfoString = `${formValues.values.selectedLists.length > 0 ? ` in den Listen ${formValues.values.selectedLists.map(l => `'${l.name}'`).join(", ")}` : ""}`
|
const listInfoString = `${formValues.values.selectedLists.length > 0 ? ` in den Listen ${formValues.values.selectedLists.map(l => `'${l.name}'`).join(", ")}` : ""}`
|
||||||
|
|
||||||
const entries = query.data?.pages.flatMap(p => p.items) ?? []
|
const entries = query.data?.pages.flatMap(p => p.items) ?? []
|
||||||
const entriesCount = query.data?.pages?.[0]?.totalItems ?? 0
|
const entriesCount = query.data?.pages?.[0]?.totalItems ?? 0
|
||||||
|
|
||||||
|
const questionSchema = useMemo(() => ({
|
||||||
|
fields: [
|
||||||
|
...event.defaultEntryQuestionSchema?.fields ?? [],
|
||||||
|
...formValues.values.selectedLists.map(l => ([
|
||||||
|
...l.entryQuestionSchema?.fields ?? [],
|
||||||
|
])).flat()
|
||||||
|
]
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}), [event.id, JSON.stringify(formValues.values.selectedLists)])
|
||||||
|
|
||||||
|
const statusSchema = useMemo(() => ({
|
||||||
|
fields: [
|
||||||
|
...event.defaultEntryStatusSchema?.fields ?? [],
|
||||||
|
...formValues.values.selectedLists.map(l => ([
|
||||||
|
...l.entryStatusSchema?.fields ?? [],
|
||||||
|
])).flat()
|
||||||
|
]
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}), [event.id, JSON.stringify(formValues.values.selectedLists)])
|
||||||
|
|
||||||
return <div className={"stack"}>
|
return <div className={"stack"}>
|
||||||
<Title order={4} c={"blue"}>Listen Anmeldungen</Title>
|
<Title order={4} c={"blue"}>Listen Anmeldungen</Title>
|
||||||
|
|
||||||
|
@ -163,28 +184,14 @@ export default function ListSearch({event}: { event: EventModel }) {
|
||||||
<Group>
|
<Group>
|
||||||
<FormFilter
|
<FormFilter
|
||||||
label={"Fragen"}
|
label={"Fragen"}
|
||||||
schema={{
|
schema={questionSchema}
|
||||||
fields: [
|
|
||||||
...event.defaultEntryQuestionSchema?.fields ?? [],
|
|
||||||
...formValues.values.selectedLists.map(l => ([
|
|
||||||
...l.entryQuestionSchema?.fields ?? [],
|
|
||||||
])).flat()
|
|
||||||
]
|
|
||||||
}}
|
|
||||||
defaultValue={formValues.values.questionFilter}
|
defaultValue={formValues.values.questionFilter}
|
||||||
onChange={(qf) => formValues.setFieldValue("questionFilter", qf)}
|
onChange={(qf) => formValues.setFieldValue("questionFilter", qf)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<FormFilter
|
<FormFilter
|
||||||
label={"Status"}
|
label={"Status"}
|
||||||
schema={{
|
schema={statusSchema}
|
||||||
fields: [
|
|
||||||
...event.defaultEntryStatusSchema?.fields ?? [],
|
|
||||||
...formValues.values.selectedLists.map(l => ([
|
|
||||||
...l.entryStatusSchema?.fields ?? [],
|
|
||||||
])).flat()
|
|
||||||
]
|
|
||||||
}}
|
|
||||||
defaultValue={formValues.values.statusFilter}
|
defaultValue={formValues.values.statusFilter}
|
||||||
onChange={(sf) => formValues.setFieldValue("statusFilter", sf)}
|
onChange={(sf) => formValues.setFieldValue("statusFilter", sf)}
|
||||||
/>
|
/>
|
||||||
|
|
Loading…
Reference in New Issue