import React, { useEffect, useReducer } from 'react' import { useRouter } from 'next/router' import { clearBookingData, loadBookingData } from '../helpers/storage' import { createBooking } from '../helpers/booking' import { Booking } from '../db/booking' export type BookFormData = Omit & { storeData?: boolean } type BookingProviderState = { postData?: boolean postDataError?: string postDataSuccess?: boolean formData: BookFormData formDataChanged: string[] booking?: Booking dataStored: boolean dataStoredLoaded: boolean } type BookProvider = { state: BookingProviderState dispatch: React.Dispatch onChange: (data: object) => void onChangeEvent: (event: React.ChangeEvent>) => void onSubmit: () => void forgetData: () => void } type BookAction = { type: string payload?: any } export const BookContext: React.Context = React.createContext< BookProvider >(null) export const ACTIONS = { SET_FORM_DATA: 'setFormData', POST_DATA: 'postData', POST_DATA_ERROR: 'postDataError', DATA_STORED: 'dataStored', DATA_STORED_LOADED: 'dataStoredLoaded', DATA_STORED_FORGOTTEN: 'dataStoredForgotten', } function reducer(state: BookingProviderState, action: BookAction) { switch (action.type) { case ACTIONS.SET_FORM_DATA: return { ...state, formData: { ...state.formData, ...action.payload, }, formDataChanged: [ ...state.formDataChanged, ...Object.keys(action.payload), ], } case ACTIONS.POST_DATA: return { ...state, postData: true, postDataError: null, postDataSuccess: null, } case ACTIONS.POST_DATA_ERROR: return { ...state, postData: false, postDataError: action.payload, postDataSuccess: null, } case ACTIONS.DATA_STORED_LOADED: return { ...state, dataStoredLoaded: true, formData: { ...state.formData, ...action.payload, }, } case ACTIONS.DATA_STORED_FORGOTTEN: return { ...state, dataStored: undefined, dataStoredLoaded: undefined, formData: { ...initialState.formData }, } case ACTIONS.DATA_STORED: return { ...state, dataStored: action.payload, } default: throw new Error(`Unkown Action type ${action.type}`) } } const initialState: BookingProviderState = { postData: false, postDataError: null, postDataSuccess: null, formData: { startDate: '', endDate: '', purpose: '', org: '', destination: '', name: '', email: '', phone: '', street: '', zip: '', city: '', }, formDataChanged: [], dataStored: undefined, dataStoredLoaded: undefined, } export default function BookProvider({ children }) { const router = useRouter() const [state, dispatch] = useReducer(reducer, initialState) useEffect(() => { const data = loadBookingData() if (data !== null) { dispatch({ type: ACTIONS.DATA_STORED_LOADED, payload: data }) } }, []) const onChangeEvent = ( event: React.ChangeEvent> ) => { const { name, value } = event.target dispatch({ type: ACTIONS.SET_FORM_DATA, payload: { [name]: value }, }) } const onChange = (data: object) => { dispatch({ type: ACTIONS.SET_FORM_DATA, payload: data, }) } const onSubmit = async () => { dispatch({ type: ACTIONS.POST_DATA }) try { const booking = await createBooking(state.formData) router.push(`/bookings/${booking.uuid}/stored`) } catch (error) { console.error(error) dispatch({ type: ACTIONS.POST_DATA_ERROR, payload: error.message }) } } const forgetData = () => { clearBookingData() dispatch({ type: ACTIONS.DATA_STORED_FORGOTTEN }) } return ( {children} ) }