diff --git a/src/page-modules/contact/group-travel/group-travel-state-machine.ts b/src/page-modules/contact/group-travel/group-travel-state-machine.ts new file mode 100644 index 00000000..12c8c60d --- /dev/null +++ b/src/page-modules/contact/group-travel/group-travel-state-machine.ts @@ -0,0 +1,132 @@ +import { assign, setup } from 'xstate'; + +export type ContextType = { + travelType: 'bus' | 'boat' | null; + formData: { + dateOfTravel: string; + line: string; + fromStop: string; + toStop: string; + departure: string; + returnInfo: string; + groupSize: string; + responsiblePerson: string; + phoneNumber: string; + }; +}; + +type GroupTravelEvents = + | { type: 'CHOOSE_BOAT' } + | { type: 'CHOOSE_BUS' } + | { type: 'SUBMIT'; formData: ContextType['formData'] }; + +export const groupTravelStateMachine = setup({ + types: { + context: {} as ContextType, + events: {} as GroupTravelEvents, + }, + guards: { + isFormValid: ({ context }) => { + const { + dateOfTravel, + line, + fromStop, + toStop, + groupSize, + responsiblePerson, + phoneNumber, + } = context.formData; + return ( + !!dateOfTravel && + !!line && + !!fromStop && + !!toStop && + !!groupSize && + !!responsiblePerson && + !!phoneNumber + ); + }, + }, + actions: { + navigateToErrorPage: () => { + window.location.href = '/contact/error'; + }, + navigateToSuccessPage: () => { + window.location.href = '/contact/success'; + }, + updatedFormData: assign(({ context, event }) => { + if (event.type !== 'SUBMIT') return context; + return { + formData: { + ...context.formData, + ...event.formData, + }, + }; + }), + showValidationErrors: (context) => { + console.log('Need to handle validation'); + }, + }, +}).createMachine({ + id: 'ticketControlForm', + initial: 'selectTravelType', + context: { + travelType: null, // 'bus' or 'boat' + formData: { + dateOfTravel: '', + line: '', + fromStop: '', + toStop: '', + departure: '', + returnInfo: '', + groupSize: '', + responsiblePerson: '', + phoneNumber: '', + }, + } as ContextType, + states: { + selectTravelType: { + on: { + CHOOSE_BOAT: { + target: 'boatInfo', + actions: assign({ travelType: 'boat' }), + }, + CHOOSE_BUS: { + target: 'busForm', + actions: assign({ travelType: 'bus' }), + }, + }, + }, + boatInfo: { + type: 'final', + }, + busForm: { + initial: 'editing', + states: { + editing: { + on: { + SUBMIT: [ + { + target: 'success', + guard: 'isFormValid', + actions: 'updatedFormData', + }, + { + target: 'editing', + actions: 'showValidationErrors', + }, + ], + }, + }, + success: { + entry: 'navigateToSuccessPage', + type: 'final', + }, + error: { + entry: 'navigateToErrorPage', + type: 'final', + }, + }, + }, + }, +}); diff --git a/src/page-modules/contact/group-travel/index.tsx b/src/page-modules/contact/group-travel/index.tsx new file mode 100644 index 00000000..d2e4c0dc --- /dev/null +++ b/src/page-modules/contact/group-travel/index.tsx @@ -0,0 +1,7 @@ +export default function GroupTravelContent() { + return ( +
+

Group travel content

+
+ ); +} diff --git a/src/pages/contact/group-travel.tsx b/src/pages/contact/group-travel.tsx new file mode 100644 index 00000000..49bbe9a7 --- /dev/null +++ b/src/pages/contact/group-travel.tsx @@ -0,0 +1,24 @@ +import DefaultLayout from '@atb/layouts/default'; +import { withGlobalData, WithGlobalData } from '@atb/layouts/global-data'; +import { NextPage } from 'next'; +import { + ContactPageLayout, + ContactPageLayoutProps, +} from '@atb/page-modules/contact'; +import GroupTravelContent from '@atb/page-modules/contact/group-travel'; + +export type GroupTravelPageProps = WithGlobalData; + +const GroupTravelPage: NextPage = (props) => { + return ( + + + + + + ); +}; + +export default GroupTravelPage; + +export const getServerSideProps = withGlobalData();