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