UNPKG

portal-www

Version:

Nova Portal Website. Based on Next starter by Ueno

245 lines (232 loc) 6.06 kB
import { Machine, assign } from 'xstate'; import { isPast } from 'date-fns'; type periodInput = { variables: { input: { subscriptionId: string, periodEnd: Date | null, }, }, }; interface IPeriodMachineContext { subscriptionId: string; selectedDay: Date | null; nextDueDate: Date | null; calculatedPeriods: [any] | []; getPeriods: () => any; newPeriod: (({ }: periodInput) => any); calculatePeriods: ({ }: periodInput) => any; error: string | null; } const periodMachine = Machine<IPeriodMachineContext, any>( { id: 'periodMachine', initial: 'initialize', states: { initialize: { invoke: { id: 'invokeGetPeriods', src: (context, _) => { return context.getPeriods(); }, }, on: { SUCCESS: { actions: 'setNextDueDate', target: 'editing', }, ERROR: { actions: 'setError', target: 'error', }, }, }, editing: { on: { CONFIRM: { target: 'setNewPeriod', cond: 'canConfirm', }, 'selectedDay.UPDATE': [ { actions: 'updateSelectedDay', target: 'calculate', cond: 'validEdit', }, { actions: 'updateSelectedDay', }, ], }, }, calculate: { initial: 'calculating', states: { calculating: { invoke: { id: 'calculatePeriods', src: (context, _) => { return context.calculatePeriods({ variables: { input: { subscriptionId: context.subscriptionId, periodEnd: context.selectedDay, }, }, }); }, onDone: { actions: 'calculatePeriodsResult', target: 'done', }, onError: { actions: 'setError', target: '#periodMachine.error', }, }, }, done: { always: [ { target: '#periodMachine.editing', cond: 'notError' }, { target: '#periodMachine.error', cond: 'isError' }, ], }, }, }, setNewPeriod: { initial: 'settingNewPeriod', states: { settingNewPeriod: { invoke: { id: 'setNewPeriodInvoke', src: (context, _) => { return context.newPeriod({ variables: { input: { subscriptionId: context.subscriptionId, periodEnd: context.selectedDay, }, }, }); }, onDone: { actions: 'setNewPeriodResult', target: 'done', }, onError: { actions: 'setError', target: '#periodMachine.error', }, }, }, done: { always: [ { target: '#periodMachine.success', cond: 'notError' }, { target: '#periodMachine.error', cond: 'isError' }, ], }, }, }, success: { on: { RESET: { actions: 'reset', target: 'initialize', }, }, }, error: { on: { RESET: { actions: 'reset', target: 'initialize', }, }, }, }, }, { actions: { updateSelectedDay: assign({ selectedDay: (_, event) => { return event.value ? event.value : null; }, }), setNextDueDate: assign( (_context, event) => { const res = ((periods) => { const newestPeriod = periods?.[0]; if (!newestPeriod || isPast?.(new Date(newestPeriod?.periodEnd))) { return null; } if (newestPeriod?.status === 'Paid') { return new Date(newestPeriod?.periodEnd); } return new Date(newestPeriod?.periodStart); })(event.value); return { nextDueDate: res, }; }, ), calculatePeriodsResult: assign( (_context, event) => { if (event?.data?.data?.calculatePeriods?.data) { return { calculatedPeriods: event?.data?.data?.calculatePeriods?.data ?? [], error: null, }; } return { calculatedPeriods: [], error: event?.data?.data?.calculatePeriods?.error.message, }; }, ), setNewPeriodResult: assign( (_context, event) => { if (event?.data?.data?.changeSubscriptionPeriod?.error) { return { error: event?.data?.data?.changeSubscriptionPeriod?.error?.message, }; } return { error: null, }; }, ), setError: assign( (_context, event) => { const error = event?.data?.message ?? event.value; return { error, }; }, ), reset: assign( (_context, _event) => { return { selectedDay: null, error: null, nextDueDate: null, calculatedPeriods: [], }; }, ), }, guards: { validEdit: (_context, event) => { return !!event.value; }, canConfirm: (context, _event) => { return !!context.selectedDay; }, isError: (context, _event) => { return !!context.error; }, notError: (context, _event) => { return !context.error; }, }, }); export { periodMachine };