diff --git a/app/[slug]/dashboard/expenses/page.tsx b/app/[slug]/dashboard/expenses/page.tsx index 8b24064..dfa7bbf 100644 --- a/app/[slug]/dashboard/expenses/page.tsx +++ b/app/[slug]/dashboard/expenses/page.tsx @@ -1,15 +1,44 @@ /* Copyright (C) 2024 Manuel Bustillo*/ -import { lusitana } from '@/app/ui/fonts'; +'use client' + +import { AbstractApi } from '@/app/api/abstract-api'; +import { Expense, ExpenseSerializer } from '@/app/lib/expense'; +import { classNames } from '@/app/ui/components/button'; +import ExpenseFormDialog from '@/app/ui/components/expense-form-dialog'; import ExpensesTable from '@/app/ui/expenses/table'; - -export default function Page () { +import SkeletonTable from '@/app/ui/guests/skeleton-row'; +import { Suspense, useEffect, useState } from 'react'; + +export default function Page() { + const refreshExpenses = () => { + new AbstractApi().getAll(new ExpenseSerializer(), (expenses: Expense[]) => { + setExpenses(expenses); + }); + } + + const [expenses, setExpenses] = useState([]); + const [expenseBeingEdited, setExpenseBeingEdited] = useState(undefined); + useEffect(() => { refreshExpenses() }, []); + return (
-
-

Expenses

-

Summary

- +
+ + { refreshExpenses(); setExpenseBeingEdited(undefined) }} + expense={expenseBeingEdited} + visible={expenseBeingEdited !== undefined} + onHide={() => { setExpenseBeingEdited(undefined) }} + /> + }> + setExpenseBeingEdited(expense)} + /> +
); diff --git a/app/[slug]/dashboard/guests/page.tsx b/app/[slug]/dashboard/guests/page.tsx index 0b7a88d..beb73f8 100644 --- a/app/[slug]/dashboard/guests/page.tsx +++ b/app/[slug]/dashboard/guests/page.tsx @@ -2,30 +2,30 @@ 'use client'; -import { loadGroups } from '@/app/api/groups'; -import { loadGuests } from '@/app/api/guests'; -import { Group, Guest } from '@/app/lib/definitions'; +import { AbstractApi, } from '@/app/api/abstract-api'; +import { Guest, GuestSerializer } from '@/app/lib/guest'; 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 GuestFormDialog from '@/app/ui/components/guest-form-dialog'; import GroupsTable from '@/app/ui/groups/table'; import SkeletonTable from '@/app/ui/guests/skeleton-row'; import GuestsTable from '@/app/ui/guests/table'; import { TabPanel, TabView } from 'primereact/tabview'; import { Suspense, useState } from 'react'; +import { Group, GroupSerializer } from '@/app/lib/group'; export default function Page() { function refreshGuests() { - loadGuests((guests) => { - setGuests(guests); + new AbstractApi().getAll(new GuestSerializer(), (objects: Guest[]) => { + setGuests(objects); setGuestsLoaded(true); }); } function refreshGroups() { - loadGroups((groups) => { - setGroups(groups); + new AbstractApi().getAll(new GroupSerializer(), (objects: Group[]) => { + setGroups(objects); setGroupsLoaded(true); }); } diff --git a/app/api/abstract-api.tsx b/app/api/abstract-api.tsx new file mode 100644 index 0000000..b43e72e --- /dev/null +++ b/app/api/abstract-api.tsx @@ -0,0 +1,65 @@ +/* Copyright (C) 2024 Manuel Bustillo*/ + +import { Entity } from '@/app/lib/definitions'; +import { getCsrfToken, getSlug } from '@/app/lib/utils'; + +export interface Api { + getAll(serializable: Serializable ,callback: (objets: T[]) => void): void; + create(serializable: Serializable, object: T, callback: () => void): void; + update(serializable: Serializable, object: T, callback: () => void): void; + destroy(serializable: Serializable, object: T, callback: () => void): void; +} + +export interface Serializable { + fromJson(json: any): T; + toJson(object: T): string; + apiPath(): string; +} + +export class AbstractApi implements Api { + getAll(serializable: Serializable, callback: (objets: T[]) => void): void { + fetch(`/api/${getSlug()}/${serializable.apiPath()}`) + .then((response) => response.json()) + .then((data) => { + callback(data.map((record: any) => { + return serializable.fromJson(record); + })); + }, (error) => { + return []; + }); + } + + update(serializable: Serializable, object: T, callback: () => void): void { + fetch(`/api/${getSlug()}/${serializable.apiPath()}/${object.id}`, { + method: 'PUT', + body: serializable.toJson(object), + headers: { + 'Content-Type': 'application/json', + 'X-CSRF-TOKEN': getCsrfToken(), + } + }).then(callback) + .catch((error) => console.error(error)); + } + + create(serializable: Serializable, object: T, callback: () => void): void { + fetch(`/api/${getSlug()}/${serializable.apiPath()}`, { + method: 'POST', + body: serializable.toJson(object), + headers: { + 'Content-Type': 'application/json', + 'X-CSRF-TOKEN': getCsrfToken(), + } + }).then(callback) + .catch((error) => console.error(error)); + } + + destroy(serializable: Serializable, object: T, callback: () => void): void { + fetch(`/api/${getSlug()}/${serializable.apiPath()}/${object.id}`, { + method: 'DELETE', + headers: { + 'X-CSRF-TOKEN': getCsrfToken(), + } + }).then(callback) + .catch((error) => console.error(error)); + } +} diff --git a/app/api/expenses.tsx b/app/api/expenses.tsx deleted file mode 100644 index a23cd16..0000000 --- a/app/api/expenses.tsx +++ /dev/null @@ -1,40 +0,0 @@ -/* Copyright (C) 2024 Manuel Bustillo*/ - -import { Expense } from '@/app/lib/definitions'; -import { getCsrfToken, getSlug } from '@/app/lib/utils'; - -export function loadExpenses(onLoad?: (expenses: Expense[]) => void) { - fetch(`/api/${getSlug()}/expenses`) - .then((response) => response.json()) - .then((data) => { - onLoad && onLoad(data.map((record: any) => { - return ({ - id: record.id, - name: record.name, - amount: record.amount, - pricingType: record.pricing_type - }); - })); - }, (error) => { - return []; - }); -} - -export function updateExpense(expense: Expense) { - fetch(`/api/${getSlug()}/expenses/${expense.id}`, - { - method: 'PUT', - body: JSON.stringify({ - expense: { - name: expense.name, - amount: expense.amount, - pricing_type: expense.pricingType, - } - }), - headers: { - 'Content-Type': 'application/json', - 'X-CSRF-TOKEN': getCsrfToken(), - } - }) - .catch((error) => console.error(error)); -} \ No newline at end of file diff --git a/app/api/groups.tsx b/app/api/groups.tsx deleted file mode 100644 index 8c8081e..0000000 --- a/app/api/groups.tsx +++ /dev/null @@ -1,81 +0,0 @@ -/* Copyright (C) 2024 Manuel Bustillo*/ - -import { Group } from '@/app/lib/definitions'; -import { getCsrfToken, getSlug } from '../lib/utils'; - -export function loadGroups(onLoad?: (groups: Group[]) => void) { - fetch(`/api/${getSlug()}/groups`) - .then((response) => response.json()) - .then((data) => { - onLoad && onLoad(data.map((record: any) => { - return ({ - id: record.id, - name: record.name, - color: record.color, - attendance: { - considered: record.considered, - invited: record.invited, - confirmed: record.confirmed, - tentative: record.tentative, - declined: record.declined, - total: record.total, - } - }); - })); - }, (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)); -} - -export function destroyGroup(group: Group, onDestroy?: () => void) { - fetch(`/api/${getSlug()}/groups/${group.id}`, { - method: 'DELETE', - headers: { - 'X-CSRF-TOKEN': getCsrfToken(), - } - }) - .then((response) => response.json()) - .then((data) => { - onDestroy && onDestroy(); - }) - .catch((error) => console.error(error)); -} \ No newline at end of file diff --git a/app/api/guests.tsx b/app/api/guests.tsx deleted file mode 100644 index ce4f232..0000000 --- a/app/api/guests.tsx +++ /dev/null @@ -1,65 +0,0 @@ -/* Copyright (C) 2024 Manuel Bustillo*/ - -import { Guest } from '@/app/lib/definitions'; -import { getCsrfToken, getSlug } from '@/app/lib/utils'; - -export function loadGuests(onLoad?: (guests: Guest[]) => void) { - fetch(`/api/${getSlug()}/guests`) - .then((response) => response.json()) - .then((data) => { - onLoad && onLoad(data.map((record: any) => { - return ({ - id: record.id, - name: record.name, - status: record.status, - group_name: record.group.name, - groupId: record.group.id, - }); - })); - }, (error) => { - return []; - }); -}; - -export function updateGuest(guest: Guest) { - return fetch(`/api/${getSlug()}/guests/${guest.id}`, - { - method: 'PUT', - body: JSON.stringify({ guest: { name: guest.name, status: guest.status, group_id: guest.groupId } }), - headers: { - 'Content-Type': 'application/json', - 'X-CSRF-TOKEN': getCsrfToken(), - } - }) - .catch((error) => console.error(error)); -} - -export function createGuest(guest: Guest, onCreate?: () => void) { - fetch(`/api/${getSlug()}/guests`, { - method: 'POST', - body: JSON.stringify({ name: guest.name, group_id: guest.groupId, status: guest.status }), - headers: { - 'Content-Type': 'application/json', - 'X-CSRF-TOKEN': getCsrfToken(), - } - }) - .then((response) => response.json()) - .then((data) => { - onCreate && onCreate(); - }) - .catch((error) => console.error(error)); -} - -export function destroyGuest(guest: Guest, onDestroy?: () => void) { - fetch(`/api/${getSlug()}/guests/${guest.id}`, { - method: 'DELETE', - headers: { - 'X-CSRF-TOKEN': getCsrfToken(), - } - }) - .then((response) => response.json()) - .then((data) => { - onDestroy && onDestroy(); - }) - .catch((error) => console.error(error)); -} \ No newline at end of file diff --git a/app/lib/definitions.ts b/app/lib/definitions.ts index 464cb83..218150d 100644 --- a/app/lib/definitions.ts +++ b/app/lib/definitions.ts @@ -1,28 +1,11 @@ /* Copyright (C) 2024 Manuel Bustillo*/ -// This file contains type definitions for your data. -// It describes the shape of the data, and what data type each property should accept. -// For simplicity of teaching, we're manually defining these types. -// However, these types are generated automatically if you're using an ORM such as Prisma. +import { Guest } from "./guest"; -export const guestStatuses = ['considered', 'invited', 'confirmed', 'declined', 'tentative'] as const; -export type GuestStatus = typeof guestStatuses[number]; -export type Guest = { +export interface Entity { id?: string; - name?: string; - group_name?: string; - groupId?: string; - color?: string; - status?: GuestStatus } -export type Expense = { - id: string; - name: string; - amount: number; - pricingType: 'fixed' | 'per person'; -}; - export type TableArrangement = { id: string; number: number; @@ -31,26 +14,6 @@ export type TableArrangement = { discomfort?: number } -export type Group = { - id?: string; - name?: string; - guest_count?: number; - icon?: string; - children?: Group[]; - parentId?: string; - color?: string; - attendance?: AttendanceSummary -}; - -export type AttendanceSummary = { - considered: number; - invited: number; - confirmed: number; - declined: number; - tentative: number; - total: number; -} - export type guestsTable = { id: string; customer_id: string; @@ -73,5 +36,5 @@ export type Captcha = { } export type StructuredErrors = { - [key: string]: string[]|string; + [key: string]: string[] | string; }; \ No newline at end of file diff --git a/app/lib/expense.tsx b/app/lib/expense.tsx new file mode 100644 index 0000000..6964776 --- /dev/null +++ b/app/lib/expense.tsx @@ -0,0 +1,41 @@ +/* Copyright (C) 2024 Manuel Bustillo*/ + +import { Serializable } from "../api/abstract-api"; +import { Entity } from "./definitions"; + +export const pricingTypes = ['fixed', 'per_person'] as const; +export type PricingType = typeof pricingTypes[number]; + +export class Expense implements Entity { + id?: string; + name: string; + amount: number; + pricingType: PricingType; + + constructor(id?: string, name?: string, amount?: number, pricingType?: PricingType) { + this.id = id; + this.name = name || ''; + this.amount = amount || 0; + this.pricingType = pricingType || 'fixed'; + } +} + +export class ExpenseSerializer implements Serializable{ + fromJson(data: any): Expense { + return new Expense(data.id, data.name, data.amount, data.pricing_type); + } + + toJson(expense: Expense): string { + return JSON.stringify({ + expense: { + name: expense.name, + amount: expense.amount, + pricing_type: expense.pricingType + } + }); + } + + apiPath(): string { + return 'expenses'; + } +} \ No newline at end of file diff --git a/app/lib/group.tsx b/app/lib/group.tsx new file mode 100644 index 0000000..387e557 --- /dev/null +++ b/app/lib/group.tsx @@ -0,0 +1,64 @@ +/* Copyright (C) 2024 Manuel Bustillo*/ + +import { Entity } from "./definitions"; + +export type AttendanceSummary = { + considered: number; + invited: number; + confirmed: number; + declined: number; + tentative: number; + total: number; +} + +export class Group implements Entity { + id?: string; + name?: string; + guest_count?: number; + icon?: string; + children?: Group[]; + parentId?: string; + color?: string; + attendance?: AttendanceSummary + + constructor(id?: string, name?: string, guest_count?: number, icon?: string, children?: Group[], parentId?: string, color?: string, attendance?: AttendanceSummary) { + this.id = id; + this.name = name; + this.guest_count = guest_count; + this.icon = icon; + this.children = children; + this.parentId = parentId; + this.color = color; + this.attendance = attendance; + } +} + +export class GroupSerializer { + fromJson(data: any): Group { + return new Group( + data.id, + data.name, + data.guest_count, + data.icon, + data.children, + data.parent_id, + data.color, + data.attendance + ); + } + + toJson(group: Group): string { + return JSON.stringify({ + group: { + name: group.name, + color: group.color, + icon: group.icon, + parent_id: group.parentId + } + }); + } + + apiPath(): string { + return 'groups'; + } +} \ No newline at end of file diff --git a/app/lib/guest.tsx b/app/lib/guest.tsx new file mode 100644 index 0000000..0baddfe --- /dev/null +++ b/app/lib/guest.tsx @@ -0,0 +1,40 @@ +/* Copyright (C) 2024 Manuel Bustillo*/ + +import { Serializable } from "../api/abstract-api"; +import { Entity } from "./definitions"; + +export const guestStatuses = ['considered', 'invited', 'confirmed', 'declined', 'tentative'] as const; +export type GuestStatus = typeof guestStatuses[number]; + +export class Guest implements Entity { + id?: string; + name?: string; + group_name?: string; + groupId?: string; + color?: string; + status?: GuestStatus; + + constructor(id?: string, name?: string, group_name?: string, groupId?: string, color?: string, status?: GuestStatus) { + this.id = id; + this.name = name; + this.group_name = group_name; + this.groupId = groupId; + this.color = color; + this.status = status; + } +} + +export class GuestSerializer implements Serializable { + fromJson(data: any): Guest { + return new Guest(data.id, data.name, data.group_name, data.group_id, data.color, data.status); + } + + toJson(guest: Guest): string { + return JSON.stringify({ guest: { name: guest.name, status: guest.status, group_id: guest.groupId } }); + } + + apiPath(): string { + return 'guests'; + } +} + diff --git a/app/ui/components/expense-form-dialog.tsx b/app/ui/components/expense-form-dialog.tsx new file mode 100644 index 0000000..3c6747f --- /dev/null +++ b/app/ui/components/expense-form-dialog.tsx @@ -0,0 +1,83 @@ +/* Copyright (C) 2024 Manuel Bustillo*/ + +'use client'; + +import { AbstractApi } from '@/app/api/abstract-api'; +import { Expense, ExpenseSerializer, PricingType, pricingTypes } from '@/app/lib/expense'; +import { capitalize } from '@/app/lib/utils'; +import { classNames } from '@/app/ui/components/button'; +import { Dialog } from 'primereact/dialog'; +import { Dropdown } from 'primereact/dropdown'; +import { FloatLabel } from 'primereact/floatlabel'; +import { InputText } from 'primereact/inputtext'; +import { useState } from 'react'; + +export default function ExpenseFormDialog({ onCreate, onHide, expense, visible }: { + onCreate?: () => void, + onHide: () => void, + expense?: Expense, + visible: boolean, +}) { + + const [name, setName] = useState(expense?.name || ''); + const [amount, setAmount] = useState(expense?.amount || 0); + const [pricingType, setPricingType] = useState(expense?.pricingType || 'fixed'); + + const api = new AbstractApi(); + const serializer = new ExpenseSerializer(); + + function resetForm() { + setName(''); + setAmount(0); + setPricingType('fixed'); + } + + function submitGroup() { + if (expense?.id !== undefined) { + expense.name = name; + expense.amount = amount; + expense.pricingType = pricingType; + + api.update(serializer, expense, () => { + resetForm(); + onCreate && onCreate(); + }); + } else { + + api.create(serializer, new Expense(undefined, name, amount, pricingType), () => { + resetForm(); + onCreate && onCreate(); + }); + } + } + + return ( + <> + + +
+ + setName(e.target.value)} /> + + + + setAmount(parseFloat(e.target.value))} /> + + + + setPricingType(e.target.value)} options={ + pricingTypes.map((type) => { + return { label: capitalize(type), value: type }; + }) + } /> + + + + +
+
+ + ); +} \ No newline at end of file diff --git a/app/ui/components/group-form-dialog.tsx b/app/ui/components/group-form-dialog.tsx index 3ef1ec5..d652a13 100644 --- a/app/ui/components/group-form-dialog.tsx +++ b/app/ui/components/group-form-dialog.tsx @@ -2,8 +2,6 @@ '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'; @@ -11,6 +9,9 @@ import { Dropdown } from 'primereact/dropdown'; import { FloatLabel } from 'primereact/floatlabel'; import { InputText } from 'primereact/inputtext'; import { useState } from 'react'; +import { Group, GroupSerializer } from '@/app/lib/group'; +import { ApiError } from 'next/dist/server/api-utils'; +import { AbstractApi } from '@/app/api/abstract-api'; export default function GroupFormDialog({groups, onCreate, onHide, group, visible }: { groups: Group[], @@ -25,6 +26,9 @@ export default function GroupFormDialog({groups, onCreate, onHide, group, visibl const [color, setColor] = useState(group?.color || ''); const [parentId, setParentId] = useState(group?.parentId || ''); + const api = new AbstractApi(); + const serializer = new GroupSerializer(); + function resetForm() { setName(''); setIcon(''); @@ -43,12 +47,13 @@ export default function GroupFormDialog({groups, onCreate, onHide, group, visibl group.color = color; group.parentId = parentId; - updateGroup(group).then(() => { + api.update(serializer, group, () => { resetForm(); onCreate && onCreate(); }); } else { - group && createGroup({name, icon, color, parentId}, () => { + + api.create(serializer, new Group(undefined, name, undefined, icon, undefined, parentId, color), () => { resetForm(); onCreate && onCreate(); }); diff --git a/app/ui/components/guest-form-dialog.tsx b/app/ui/components/guest-form-dialog.tsx index bf94230..9d8bec5 100644 --- a/app/ui/components/guest-form-dialog.tsx +++ b/app/ui/components/guest-form-dialog.tsx @@ -2,8 +2,9 @@ 'use client'; -import { createGuest, updateGuest } from '@/app/api/guests'; -import { Group, Guest, GuestStatus, guestStatuses } from '@/app/lib/definitions'; +import { AbstractApi } from '@/app/api/abstract-api'; +import { Group } from '@/app/lib/group'; +import { Guest, GuestSerializer, GuestStatus, guestStatuses } from '@/app/lib/guest'; import { capitalize } from '@/app/lib/utils'; import { classNames } from '@/app/ui/components/button'; import { Dialog } from 'primereact/dialog'; @@ -24,6 +25,9 @@ export default function GuestFormDialog({ groups, onCreate, onHide, guest, visib const [group, setGroup] = useState(guest?.groupId || null); const [status, setStatus] = useState(guest?.status || null); + const api = new AbstractApi(); + const serializer = new GuestSerializer(); + function resetForm() { setName(''); setGroup(null); @@ -37,14 +41,15 @@ export default function GuestFormDialog({ groups, onCreate, onHide, guest, visib if (guest?.id !== undefined) { guest.name = name; - guest.groupId = group; + guest.groupId = group; guest.status = status; - updateGuest(guest).then(() => { + + api.update(serializer, guest, () => { resetForm(); onCreate && onCreate(); }); } else { - guest && createGuest({name: name, groupId: group, status: status}, () => { + api.create(serializer, new Guest(undefined, name, undefined, group, undefined, status), ()=> { resetForm(); onCreate && onCreate(); }); diff --git a/app/ui/expenses/table.tsx b/app/ui/expenses/table.tsx index 121990c..28543d6 100644 --- a/app/ui/expenses/table.tsx +++ b/app/ui/expenses/table.tsx @@ -2,41 +2,43 @@ 'use client' -import { loadExpenses, updateExpense } from '@/app/api/expenses'; -import { Expense } from '@/app/lib/definitions'; -import { useState } from "react"; -import InlineTextField from "../components/form/inlineTextField"; +import { AbstractApi } from '@/app/api/abstract-api'; +import { Expense, ExpenseSerializer } from '@/app/lib/expense'; +import { PencilIcon, TrashIcon } from '@heroicons/react/24/outline'; import TableOfContents from "../components/table-of-contents"; -export default function ExpensesTable() { - const [expenses, setExpenses] = useState>([]); - const [expensesLoaded, setExpensesLoaded] = useState(false); - function refreshExpenses() { - loadExpenses((expenses) => { - setExpenses(expenses); - setExpensesLoaded(true); - }); - } +export default function ExpensesTable({ expenses, onUpdate, onEdit }: { + expenses: Expense[], + onUpdate: () => void, + onEdit: (expense: Expense) => void, +}) { - !expensesLoaded && refreshExpenses(); + const api = new AbstractApi(); + const serializer = new ExpenseSerializer(); return ( ( - { expense.name = value; updateExpense(expense) }} /> + {expense.name} - { expense.amount = parseFloat(value); updateExpense(expense) }} /> + {expense.amount} {expense.pricingType} + +
+ { api.destroy(serializer, expense, onUpdate) }} /> + onEdit(expense)} /> +
+ )} /> diff --git a/app/ui/groups/table.tsx b/app/ui/groups/table.tsx index ca1240e..5e1f0df 100644 --- a/app/ui/groups/table.tsx +++ b/app/ui/groups/table.tsx @@ -2,10 +2,10 @@ 'use client'; -import { Group } from '@/app/lib/definitions'; +import { Group, GroupSerializer } from '@/app/lib/group'; import TableOfContents from '../components/table-of-contents'; import { PencilIcon, TrashIcon } from '@heroicons/react/24/outline'; -import { destroyGroup } from '@/app/api/groups'; +import { AbstractApi } from '@/app/api/abstract-api'; export default function GroupsTable({ groups, onUpdate, onEdit }: { groups: Group[], @@ -13,6 +13,9 @@ export default function GroupsTable({ groups, onUpdate, onEdit }: { onEdit: (group: Group) => void, }) { + const api = new AbstractApi(); + const serializer = new GroupSerializer(); + return (
- { destroyGroup(group, () => onUpdate()) }} /> + { api.destroy(serializer, group, onUpdate) }} /> onEdit(group)} />
diff --git a/app/ui/guests/table.tsx b/app/ui/guests/table.tsx index 304c357..4f3694b 100644 --- a/app/ui/guests/table.tsx +++ b/app/ui/guests/table.tsx @@ -2,9 +2,8 @@ 'use client'; -import { destroyGuest, updateGuest } from '@/app/api/guests'; -import { Guest, GuestStatus } from '@/app/lib/definitions'; -import { classNames } from '@/app/ui/components/button'; +import { AbstractApi } from '@/app/api/abstract-api'; +import { Guest , GuestSerializer} from '@/app/lib/guest'; import { PencilIcon, TrashIcon } from '@heroicons/react/24/outline'; import clsx from 'clsx'; import TableOfContents from '../components/table-of-contents'; @@ -14,6 +13,10 @@ export default function guestsTable({ guests, onUpdate, onEdit }: { onUpdate: () => void, onEdit: (guest: Guest) => void }) { + + const api = new AbstractApi(); + const serializer = new GuestSerializer(); + return (
- { destroyGuest(guest, () => onUpdate()) }} /> + { api.destroy(serializer, guest, onUpdate)}} /> onEdit(guest)} />