diff --git a/app/src/app/app/changelog/page.tsx b/app/src/app/app/changelog/page.tsx index cb1bcc026..18ac69009 100644 --- a/app/src/app/app/changelog/page.tsx +++ b/app/src/app/app/changelog/page.tsx @@ -44,6 +44,18 @@ export default async function Page() { return (
+ + +

+ Du kannst jetzt SILC-Transaktionen direkt über den “Neu”-Button in der + TopBar erstellen. +

+
+
+ ).then((mod) => mod.CreateProfitDistributionCycleForm), ); +const CreateSilcTransactionForm = dynamic(() => + import( + "@/modules/silc/components/CreateSilcTransactionForm" + ).then((mod) => mod.CreateSilcTransactionForm), +); + export const createForms = { citizen: { formComponent: CreateCitizenForm, @@ -80,6 +86,11 @@ export const createForms = { modalHeading: "Neuer Task", modalWidth: "w-[768px]", }, + silcTransaction: { + formComponent: CreateSilcTransactionForm, + modalHeading: "Neue SILC-Transaktion", + modalWidth: "w-[480px]", + }, }; interface CreateContext { diff --git a/app/src/modules/shell/components/TopBar/Create.tsx b/app/src/modules/shell/components/TopBar/Create.tsx index 56affff5c..e31ecdb55 100644 --- a/app/src/modules/shell/components/TopBar/Create.tsx +++ b/app/src/modules/shell/components/TopBar/Create.tsx @@ -39,6 +39,10 @@ export const Create = ({ className }: Props) => { const showCreateTask = Boolean( authentication && authentication.authorize("task", "create"), ); + const showCreateSilcTransaction = Boolean( + authentication && + authentication.authorize("silcTransactionOfOtherCitizen", "create"), + ); if ( !showCreateCitizen && @@ -46,7 +50,8 @@ export const Create = ({ className }: Props) => { !showCreateOrganization && !showCreateRole && !showCreatePenaltyEntry && - !showCreateTask + !showCreateTask && + !showCreateSilcTransaction ) return null; @@ -73,6 +78,7 @@ export const Create = ({ className }: Props) => { showCreateRole={showCreateRole} showCreatePenaltyEntry={showCreatePenaltyEntry} showCreateTask={showCreateTask} + showCreateSilcTransaction={showCreateSilcTransaction} />
@@ -86,6 +92,7 @@ interface PopoverChildrenProps { readonly showCreateRole: boolean; readonly showCreatePenaltyEntry: boolean; readonly showCreateTask: boolean; + readonly showCreateSilcTransaction: boolean; } const PopoverChildren = ({ @@ -95,6 +102,7 @@ const PopoverChildren = ({ showCreateRole, showCreatePenaltyEntry, showCreateTask, + showCreateSilcTransaction, }: PopoverChildrenProps) => { const { closePopover } = usePopover(); const { openCreateModal } = useCreateContext(); @@ -157,6 +165,12 @@ const PopoverChildren = ({ }); if (showCreateTask) items.push({ label: "Task", type: "button", modalId: "task" }); + if (showCreateSilcTransaction) + items.push({ + label: "SILC-Transaktion", + type: "button", + modalId: "silcTransaction", + }); items = items.toSorted((a, b) => a.label.localeCompare(b.label)); diff --git a/app/src/modules/silc/components/CreateSilcTransactionForm.tsx b/app/src/modules/silc/components/CreateSilcTransactionForm.tsx new file mode 100644 index 000000000..4773d343d --- /dev/null +++ b/app/src/modules/silc/components/CreateSilcTransactionForm.tsx @@ -0,0 +1,106 @@ +"use client"; + +import { CitizenInput } from "@/modules/citizen/components/CitizenInput"; +import Button from "@/modules/common/components/Button"; +import { Button2 } from "@/modules/common/components/Button2"; +import { NumberInput } from "@/modules/common/components/form/NumberInput"; +import { Textarea } from "@/modules/common/components/form/Textarea"; +import Note from "@/modules/common/components/Note"; +import { unstable_rethrow } from "next/navigation"; +import { useActionState } from "react"; +import toast from "react-hot-toast"; +import { FaSave, FaSpinner } from "react-icons/fa"; +import { createSilcTransaction } from "../actions/createSilcTransaction"; + +interface Props { + readonly onSuccess?: () => void; +} + +export const CreateSilcTransactionForm = ({ onSuccess }: Props) => { + const [state, formAction, isPending] = useActionState( + async (previousState: unknown, formData: FormData) => { + try { + const response = await createSilcTransaction(formData); + + if (response.error) { + toast.error(response.error); + console.error(response); + return response; + } + + toast.success(response.success!); + if (formData.has("createAnother")) { + return response; + } + + onSuccess?.(); + return response; + } catch (error) { + unstable_rethrow(error); + toast.error( + "Ein unbekannter Fehler ist aufgetreten. Bitte versuche es später erneut.", + ); + console.error(error); + return { + error: + "Ein unbekannter Fehler ist aufgetreten. Bitte versuche es später erneut.", + requestPayload: formData, + }; + } + }, + null, + ); + + return ( +
+ + + + +