import { createMachine, EventObject, interpret, StateMachine, Typestate } from '@xstate/fsm'; import { RequestStatusFlow } from '../../interfaces'; import { GPS_COORDINATES } from '../constants' import { Element } from '../element' export const REQUEST_STATUS = { NEW: 'request_status_new', OPEN: 'request_status_open', IN_PROGRESS: 'request_status_in_progress', ON_HOLD: 'request_status_on_hold', CLOSED: 'request_status_closed', CANCELLED: 'request_status_cancelled', REJECTED: 'request_status_rejected', COMPLETED: 'request_status_completed', } export const REQUEST_APPROVAL_STATUS = { APPROVED: 'request_approved', NEEDS_CHANGES: 'request_needs_changes', REJECTED: 'request_rejected', } export class Request extends Element { static get TYPE() { return 'Request' } static get ATTRIBUTES() { return { ...Element.ATTRIBUTES, APPROVERS: 'approvers', ASSIGNEES: 'assignees', CHECKLIST: 'checklist', COORDINATES: GPS_COORDINATES, DESCRIPTION: 'description', ELEMENTS: 'elements', FILES: 'files', IS_INCOMPLETE: 'is_incomplete', REQUEST_APPROVAL_STATUS: 'request_approval_status', REQUEST_DUE_DATE: 'request_due_date', REQUEST_STATUS: 'request_status', EXPORT_EXECUTION: 'export_execution', EXPORT_RECIPIENT_EMAILS: 'export_recipient_emails', LISTING_CONFIG_ATE: 'listing_config_ate', LISTING_CONFIG_INLINE: 'listing_config_inline', REQUEST_IS_TEMPLATE: 'request_is_template', REQUEST_RECURRENCE: 'request_recurrence', } } static get SHORTNAME() { return 'Ticket' } } type State = string export type TicketStateMachine = StateMachine.Service> // Create a state machine for a given flow export const createTicketStateMachine = (flow: RequestStatusFlow, initialState: State): TicketStateMachine => { // Initialize states with all possible states const states: { [key: string]: { on: { [key: string]: State } } } = {}; Object.values(REQUEST_STATUS).forEach(state => { states[state] = { on: {} }; }); // Populate the 'on' objects for states that have transitions flow.transitions.forEach(transition => { states[transition.from].on[transition.name] = transition.to; }); // Add a custom event to set the state Object.keys(states).forEach(state => { states[state].on['SET_STATE'] = state; }); const machine = createMachine({ id: 'ticket', initial: initialState, // You can make this dynamic too, if needed states }); return interpret(machine); }; export const canTransition = (currentState: State, event: string, flow: RequestStatusFlow): boolean => { const validTransition = flow.transitions.find( t => t.from === currentState && t.name === event ); return Boolean(validTransition); };