diff --git a/src/app/harbor/tabs/tabs.tsx b/src/app/harbor/tabs/tabs.tsx index 99e8c1b8..9e7637f5 100644 --- a/src/app/harbor/tabs/tabs.tsx +++ b/src/app/harbor/tabs/tabs.tsx @@ -226,7 +226,7 @@ export default function Harbor({ { name: <>Tavern 🍻, path: 'tavern', - component: , + component: , //, // component: process.env.NEXT_PUBLIC_LOW_RATE_LIMIT ? ( // // ) : ( diff --git a/src/app/harbor/tavern/tavern-utils.ts b/src/app/harbor/tavern/tavern-utils.ts index 8f53ba79..ab66623b 100644 --- a/src/app/harbor/tavern/tavern-utils.ts +++ b/src/app/harbor/tavern/tavern-utils.ts @@ -1,6 +1,11 @@ 'use server' import { getSession } from '@/app/utils/auth' +import { + setTavernRsvpStatus, + submitMyTavernLocation, + submitShirtSize, +} from '@/app/utils/tavern' import Airtable from 'airtable' Airtable.configure({ @@ -8,7 +13,7 @@ Airtable.configure({ endpointUrl: process.env.AIRTABLE_ENDPOINT_URL, }) -type RsvpStatus = 'none' | 'organizer' | 'participant' +export type RsvpStatus = 'none' | 'organizer' | 'participant' export type TavernPersonItem = { status: RsvpStatus coordinates: string @@ -102,3 +107,19 @@ export const getTavernEvents = async () => { lastEventsFetch = Date.now() return items } + +export async function rspvForTavern(formData: FormData) { + let res = { success: true, error: null } + + await Promise.all([ + setTavernRsvpStatus(formData.get('rsvp') as RsvpStatus), + submitMyTavernLocation(formData.get('tavern') as string), + submitShirtSize(formData.get('shirt') as string), + ]).catch((error) => { + console.error('Error submitting tavern RSVP', error) + res = { success: false, error: error.toString() } + }) + + console.log('Successfully saved tavern RSVP') + return JSON.stringify(res) +} diff --git a/src/app/harbor/tavern/tavern.tsx b/src/app/harbor/tavern/tavern.tsx index 231b07a9..a5a6b1b0 100644 --- a/src/app/harbor/tavern/tavern.tsx +++ b/src/app/harbor/tavern/tavern.tsx @@ -15,8 +15,10 @@ import dynamic from 'next/dynamic' import { getTavernEvents, getTavernPeople, + rspvForTavern, TavernEventItem, TavernPersonItem, + RsvpStatus, } from './tavern-utils' import Modal from '@/components/ui/modal' import { Button } from '@/components/ui/button' @@ -27,63 +29,77 @@ const Map = dynamic(() => import('./map'), { ssr: false, }) -const RsvpStatusSwitcher = ({ tavernEvents, onTavernSelect }) => { - const [rsvpStatus, setRsvpStatus] = useLocalStorageState( - 'cache.rsvpStatus', - 'none', - ) - const [whichTavern, setWhichTavern] = useLocalStorageState( - 'cache.whichTavern', - 'none', - ) - const [shirtSize, setShirtSize] = useLocalStorageState( - 'cache.shirtSize', - 'none', - ) +type TavernDatafetchCategory = + | 'rsvpStatus' + | 'tavernEvents' + | 'myTavernLocation' + | 'tavernPeople' + | 'shirtSize' + +const RsvpStatusSwitcher = ({ + rsvpStatus, + setRsvpStatus, + tavernEvents, + selectedTavern, + setSelectedTavern, + shirtSize, + setShirtSize, + erroredFetches, +}: { + rsvpStatus: RsvpStatus + setRsvpStatus: (status: RsvpStatus) => void + tavernEvents: TavernEventItem[] + selectedTavern: TavernEventItem | null + setSelectedTavern: (tavernId: string | null) => void + shirtSize: any + setShirtSize: (size: string) => void + erroredFetches: TavernDatafetchCategory[] +}) => { + const [editedFlag, setEditedFlag] = useState(false) const [attendeeNoOrganizerModal, setAttendeeNoOrganizerModal] = useState(false) const { toast } = useToast() - useEffect(() => { - toast({ - title: 'Saved', - description: - editMessages[Math.floor(Math.random() * editMessages.length)], - }) - }, [rsvpStatus, whichTavern, shirtSize]) - useEffect(() => { - // set rsvp status - getTavernRsvpStatus().then((status) => setRsvpStatus(status)) - getShirtSize().then((ss) => setShirtSize(ss)) - }, []) + // useEffect(() => { + // toast({ + // title: 'Saved', + // description: + // editMessages[Math.floor(Math.random() * editMessages.length)], + // }) + // }, [rsvpStatus, whichTavern, shirtSize]) - const onOptionChangeHandler = (e) => { - const status = e.target.value - setRsvpStatus(status) - setTavernRsvpStatus(status) + // useEffect(() => { + // // set rsvp status + // getShirtSize().then((ss) => setShirtSize(ss)) + // }, []) - if (status !== 'participant' && status !== 'organizer') { - setWhichTavern('none') - submitMyTavernLocation(null) - onTavernSelect(null) - } - } + // const onOptionChangeHandler = (e) => { + // const status = e.target.value + // setRsvpStatus(status) + // setTavernRsvpStatus(status) - const onTavernChangeHandler = (event) => { - const tavernId = event.target.value - setWhichTavern(tavernId) - submitMyTavernLocation(tavernId).catch(console.error) - onTavernSelect(tavernId) - - if ( - rsvpStatus === 'participant' && - tavernEvents.find((te) => te.id === tavernId).organizers.length === 0 - ) { - console.log('u shoiuld vhe an organizer') - setAttendeeNoOrganizerModal(true) - } - } + // if (status !== 'participant' && status !== 'organizer') { + // setWhichTavern('none') + // submitMyTavernLocation(null) + // onTavernSelect(null) + // } + // } + + // const onTavernChangeHandler = (event) => { + // const tavernId = event.target.value + // setWhichTavern(tavernId) + // submitMyTavernLocation(tavernId).catch(console.error) + // onTavernSelect(tavernId) + + // if ( + // rsvpStatus === 'participant' && + // tavernEvents.find((te) => te.id === tavernId).organizers.length === 0 + // ) { + // console.log('u shoiuld vhe an organizer') + // setAttendeeNoOrganizerModal(true) + // } + // } const eventsByCountry = tavernEvents.reduce((acc, event) => { const country = event.locality.split(', ').at(-1) @@ -110,25 +126,154 @@ const RsvpStatusSwitcher = ({ tavernEvents, onTavernSelect }) => {
Please consider volunteering to organize this tavern, me hearty! -
{ + const rsvpResponse = JSON.parse(await rspvForTavern(formData)) + + if (rsvpResponse.success) { + toast({ + title: 'Saved', + description: + editMessages[Math.floor(Math.random() * editMessages.length)], + }) + } else { + toast({ + title: 'Error', + description: `Failed to save your changes:\n${rsvpResponse.error}`, + }) + } + }} + className="flex flex-col justify-items-stretch" + > + {erroredFetches.includes('rsvpStatus') ? ( +

+ Failed to load your current RSVP status. +

+ ) : !rsvpStatus ? ( +

Loading RSVP status selection...

+ ) : ( + <> + + + {rsvpStatus === 'participant' || rsvpStatus === 'organizer' ? ( + <> +
+ {erroredFetches.includes('tavernEvents') ? ( +

+ Failed to fetch tavern events +

+ ) : erroredFetches.includes('myTavernLocation') ? ( +

+ Failed to fetch your tavern location +

+ ) : !tavernEvents || !selectedTavern ? ( +

Loading tavern events selection...

+ ) : ( + + )} +
+ +
+ {erroredFetches.includes('shirtSize') ? ( +

+ Failed to fetch your shirt size +

+ ) : !shirtSize ? ( +

Loading shirt size selection...

+ ) : ( + + )} +
+ + ) : null} + + )} + +
+ {editedFlag ? ( +

You have unsaved changes!

+ ) : null} + + +
+ + + {/*
- + {tavernEvents && (rsvpStatus === 'participant' || rsvpStatus === 'organizer') ? ( @@ -178,29 +323,67 @@ const RsvpStatusSwitcher = ({ tavernEvents, onTavernSelect }) => { ) : null} -
+
*/} ) } export default function Tavern() { + const [rsvpStatus, setRsvpStatus] = useLocalStorageState( + 'cache.rsvpStatus', + 'none', + ) const [tavernPeople, setTavernPeople] = useState([]) const [tavernEvents, setTavernEvents] = useState([]) const [selectedTavern, setSelectedTavern] = useState( null, ) + const [shirtSize, setShirtSize] = useLocalStorageState( + 'cache.shirtSize', + 'none', + ) + const [erroredFetches, setErroredFetches] = useState< + TavernDatafetchCategory[] + >([]) useEffect(() => { - Promise.all([ - getTavernPeople(), - getTavernEvents(), - getMyTavernLocation(), - ]).then(([tp, te, myTavernLocation]) => { - setTavernPeople(tp) - setTavernEvents(te) - setSelectedTavern(myTavernLocation) - console.log("ARRR TH TAVERN YE BE GOEN T' BE", myTavernLocation) - }) + getTavernRsvpStatus() + .then((d) => { + console.log({ travernrspv: d }) + setRsvpStatus(d) + }) + .catch((err: Error) => { + console.error(err) + setErroredFetches((p) => [...p, 'rsvpStatus']) + }) + + getTavernEvents() + .then(setTavernEvents) + .catch((err: Error) => { + console.error(err) + setErroredFetches((p) => [...p, 'tavernEvents']) + }) + + getMyTavernLocation() + .then(setSelectedTavern) + .catch((err: Error) => { + console.error(err) + setErroredFetches((p) => [...p, 'myTavernLocation']) + }) + + getTavernPeople() + .then(setTavernPeople) + .catch((err: Error) => { + console.error(err) + setErroredFetches((p) => [...p, 'tavernPeople']) + }) + + getShirtSize() + .then(setShirtSize) + .catch((err: Error) => { + console.error(err) + setErroredFetches((p) => [...p, 'shirtSize']) + }) }, []) const handleTavernSelect = (tavernId: string | null) => { @@ -262,8 +445,14 @@ export default function Tavern() {

{selectedTavern?.eventDate ? ( @@ -289,11 +478,27 @@ export default function Tavern() {

) : null} - + {erroredFetches.includes('tavernEvents') ? ( +

+ Failed to load tavern events for the tavern map. +

+ ) : erroredFetches.includes('myTavernLocation') ? ( +

+ Failed to load your chosen tavern location for the tavern map. +

+ ) : erroredFetches.includes('tavernPeople') ? ( +

+ Failed to load tavern people for the tavern map. +

+ ) : !tavernEvents || !tavernPeople ? ( +

Loading tavern map...

+ ) : ( + + )} ) diff --git a/src/app/utils/tavern.ts b/src/app/utils/tavern.ts index 1a607e3f..f33227bb 100644 --- a/src/app/utils/tavern.ts +++ b/src/app/utils/tavern.ts @@ -9,7 +9,7 @@ Airtable.configure({ endpointUrl: process.env.AIRTABLE_ENDPOINT_URL, }) -type RsvpStatus = 'none' | 'organizer' | 'participant' +export type RsvpStatus = 'none' | 'organizer' | 'participant' export const setTavernRsvpStatus = async (rsvpStatus: RsvpStatus) => { // check auth const session = await getSession()