Simplify guest edition by adding status to the dialog #112
| @ -25,7 +25,7 @@ export function updateGuest(guest: Guest) { | |||||||
|   return fetch(`/api/guests/${guest.id}`, |   return fetch(`/api/guests/${guest.id}`, | ||||||
|     { |     { | ||||||
|       method: 'PUT', |       method: 'PUT', | ||||||
|       body: JSON.stringify({ guest: { name: guest.name, status: guest.status } }), |       body: JSON.stringify({ guest: { name: guest.name, status: guest.status, group_id: guest.groupId } }), | ||||||
|       headers: { |       headers: { | ||||||
|         'Content-Type': 'application/json', |         'Content-Type': 'application/json', | ||||||
|         'X-CSRF-TOKEN': getCsrfToken(), |         'X-CSRF-TOKEN': getCsrfToken(), | ||||||
| @ -34,10 +34,10 @@ export function updateGuest(guest: Guest) { | |||||||
|     .catch((error) => console.error(error)); |     .catch((error) => console.error(error)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export function createGuest(name: string, group_id: string, onCreate?: () => void) { | export function createGuest(guest: Guest, onCreate?: () => void) { | ||||||
|   fetch("/api/guests", { |   fetch("/api/guests", { | ||||||
|     method: 'POST', |     method: 'POST', | ||||||
|     body: JSON.stringify({ name: name, group_id: group_id }), |     body: JSON.stringify({ name: guest.name, group_id: guest.groupId, status: guest.status }), | ||||||
|     headers: { |     headers: { | ||||||
|       'Content-Type': 'application/json', |       'Content-Type': 'application/json', | ||||||
|       'X-CSRF-TOKEN': getCsrfToken(), |       'X-CSRF-TOKEN': getCsrfToken(), | ||||||
|  | |||||||
| @ -18,7 +18,8 @@ export type Customer = { | |||||||
|   image_url: string; |   image_url: string; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| export type GuestStatus = 'considered' | 'invited' | 'confirmed' | 'declined' | 'tentative'; | export const guestStatuses = ['considered', 'invited', 'confirmed', 'declined', 'tentative'] as const; | ||||||
|  | export type GuestStatus = typeof guestStatuses[number]; | ||||||
| export type Guest = { | export type Guest = { | ||||||
|   id?: string; |   id?: string; | ||||||
|   name?: string; |   name?: string; | ||||||
|  | |||||||
| @ -16,6 +16,11 @@ export const getCsrfToken = () => { | |||||||
|       ?.split("=")[1] || 'unknown'; |       ?.split("=")[1] || 'unknown'; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // From https://stackoverflow.com/a/1026087/3607039
 | ||||||
|  | export const capitalize = (val:string) => { | ||||||
|  |   return String(val).charAt(0).toUpperCase() + String(val).slice(1); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| export const formatDateToLocal = ( | export const formatDateToLocal = ( | ||||||
|   dateStr: string, |   dateStr: string, | ||||||
|   locale: string = 'en-US', |   locale: string = 'en-US', | ||||||
|  | |||||||
| @ -3,7 +3,8 @@ | |||||||
| 'use client'; | 'use client'; | ||||||
| 
 | 
 | ||||||
| import { createGuest, updateGuest } from '@/app/api/guests'; | import { createGuest, updateGuest } from '@/app/api/guests'; | ||||||
| import { Group, Guest } from '@/app/lib/definitions'; | import { Group, Guest, GuestStatus, guestStatuses } from '@/app/lib/definitions'; | ||||||
|  | import { capitalize } from '@/app/lib/utils'; | ||||||
| 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,7 +12,7 @@ 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 GuestFormDialog({ groups, onCreate, onHide, guest, visible}: { | export default function GuestFormDialog({ groups, onCreate, onHide, guest, visible }: { | ||||||
|   groups: Group[], |   groups: Group[], | ||||||
|   onCreate?: () => void, |   onCreate?: () => void, | ||||||
|   onHide: () => void, |   onHide: () => void, | ||||||
| @ -21,26 +22,29 @@ export default function GuestFormDialog({ groups, onCreate, onHide, guest, visib | |||||||
| 
 | 
 | ||||||
|   const [name, setName] = useState(guest?.name || ''); |   const [name, setName] = useState(guest?.name || ''); | ||||||
|   const [group, setGroup] = useState(guest?.groupId || null); |   const [group, setGroup] = useState(guest?.groupId || null); | ||||||
|  |   const [status, setStatus] = useState<GuestStatus | null>(guest?.status || null); | ||||||
| 
 | 
 | ||||||
|   function resetForm() { |   function resetForm() { | ||||||
|     setName(''); |     setName(''); | ||||||
|     setGroup(null); |     setGroup(null); | ||||||
|  |     setStatus(null); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   function submitGuest() { |   function submitGuest() { | ||||||
|     if (!(name && group)) { |     if (!(name && group && status)) { | ||||||
|       return |       return | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (guest?.id !== undefined) { |     if (guest?.id !== undefined) { | ||||||
|       guest.name = name; |       guest.name = name; | ||||||
|       guest.groupId = group; |       guest.groupId = group; | ||||||
|  |       guest.status = status; | ||||||
|       updateGuest(guest).then(() => { |       updateGuest(guest).then(() => { | ||||||
|         resetForm(); |         resetForm(); | ||||||
|         onCreate && onCreate(); |         onCreate && onCreate(); | ||||||
|       }); |       }); | ||||||
|     } else { |     } else { | ||||||
|       createGuest(name, group, () => { |       guest && createGuest({name: name, groupId: group, status: status}, () => { | ||||||
|         resetForm(); |         resetForm(); | ||||||
|         onCreate && onCreate(); |         onCreate && onCreate(); | ||||||
|       }); |       }); | ||||||
| @ -64,7 +68,15 @@ export default function GuestFormDialog({ groups, onCreate, onHide, guest, visib | |||||||
|             } /> |             } /> | ||||||
|             <label htmlFor="group">Group</label> |             <label htmlFor="group">Group</label> | ||||||
|           </FloatLabel> |           </FloatLabel> | ||||||
|           <button className={classNames('primary')} onClick={submitGuest} disabled={!(name.length > 0 && group)}> |           <FloatLabel> | ||||||
|  |             <Dropdown id="status" className='rounded-sm min-w-32' value={status} onChange={(e) => setStatus(e.target.value)} options={ | ||||||
|  |               guestStatuses.map((status) => { | ||||||
|  |                 return { label: capitalize(status), value: status }; | ||||||
|  |               }) | ||||||
|  |             } /> | ||||||
|  |             <label htmlFor="status">Status</label> | ||||||
|  |           </FloatLabel> | ||||||
|  |           <button className={classNames('primary')} onClick={submitGuest} disabled={!(name.length > 0 && group && status)}> | ||||||
|             {guest?.id !== undefined ? 'Update' : 'Create'} |             {guest?.id !== undefined ? 'Update' : 'Create'} | ||||||
|           </button> |           </button> | ||||||
|         </div> |         </div> | ||||||
|  | |||||||
| @ -14,11 +14,6 @@ export default function guestsTable({ guests, onUpdate, onEdit }: { | |||||||
|   onUpdate: () => void, |   onUpdate: () => void, | ||||||
|   onEdit: (guest: Guest) => void |   onEdit: (guest: Guest) => void | ||||||
| }) { | }) { | ||||||
|   const handleGuestChange = (guest: Guest, status: GuestStatus) => { |  | ||||||
|     guest.status = status; |  | ||||||
|     updateGuest(guest).then(() => onUpdate()); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   return ( |   return ( | ||||||
|     <TableOfContents |     <TableOfContents | ||||||
|       headers={['Name', 'Group', 'Status', 'Actions']} |       headers={['Name', 'Group', 'Status', 'Actions']} | ||||||
| @ -50,16 +45,6 @@ export default function guestsTable({ guests, onUpdate, onEdit }: { | |||||||
|           </td> |           </td> | ||||||
|           <td> |           <td> | ||||||
|             <div className="flex flex-row items-center"> |             <div className="flex flex-row items-center"> | ||||||
|               {guest.status === 'considered' && (<button data-guest-id={guest.id} onClick={() => handleGuestChange(guest, 'invited')} className={classNames('blue')}> |  | ||||||
|                 Invite |  | ||||||
|               </button>)} |  | ||||||
|               {(guest.status === 'invited' || guest.status === 'tentative') && ( |  | ||||||
|                 <> |  | ||||||
|                   <button data-guest-id={guest.id} onClick={() => handleGuestChange(guest, 'confirmed')} className={classNames('green')}>Confirm</button> |  | ||||||
|                   {guest.status != 'tentative' && <button data-guest-id={guest.id} onClick={() => handleGuestChange(guest, 'tentative')} className={classNames('yellow')}>Tentative</button>} |  | ||||||
|                   <button data-guest-id={guest.id} onClick={() => handleGuestChange(guest, 'declined')} className={classNames('red')}>Decline</button> |  | ||||||
|                 </> |  | ||||||
|               )} |  | ||||||
|               <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)} /> |               <PencilIcon className='size-6 cursor-pointer' onClick={() => onEdit(guest)} /> | ||||||
|             </div> |             </div> | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user