diff --git a/app/[slug]/dashboard/guests/page.tsx b/app/[slug]/dashboard/guests/page.tsx index 09db838..20cc211 100644 --- a/app/[slug]/dashboard/guests/page.tsx +++ b/app/[slug]/dashboard/guests/page.tsx @@ -7,6 +7,7 @@ import { loadGuests } from '@/app/api/guests'; import { Group, Guest } from '@/app/lib/definitions'; import { classNames } from '@/app/ui/components/button'; import GuestFormDialog from '@/app/ui/components/guest-form-dialog'; +import GroupFormDialog from '@/app/ui/components/group-form-dialog'; import GroupsTable from '@/app/ui/groups/table'; import SkeletonTable from '@/app/ui/guests/skeleton-row'; import GuestsTable from '@/app/ui/guests/table'; @@ -31,6 +32,7 @@ export default function Page() { const [groupsLoaded, setGroupsLoaded] = useState(false); const [groups, setGroups] = useState>([]); + const [groupBeingEdited, setGroupBeingEdited] = useState(undefined); const [guestsLoaded, setGuestsLoaded] = useState(false); const [guests, setGuests] = useState>([]); @@ -59,7 +61,18 @@ export default function Page() { -
+
+ + + { refreshGroups(); setGroupBeingEdited(undefined) }} + group={groupBeingEdited} + visible={groupBeingEdited !== undefined} + onHide={() => { setGroupBeingEdited(undefined) }} + /> + }> diff --git a/app/api/groups.tsx b/app/api/groups.tsx index 807c19f..1ffc0b5 100644 --- a/app/api/groups.tsx +++ b/app/api/groups.tsx @@ -1,7 +1,7 @@ /* Copyright (C) 2024 Manuel Bustillo*/ import { Group } from '@/app/lib/definitions'; -import { getSlug } from '../lib/utils'; +import { getCsrfToken, getSlug } from '../lib/utils'; export function loadGroups(onLoad?: (groups: Group[]) => void) { fetch(`/api/${getSlug()}/groups`) @@ -25,4 +25,43 @@ export function loadGroups(onLoad?: (groups: Group[]) => void) { }, (error) => { return []; }); +} + +export function updateGroup(group: Group) { + return fetch(`/api/${getSlug()}/groups/${group.id}`, + { + method: 'PUT', + body: JSON.stringify({ group: { + name: group.name, + color: group.color, + icon: group.icon, + parent_id: group.parentId + } }), + headers: { + 'Content-Type': 'application/json', + 'X-CSRF-TOKEN': getCsrfToken(), + } + }) + .catch((error) => console.error(error)); +} + +export function createGroup(group: Group, onCreate?: () => void) { + fetch(`/api/${getSlug()}/groups`, { + method: 'POST', + body: JSON.stringify({ + name: group.name, + color: group.color, + icon: group.icon, + parent_id: group.parentId + }), + headers: { + 'Content-Type': 'application/json', + 'X-CSRF-TOKEN': getCsrfToken(), + } + }) + .then((response) => response.json()) + .then((data) => { + onCreate && onCreate(); + }) + .catch((error) => console.error(error)); } \ No newline at end of file diff --git a/app/lib/definitions.ts b/app/lib/definitions.ts index aba529b..464cb83 100644 --- a/app/lib/definitions.ts +++ b/app/lib/definitions.ts @@ -32,11 +32,12 @@ export type TableArrangement = { } export type Group = { - id: string; - name: string; - guest_count: number; - icon: string; - children: Group[]; + id?: string; + name?: string; + guest_count?: number; + icon?: string; + children?: Group[]; + parentId?: string; color?: string; attendance?: AttendanceSummary }; diff --git a/app/ui/components/group-form-dialog.tsx b/app/ui/components/group-form-dialog.tsx new file mode 100644 index 0000000..3ef1ec5 --- /dev/null +++ b/app/ui/components/group-form-dialog.tsx @@ -0,0 +1,91 @@ +/* Copyright (C) 2024 Manuel Bustillo*/ + +'use client'; + +import { createGroup, updateGroup } from '@/app/api/groups'; +import { Group } from '@/app/lib/definitions'; +import { classNames } from '@/app/ui/components/button'; +import { Dialog } from 'primereact/dialog'; +import { ColorPicker } from 'primereact/colorpicker'; +import { Dropdown } from 'primereact/dropdown'; +import { FloatLabel } from 'primereact/floatlabel'; +import { InputText } from 'primereact/inputtext'; +import { useState } from 'react'; + +export default function GroupFormDialog({groups, onCreate, onHide, group, visible }: { + groups: Group[], + onCreate?: () => void, + onHide: () => void, + group?: Group, + visible: boolean, +}) { + + const [name, setName] = useState(group?.name || ''); + const [icon, setIcon] = useState(group?.icon || ''); + const [color, setColor] = useState(group?.color || ''); + const [parentId, setParentId] = useState(group?.parentId || ''); + + function resetForm() { + setName(''); + setIcon(''); + setColor(''); + setParentId(''); + } + + function submitGroup() { + if (!(name)) { + return + } + + if (group?.id !== undefined) { + group.name = name; + group.icon = icon; + group.color = color; + group.parentId = parentId; + + updateGroup(group).then(() => { + resetForm(); + onCreate && onCreate(); + }); + } else { + group && createGroup({name, icon, color, parentId}, () => { + resetForm(); + onCreate && onCreate(); + }); + } + } + + return ( + <> + + +
+ + setName(e.target.value)} /> + + + + setIcon(e.target.value)} /> + + + + setColor(`#${e.value}`)} /> + + + setParentId(e.target.value)} options={ + groups.map((group) => { + return { label: group.name, value: group.id }; + }) + } /> + + + + +
+
+ + ); +} \ No newline at end of file diff --git a/app/ui/components/guest-form-dialog.tsx b/app/ui/components/guest-form-dialog.tsx index 9da1ff9..bf94230 100644 --- a/app/ui/components/guest-form-dialog.tsx +++ b/app/ui/components/guest-form-dialog.tsx @@ -54,7 +54,7 @@ export default function GuestFormDialog({ groups, onCreate, onHide, guest, visib return ( <> - +
setName(e.target.value)} />