Reuse the guest creation dialog for the editing flow #110
| @ -13,6 +13,7 @@ export function loadGuests(onLoad?: (guests: Guest[]) => void) { | ||||
|           name: record.name, | ||||
|           status: record.status, | ||||
|           group_name: record.group.name, | ||||
|           groupId: record.group.id, | ||||
|         }); | ||||
|       })); | ||||
|     }, (error) => { | ||||
|  | ||||
| @ -2,16 +2,18 @@ | ||||
| 
 | ||||
| 'use client'; | ||||
| 
 | ||||
| import { loadGroups } from '@/app/api/groups'; | ||||
| import { loadGuests } from '@/app/api/guests'; | ||||
| import { Group, Guest } from '@/app/lib/definitions'; | ||||
| import CreationDialog from '@/app/ui/components/creation-dialog'; | ||||
| import { classNames } from '@/app/ui/components/button'; | ||||
| import GuestFormDialog from '@/app/ui/components/guest-form-dialog'; | ||||
| import GroupsTable from '@/app/ui/groups/table'; | ||||
| import AffinityGroupsTree from '@/app/ui/guests/affinity-groups-tree'; | ||||
| 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 { loadGuests } from '@/app/api/guests'; | ||||
| import { loadGroups } from '@/app/api/groups'; | ||||
| 
 | ||||
| 
 | ||||
| export default function Page() { | ||||
|   function refreshGuests() { | ||||
| @ -33,6 +35,7 @@ export default function Page() { | ||||
| 
 | ||||
|   const [guestsLoaded, setGuestsLoaded] = useState(false); | ||||
|   const [guests, setGuests] = useState<Array<Guest>>([]); | ||||
|   const [guestBeingEdited, setGuestBeingEdited] = useState<Guest | undefined>(undefined); | ||||
| 
 | ||||
|   !groupsLoaded && refreshGroups(); | ||||
|   !guestsLoaded && refreshGuests(); | ||||
| @ -44,9 +47,17 @@ export default function Page() { | ||||
|       <TabView> | ||||
|         <TabPanel header="Guests" leftIcon="pi pi-users mx-2"> | ||||
|           <div className="flex flex-col w-full items-center justify-between"> | ||||
|             <CreationDialog groups={groups} onCreate={refreshGuests} /> | ||||
|             <button onClick={() => setGuestBeingEdited({})} className={classNames('primary')}>Add new</button> | ||||
|             <GuestFormDialog | ||||
|               key={guestBeingEdited?.id} | ||||
|               groups={groups} | ||||
|               onCreate={() => { refreshGuests(); setGuestBeingEdited(undefined) }} | ||||
|               guest={guestBeingEdited} | ||||
|               visible={guestBeingEdited !== undefined} | ||||
|               onHide={() => { setGuestBeingEdited(undefined) }} | ||||
|             /> | ||||
|             <Suspense fallback={<SkeletonTable />}> | ||||
|               <GuestsTable guests={guests} onUpdate={refreshGuests} /> | ||||
|               <GuestsTable guests={guests} onUpdate={refreshGuests} onEdit={(guest) => setGuestBeingEdited(guest)} /> | ||||
|             </Suspense> | ||||
|           </div> | ||||
|         </ TabPanel> | ||||
|  | ||||
| @ -20,9 +20,10 @@ export type Customer = { | ||||
| 
 | ||||
| export type GuestStatus = 'considered' | 'invited' | 'confirmed' | 'declined' | 'tentative'; | ||||
| export type Guest = { | ||||
|   id: string; | ||||
|   name: string; | ||||
|   id?: string; | ||||
|   name?: string; | ||||
|   group_name?: string; | ||||
|   groupId?: string; | ||||
|   color?: string; | ||||
|   status?: GuestStatus | ||||
| } | ||||
|  | ||||
| @ -2,8 +2,8 @@ | ||||
| 
 | ||||
| 'use client'; | ||||
| 
 | ||||
| import { createGuest } from '@/app/api/guests'; | ||||
| import { Group } from '@/app/lib/definitions'; | ||||
| import { createGuest, updateGuest } from '@/app/api/guests'; | ||||
| import { Group, Guest } from '@/app/lib/definitions'; | ||||
| import { classNames } from '@/app/ui/components/button'; | ||||
| import { Dialog } from 'primereact/dialog'; | ||||
| import { Dropdown } from 'primereact/dropdown'; | ||||
| @ -11,25 +11,46 @@ import { FloatLabel } from 'primereact/floatlabel'; | ||||
| import { InputText } from 'primereact/inputtext'; | ||||
| import { useState } from 'react'; | ||||
| 
 | ||||
| export default function CreationDialog({ groups, onCreate }: { groups: Group[], onCreate?: () => void }) { | ||||
|   const [visible, setVisible] = useState(false); | ||||
| export default function GuestFormDialog({ groups, onCreate, onHide, guest, visible}: { | ||||
|   groups: Group[], | ||||
|   onCreate?: () => void, | ||||
|   onHide: () => void, | ||||
|   guest?: Guest, | ||||
|   visible: boolean, | ||||
| }) { | ||||
| 
 | ||||
|   const [name, setName] = useState(''); | ||||
|   const [group, setGroup] = useState(null); | ||||
|   function submitGuest() { | ||||
|     name && group && createGuest(name, group, () => { | ||||
|       setVisible(false); | ||||
|   const [name, setName] = useState(guest?.name || ''); | ||||
|   const [group, setGroup] = useState(guest?.groupId || null); | ||||
| 
 | ||||
|   function resetForm() { | ||||
|     setName(''); | ||||
|     setGroup(null); | ||||
|   } | ||||
| 
 | ||||
|   function submitGuest() { | ||||
|     if (!(name && group)) { | ||||
|       return | ||||
|     } | ||||
| 
 | ||||
|     if (guest?.id !== undefined) { | ||||
|       guest.name = name; | ||||
|       guest.groupId = group; | ||||
|       updateGuest(guest).then(() => { | ||||
|         resetForm(); | ||||
|         onCreate && onCreate(); | ||||
|       }); | ||||
|     } else { | ||||
|       createGuest(name, group, () => { | ||||
|         resetForm(); | ||||
|         onCreate && onCreate(); | ||||
|       }); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   return ( | ||||
|     <> | ||||
|       <button onClick={() => setVisible(true)} className={classNames('primary')}>Add new</button> | ||||
| 
 | ||||
|       <Dialog header="Add guest" visible={visible} style={{ width: '50vw' }} onHide={() => { if (!visible) return; setVisible(false); }}> | ||||
|       <Dialog header="Add guest" visible={visible} style={{ width: '50vw' }} onHide={onHide}> | ||||
|         <div className="card flex justify-evenly py-5"> | ||||
|           <FloatLabel> | ||||
|             <InputText id="username" className='rounded-sm' value={name} onChange={(e) => setName(e.target.value)} /> | ||||
| @ -43,7 +64,9 @@ export default function CreationDialog({ groups, onCreate }: { groups: Group[], | ||||
|             } /> | ||||
|             <label htmlFor="group">Group</label> | ||||
|           </FloatLabel> | ||||
|           <button className={classNames('primary')} onClick={submitGuest} disabled={!(name.length > 0 && group)}>Create</button> | ||||
|           <button className={classNames('primary')} onClick={submitGuest} disabled={!(name.length > 0 && group)}> | ||||
|             {guest?.id !== undefined ? 'Update' : 'Create'} | ||||
|           </button> | ||||
|         </div> | ||||
|       </Dialog> | ||||
|     </> | ||||
| @ -5,12 +5,15 @@ | ||||
| import { destroyGuest, updateGuest } from '@/app/api/guests'; | ||||
| import { Guest, GuestStatus } from '@/app/lib/definitions'; | ||||
| import { classNames } from '@/app/ui/components/button'; | ||||
| import { PencilIcon, TrashIcon } from '@heroicons/react/24/outline'; | ||||
| import clsx from 'clsx'; | ||||
| import InlineTextField from '../components/form/inlineTextField'; | ||||
| import TableOfContents from '../components/table-of-contents'; | ||||
| import { TrashIcon } from '@heroicons/react/24/outline'; | ||||
| 
 | ||||
| export default function guestsTable({ guests, onUpdate }: { guests: Guest[], onUpdate: () => void }) { | ||||
| export default function guestsTable({ guests, onUpdate, onEdit }: { | ||||
|   guests: Guest[], | ||||
|   onUpdate: () => void, | ||||
|   onEdit: (guest: Guest) => void | ||||
| }) { | ||||
|   const handleGuestChange = (guest: Guest, status: GuestStatus) => { | ||||
|     guest.status = status; | ||||
|     updateGuest(guest).then(() => onUpdate()); | ||||
| @ -24,7 +27,7 @@ export default function guestsTable({ guests, onUpdate }: { guests: Guest[], onU | ||||
|       rowRender={(guest) => ( | ||||
|         <tr key={guest.id} className="bg-white border-b odd:bg-white odd:dark:bg-gray-900 even:bg-gray-50 even:dark:bg-gray-800"> | ||||
|           <td scope="row" className="px-6 py-4 font-medium text-gray-900 whitespace-nowrap dark:text-white"> | ||||
|             <InlineTextField initialValue={guest.name} onChange={(newName) => { guest.name = newName; updateGuest(guest) }} /> | ||||
|             {guest.name} | ||||
|           </td> | ||||
|           <td className="px-6 py-4"> | ||||
|             {guest.group_name} | ||||
| @ -58,6 +61,7 @@ export default function guestsTable({ guests, onUpdate }: { guests: Guest[], onU | ||||
|                 </> | ||||
|               )} | ||||
|               <TrashIcon className='size-6 cursor-pointer' onClick={() => { destroyGuest(guest, () => onUpdate()) }} /> | ||||
|               <PencilIcon className='size-6 cursor-pointer' onClick={() => onEdit(guest)} /> | ||||
|             </div> | ||||
|           </td> | ||||
|         </tr> | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user