@servicetitan/dte-unlayer 0.154.0 → 0.155.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/dist/display-conditions/ConditionRow.d.ts.map +1 -1
  2. package/dist/display-conditions/ConditionRow.js +111 -95
  3. package/dist/display-conditions/ConditionRow.js.map +1 -1
  4. package/dist/display-conditions/DisplayConditionModal.d.ts +3 -3
  5. package/dist/display-conditions/DisplayConditionModal.d.ts.map +1 -1
  6. package/dist/display-conditions/DisplayConditionModal.js +8 -95
  7. package/dist/display-conditions/DisplayConditionModal.js.map +1 -1
  8. package/dist/display-conditions/useConditionForms.d.ts +22 -0
  9. package/dist/display-conditions/useConditionForms.d.ts.map +1 -0
  10. package/dist/display-conditions/useConditionForms.js +110 -0
  11. package/dist/display-conditions/useConditionForms.js.map +1 -0
  12. package/dist/e-sign-offset/ESignDateSignedOffsetModal.d.ts +11 -0
  13. package/dist/e-sign-offset/ESignDateSignedOffsetModal.d.ts.map +1 -0
  14. package/dist/e-sign-offset/ESignDateSignedOffsetModal.js +192 -0
  15. package/dist/e-sign-offset/ESignDateSignedOffsetModal.js.map +1 -0
  16. package/dist/e-sign-offset/ESignOffsetRuleRow.d.ts +20 -0
  17. package/dist/e-sign-offset/ESignOffsetRuleRow.d.ts.map +1 -0
  18. package/dist/e-sign-offset/ESignOffsetRuleRow.js +87 -0
  19. package/dist/e-sign-offset/ESignOffsetRuleRow.js.map +1 -0
  20. package/dist/e-sign-offset/eSignOffsetController.d.ts +10 -0
  21. package/dist/e-sign-offset/eSignOffsetController.d.ts.map +1 -0
  22. package/dist/e-sign-offset/eSignOffsetController.js +27 -0
  23. package/dist/e-sign-offset/eSignOffsetController.js.map +1 -0
  24. package/dist/editor-core-source.d.ts +2 -2
  25. package/dist/editor-core-source.d.ts.map +1 -1
  26. package/dist/editor-core-source.js +2 -2
  27. package/dist/editor-core-source.js.map +1 -1
  28. package/dist/editor.d.ts.map +1 -1
  29. package/dist/editor.js +8 -0
  30. package/dist/editor.js.map +1 -1
  31. package/dist/shared/const.d.ts +30 -0
  32. package/dist/shared/const.d.ts.map +1 -1
  33. package/dist/shared/const.js +5 -0
  34. package/dist/shared/const.js.map +1 -1
  35. package/dist/shared/e-sign-offset.d.ts +21 -0
  36. package/dist/shared/e-sign-offset.d.ts.map +1 -0
  37. package/dist/shared/e-sign-offset.js +130 -0
  38. package/dist/shared/e-sign-offset.js.map +1 -0
  39. package/dist/store.d.ts +1 -0
  40. package/dist/store.d.ts.map +1 -1
  41. package/dist/store.js +30 -3
  42. package/dist/store.js.map +1 -1
  43. package/dist/tools.d.ts +6 -0
  44. package/dist/tools.d.ts.map +1 -1
  45. package/dist/tools.js +21 -1
  46. package/dist/tools.js.map +1 -1
  47. package/package.json +1 -1
  48. package/src/__tests__/e-sign-offset.test.ts +281 -0
  49. package/src/display-conditions/ConditionRow.tsx +86 -81
  50. package/src/display-conditions/DisplayConditionModal.tsx +12 -116
  51. package/src/display-conditions/useConditionForms.ts +146 -0
  52. package/src/e-sign-offset/ESignDateSignedOffsetModal.tsx +197 -0
  53. package/src/e-sign-offset/ESignOffsetRuleRow.tsx +101 -0
  54. package/src/e-sign-offset/eSignOffsetController.ts +39 -0
  55. package/src/editor-core-source.ts +2 -2
  56. package/src/editor.tsx +9 -0
  57. package/src/shared/const.ts +37 -0
  58. package/src/shared/e-sign-offset.ts +173 -0
  59. package/src/store.ts +45 -4
  60. package/src/tools.ts +36 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/display-conditions/DisplayConditionModal.tsx"],"sourcesContent":["import { Button, Combobox, Dialog, Flex, Text, ThemeProvider } from '@servicetitan/anvil2';\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { createPortal } from 'react-dom';\nimport {\n buildFormFieldKey,\n FormFieldInfo,\n FormInfo,\n getConditionalFieldTypeFromFormItemType,\n parseFormFieldKey,\n} from '../shared/forms';\nimport { ConditionGroupsSection, MatchType } from './ConditionGroupsSection';\nimport { defaultState, MODAL_CONTENT_MAX_HEIGHT } from './constants';\nimport { DisplayConditionRequest, onDisplayCondition } from './displayConditionController';\nimport { buildUnlayerDisplayCondition, parseUnlayerDisplayCondition } from './nunjucks';\nimport { getSchemaDataPointOptions } from './schemaDataPoints';\nimport {\n ConditionGroup as ConditionGroupType,\n DisplayBehavior,\n DisplayConditionState,\n FormFieldOption,\n LogicalOperator,\n} from './types';\n\nconst BEHAVIOR_OPTIONS = [\n { label: 'Show', value: 'show' },\n { label: 'Hide', value: 'hide' },\n] as const;\nconst NUMERIC_VALUE_RE = /^-?(?:\\d+\\.?\\d*|\\.\\d+)$/;\ntype BehaviorOption = (typeof BEHAVIOR_OPTIONS)[number];\n\nfunction deriveMatchType(conditionState: DisplayConditionState): MatchType {\n const firstGroup = conditionState.groups[0];\n if (!firstGroup || firstGroup.conditions.length <= 1) {\n return 'all';\n }\n const hasOr = firstGroup.conditions.some(c => c.logicalOperator === 'or');\n return hasOr ? 'any' : 'all';\n}\n\nfunction applyMatchTypeToState(\n conditionState: DisplayConditionState,\n matchType: MatchType,\n): DisplayConditionState {\n const logicalOp: LogicalOperator = matchType === 'all' ? 'and' : 'or';\n return {\n ...conditionState,\n groups: conditionState.groups.map((group, groupIndex) => {\n if (groupIndex !== 0) {\n return group;\n }\n return {\n ...group,\n conditions: group.conditions.map((c, i) =>\n i === 0 ? c : { ...c, logicalOperator: logicalOp },\n ),\n };\n }),\n };\n}\n\nexport interface DisplayConditionModalProps {\n /**\n * Optional portal target. Prefer leaving unset so the dialog stays under the host\n * `AnvilProvider` (`.anvil2` CSS scope). When set (e.g. a host-controlled container),\n * content is wrapped in `ThemeProvider` so Anvil2 styles still apply after portaling.\n */\n portalContainer?: Element | DocumentFragment | null;\n onConditionFormSelect?: (\n formId: number,\n sendFormFields: (formId: number, fields: FormFieldInfo[]) => void,\n ) => void;\n onConditionalsOpen?: (\n usedFormIds: number[],\n sendFormList: (forms: FormInfo[]) => void,\n sendFormFields: (formId: number, fields: FormFieldInfo[]) => void,\n ) => void;\n schema?: import('../shared/schema').SchemaObject;\n}\n\nexport const DisplayConditionModal = (props: DisplayConditionModalProps) => {\n const {\n onConditionFormSelect,\n onConditionalsOpen,\n portalContainer: portalContainerProp,\n schema,\n } = props;\n const [request, setRequest] = useState<DisplayConditionRequest | null>(null);\n const [isOpen, setIsOpen] = useState(false);\n const [state, setState] = useState(defaultState);\n const [matchType, setMatchType] = useState<MatchType>('all');\n const [forms, setForms] = useState<FormInfo[]>([]);\n const [formFieldsByFormId, setFormFieldsByFormId] = useState<Record<number, FormFieldInfo[]>>(\n {},\n );\n const [loadingFormIds, setLoadingFormIds] = useState<number[]>([]);\n const [isFormsListLoading, setIsFormsListLoading] = useState(false);\n const formFieldsByFormIdRef = useRef<Record<number, FormFieldInfo[]>>({});\n const loadingFormIdsRef = useRef<number[]>([]);\n\n const dataPointOptions = useMemo(() => getSchemaDataPointOptions(schema), [schema]);\n const formFieldOptions = useMemo<FormFieldOption[]>(() => {\n const nextOptions: FormFieldOption[] = [];\n for (const form of forms) {\n const fields = formFieldsByFormId[form.id];\n if (!fields) {\n continue;\n }\n for (const field of fields) {\n const fieldType = getConditionalFieldTypeFromFormItemType(field.itemType);\n if (!fieldType) {\n continue;\n }\n nextOptions.push({\n fieldType,\n formId: form.id,\n fullKey: buildFormFieldKey(form.id, field.id),\n title: field.header,\n });\n }\n }\n return nextOptions.sort((left, right) => left.title.localeCompare(right.title));\n }, [forms, formFieldsByFormId]);\n const allFieldOptions = useMemo(\n () => [...dataPointOptions, ...formFieldOptions],\n [dataPointOptions, formFieldOptions],\n );\n const isFieldDataLoading = isFormsListLoading || loadingFormIds.length > 0;\n\n useEffect(() => {\n formFieldsByFormIdRef.current = formFieldsByFormId;\n }, [formFieldsByFormId]);\n\n useEffect(() => {\n loadingFormIdsRef.current = loadingFormIds;\n }, [loadingFormIds]);\n\n const requestFormFields = useCallback(\n (formId: number) => {\n if (!onConditionFormSelect) {\n return;\n }\n if (\n formFieldsByFormIdRef.current[formId] ||\n loadingFormIdsRef.current.includes(formId)\n ) {\n return;\n }\n\n setLoadingFormIds(prev => (prev.includes(formId) ? prev : [...prev, formId]));\n onConditionFormSelect(formId, (selectedFormId, fields) => {\n setFormFieldsByFormId(prev => ({ ...prev, [selectedFormId]: fields }));\n setLoadingFormIds(prev => prev.filter(id => id !== selectedFormId));\n });\n },\n [onConditionFormSelect],\n );\n\n useEffect(() => {\n return onDisplayCondition(nextRequest => {\n setRequest(nextRequest);\n const existing = nextRequest.data;\n const parsed = parseUnlayerDisplayCondition(existing);\n const initialState = parsed ?? defaultState();\n const usedFormIds = Array.from(\n new Set(\n initialState.groups\n .flatMap(group => group.conditions)\n .map(condition => parseFormFieldKey(condition.dataPointKey)?.formId)\n .filter((formId): formId is number => formId != null),\n ),\n );\n\n setForms([]);\n setFormFieldsByFormId({});\n setIsFormsListLoading(!!onConditionalsOpen);\n setLoadingFormIds([]);\n\n if (onConditionalsOpen) {\n onConditionalsOpen(\n usedFormIds,\n nextForms => {\n setForms(nextForms);\n setIsFormsListLoading(false);\n },\n (formId, fields) => {\n setFormFieldsByFormId(prev => ({ ...prev, [formId]: fields }));\n setLoadingFormIds(prev => prev.filter(id => id !== formId));\n },\n );\n\n /*\n * Keep display-condition flow aligned with calculated-field flow:\n * when modal opens, request fields for already-used forms so labels\n * are available in edit mode.\n */\n usedFormIds.forEach(formId => requestFormFields(formId));\n } else {\n setIsFormsListLoading(false);\n setLoadingFormIds([]);\n }\n\n setState(initialState);\n setMatchType(deriveMatchType(initialState));\n setIsOpen(true);\n });\n }, [onConditionalsOpen, requestFormFields]);\n\n const handleClose = useCallback(() => {\n setRequest(null);\n setIsOpen(false);\n }, []);\n\n const handleSave = useCallback(() => {\n if (!request) {\n return;\n }\n const finalState = applyMatchTypeToState(state, matchType);\n const condition = buildUnlayerDisplayCondition(finalState);\n if (condition) {\n request.done(condition);\n } else {\n request.done(null);\n }\n setRequest(null);\n setIsOpen(false);\n }, [matchType, request, state]);\n\n const updateGroup = useCallback((index: number, group: ConditionGroupType) => {\n setState(prev => {\n const next = [...prev.groups];\n next[index] = group;\n return { ...prev, groups: next };\n });\n }, []);\n\n const selectedBehavior = useMemo(\n () => BEHAVIOR_OPTIONS.find(opt => opt.value === state.behavior) ?? BEHAVIOR_OPTIONS[0],\n [state.behavior],\n );\n\n const handleBehaviorChange = useCallback((item: BehaviorOption | null) => {\n if (item) {\n setState(prev => ({ ...prev, behavior: item.value as DisplayBehavior }));\n }\n }, []);\n\n const handleFormSelect = useCallback(\n (formId: number) => {\n requestFormFields(formId);\n },\n [requestFormFields],\n );\n\n const canSave = useMemo(() => {\n if (isFieldDataLoading) {\n return false;\n }\n for (const group of state.groups) {\n for (const condition of group.conditions) {\n if (!condition.dataPointKey) {\n return false;\n }\n if (condition.operator === 'is_empty' || condition.operator === 'is_not_empty') {\n continue;\n }\n const trimmedValue = condition.value.trim();\n if (!trimmedValue) {\n return false;\n }\n const fieldType =\n allFieldOptions.find(opt => opt.fullKey === condition.dataPointKey)\n ?.fieldType ?? 'string';\n if (fieldType === 'number' && !NUMERIC_VALUE_RE.test(trimmedValue)) {\n return false;\n }\n }\n }\n return state.groups.length > 0;\n }, [allFieldOptions, isFieldDataLoading, state.groups]);\n\n if (!isOpen) {\n return null;\n }\n\n /*\n * Render in-place by default (same as pdf-editor). Anvil2 3.x CSS is nested under\n * `.anvil2`; portaling to `document.body` / bare shadow root drops that ancestor and\n * styles disappear in MFE prod. Native `<dialog>` top-layer still stacks correctly.\n */\n const dialog = (\n <Dialog open={isOpen} onClose={handleClose} size=\"xlarge\">\n <Dialog.Header>Conditions</Dialog.Header>\n <Dialog.Content>\n <Flex\n direction=\"column\"\n gap=\"4\"\n style={{\n maxHeight: MODAL_CONTENT_MAX_HEIGHT,\n overflowY: 'auto',\n paddingRight: 8,\n width: '100%',\n }}\n >\n <ConditionGroupsSection\n behaviorSection={\n <Flex\n direction=\"row\"\n alignItems=\"center\"\n gap=\"2\"\n style={{ flexWrap: 'wrap' }}\n >\n <Text size=\"small\" subdued variant=\"body\">\n Select to include or exclude selected template/file.\n </Text>\n <div style={{ width: 90 }}>\n <Combobox.Select\n disableClearSelection\n itemToKey={(item: BehaviorOption | null) =>\n item?.value ?? ''\n }\n itemToString={(item: BehaviorOption | null) =>\n item?.label ?? ''\n }\n items={[...BEHAVIOR_OPTIONS]}\n selectedItem={selectedBehavior}\n onChange={handleBehaviorChange}\n >\n <Combobox.SelectTrigger\n label=\"\"\n placeholder=\"Select...\"\n size=\"small\"\n />\n <Combobox.Content>\n {({\n items,\n }: {\n items: BehaviorOption[];\n }) => (\n <Combobox.List>\n {items.map((item, i) => (\n <Combobox.Item\n index={i}\n item={item}\n key={item.value}\n >\n {item.label}\n </Combobox.Item>\n ))}\n </Combobox.List>\n )}\n </Combobox.Content>\n </Combobox.Select>\n </div>\n </Flex>\n }\n dataPointOptions={dataPointOptions}\n formFieldOptions={formFieldOptions}\n forms={forms}\n groups={state.groups}\n matchType={matchType}\n onFormSelect={handleFormSelect}\n onMatchTypeChange={setMatchType}\n onUpdateGroup={updateGroup}\n />\n </Flex>\n </Dialog.Content>\n <Dialog.Footer sticky>\n <Flex\n justifyContent=\"flex-end\"\n alignItems=\"center\"\n gap=\"3\"\n style={{ width: '100%' }}\n >\n <Button appearance=\"secondary\" onClick={handleClose}>\n Cancel\n </Button>\n <Button appearance=\"primary\" disabled={!canSave} onClick={handleSave}>\n Save Changes\n </Button>\n </Flex>\n </Dialog.Footer>\n </Dialog>\n );\n\n if (portalContainerProp) {\n return createPortal(<ThemeProvider>{dialog}</ThemeProvider>, portalContainerProp);\n }\n\n return dialog;\n};\n"],"names":["Button","Combobox","Dialog","Flex","Text","ThemeProvider","useCallback","useEffect","useMemo","useRef","useState","createPortal","buildFormFieldKey","getConditionalFieldTypeFromFormItemType","parseFormFieldKey","ConditionGroupsSection","defaultState","MODAL_CONTENT_MAX_HEIGHT","onDisplayCondition","buildUnlayerDisplayCondition","parseUnlayerDisplayCondition","getSchemaDataPointOptions","BEHAVIOR_OPTIONS","label","value","NUMERIC_VALUE_RE","deriveMatchType","conditionState","firstGroup","groups","conditions","length","hasOr","some","c","logicalOperator","applyMatchTypeToState","matchType","logicalOp","map","group","groupIndex","i","DisplayConditionModal","props","onConditionFormSelect","onConditionalsOpen","portalContainer","portalContainerProp","schema","request","setRequest","isOpen","setIsOpen","state","setState","setMatchType","forms","setForms","formFieldsByFormId","setFormFieldsByFormId","loadingFormIds","setLoadingFormIds","isFormsListLoading","setIsFormsListLoading","formFieldsByFormIdRef","loadingFormIdsRef","dataPointOptions","formFieldOptions","nextOptions","form","fields","id","field","fieldType","itemType","push","formId","fullKey","title","header","sort","left","right","localeCompare","allFieldOptions","isFieldDataLoading","current","requestFormFields","includes","prev","selectedFormId","filter","nextRequest","existing","data","parsed","initialState","usedFormIds","Array","from","Set","flatMap","condition","dataPointKey","nextForms","forEach","handleClose","handleSave","finalState","done","updateGroup","index","next","selectedBehavior","find","opt","behavior","handleBehaviorChange","item","handleFormSelect","canSave","operator","trimmedValue","trim","test","dialog","open","onClose","size","Header","Content","direction","gap","style","maxHeight","overflowY","paddingRight","width","behaviorSection","alignItems","flexWrap","subdued","variant","div","Select","disableClearSelection","itemToKey","itemToString","items","selectedItem","onChange","SelectTrigger","placeholder","List","Item","onFormSelect","onMatchTypeChange","onUpdateGroup","Footer","sticky","justifyContent","appearance","onClick","disabled"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/display-conditions/DisplayConditionModal.tsx"],"sourcesContent":["import { Button, Combobox, Dialog, Flex, Text, ThemeProvider } from '@servicetitan/anvil2';\nimport { useCallback, useEffect, useMemo, useState } from 'react';\nimport { createPortal } from 'react-dom';\nimport { ConditionGroupsSection, MatchType } from './ConditionGroupsSection';\nimport { defaultState, MODAL_CONTENT_MAX_HEIGHT } from './constants';\nimport { DisplayConditionRequest, onDisplayCondition } from './displayConditionController';\nimport { buildUnlayerDisplayCondition, parseUnlayerDisplayCondition } from './nunjucks';\nimport { getSchemaDataPointOptions } from './schemaDataPoints';\nimport {\n ConditionGroup as ConditionGroupType,\n DisplayBehavior,\n DisplayConditionState,\n LogicalOperator,\n} from './types';\nimport {\n ConditionalsOpenHandler,\n ConditionFormSelectHandler,\n useConditionForms,\n} from './useConditionForms';\n\nconst BEHAVIOR_OPTIONS = [\n { label: 'Show', value: 'show' },\n { label: 'Hide', value: 'hide' },\n] as const;\nconst NUMERIC_VALUE_RE = /^-?(?:\\d+\\.?\\d*|\\.\\d+)$/;\ntype BehaviorOption = (typeof BEHAVIOR_OPTIONS)[number];\n\nfunction deriveMatchType(conditionState: DisplayConditionState): MatchType {\n const firstGroup = conditionState.groups[0];\n if (!firstGroup || firstGroup.conditions.length <= 1) {\n return 'all';\n }\n const hasOr = firstGroup.conditions.some(c => c.logicalOperator === 'or');\n return hasOr ? 'any' : 'all';\n}\n\nfunction applyMatchTypeToState(\n conditionState: DisplayConditionState,\n matchType: MatchType,\n): DisplayConditionState {\n const logicalOp: LogicalOperator = matchType === 'all' ? 'and' : 'or';\n return {\n ...conditionState,\n groups: conditionState.groups.map((group, groupIndex) => {\n if (groupIndex !== 0) {\n return group;\n }\n return {\n ...group,\n conditions: group.conditions.map((c, i) =>\n i === 0 ? c : { ...c, logicalOperator: logicalOp },\n ),\n };\n }),\n };\n}\n\nexport interface DisplayConditionModalProps {\n /**\n * Optional portal target. Prefer leaving unset so the dialog stays under the host\n * `AnvilProvider` (`.anvil2` CSS scope). When set (e.g. a host-controlled container),\n * content is wrapped in `ThemeProvider` so Anvil2 styles still apply after portaling.\n */\n portalContainer?: Element | DocumentFragment | null;\n onConditionFormSelect?: ConditionFormSelectHandler;\n onConditionalsOpen?: ConditionalsOpenHandler;\n schema?: import('../shared/schema').SchemaObject;\n}\n\nexport const DisplayConditionModal = (props: DisplayConditionModalProps) => {\n const {\n onConditionFormSelect,\n onConditionalsOpen,\n portalContainer: portalContainerProp,\n schema,\n } = props;\n const [request, setRequest] = useState<DisplayConditionRequest | null>(null);\n const [isOpen, setIsOpen] = useState(false);\n const [state, setState] = useState(defaultState);\n const [matchType, setMatchType] = useState<MatchType>('all');\n const { formFieldOptions, forms, isFieldDataLoading, loadForms, requestFormFields } =\n useConditionForms({ onConditionFormSelect, onConditionalsOpen });\n\n const dataPointOptions = useMemo(() => getSchemaDataPointOptions(schema), [schema]);\n const allFieldOptions = useMemo(\n () => [...dataPointOptions, ...formFieldOptions],\n [dataPointOptions, formFieldOptions],\n );\n\n useEffect(() => {\n return onDisplayCondition(nextRequest => {\n setRequest(nextRequest);\n const existing = nextRequest.data;\n const parsed = parseUnlayerDisplayCondition(existing);\n const initialState = parsed ?? defaultState();\n\n loadForms(initialState.groups);\n setState(initialState);\n setMatchType(deriveMatchType(initialState));\n setIsOpen(true);\n });\n }, [loadForms]);\n\n const handleClose = useCallback(() => {\n setRequest(null);\n setIsOpen(false);\n }, []);\n\n const handleSave = useCallback(() => {\n if (!request) {\n return;\n }\n const finalState = applyMatchTypeToState(state, matchType);\n const condition = buildUnlayerDisplayCondition(finalState);\n if (condition) {\n request.done(condition);\n } else {\n request.done(null);\n }\n setRequest(null);\n setIsOpen(false);\n }, [matchType, request, state]);\n\n const updateGroup = useCallback((index: number, group: ConditionGroupType) => {\n setState(prev => {\n const next = [...prev.groups];\n next[index] = group;\n return { ...prev, groups: next };\n });\n }, []);\n\n const selectedBehavior = useMemo(\n () => BEHAVIOR_OPTIONS.find(opt => opt.value === state.behavior) ?? BEHAVIOR_OPTIONS[0],\n [state.behavior],\n );\n\n const handleBehaviorChange = useCallback((item: BehaviorOption | null) => {\n if (item) {\n setState(prev => ({ ...prev, behavior: item.value as DisplayBehavior }));\n }\n }, []);\n\n const handleFormSelect = useCallback(\n (formId: number) => {\n requestFormFields(formId);\n },\n [requestFormFields],\n );\n\n const canSave = useMemo(() => {\n if (isFieldDataLoading) {\n return false;\n }\n for (const group of state.groups) {\n for (const condition of group.conditions) {\n if (!condition.dataPointKey) {\n return false;\n }\n if (condition.operator === 'is_empty' || condition.operator === 'is_not_empty') {\n continue;\n }\n const trimmedValue = condition.value.trim();\n if (!trimmedValue) {\n return false;\n }\n const fieldType =\n allFieldOptions.find(opt => opt.fullKey === condition.dataPointKey)\n ?.fieldType ?? 'string';\n if (fieldType === 'number' && !NUMERIC_VALUE_RE.test(trimmedValue)) {\n return false;\n }\n }\n }\n return state.groups.length > 0;\n }, [allFieldOptions, isFieldDataLoading, state.groups]);\n\n if (!isOpen) {\n return null;\n }\n\n /*\n * Render in-place by default (same as pdf-editor). Anvil2 3.x CSS is nested under\n * `.anvil2`; portaling to `document.body` / bare shadow root drops that ancestor and\n * styles disappear in MFE prod. Native `<dialog>` top-layer still stacks correctly.\n */\n const dialog = (\n <Dialog open={isOpen} onClose={handleClose} size=\"xlarge\">\n <Dialog.Header>Conditions</Dialog.Header>\n <Dialog.Content>\n <Flex\n direction=\"column\"\n gap=\"4\"\n style={{\n maxHeight: MODAL_CONTENT_MAX_HEIGHT,\n overflowY: 'auto',\n paddingRight: 8,\n width: '100%',\n }}\n >\n <ConditionGroupsSection\n behaviorSection={\n <Flex\n direction=\"row\"\n alignItems=\"center\"\n gap=\"2\"\n style={{ flexWrap: 'wrap' }}\n >\n <Text size=\"small\" subdued variant=\"body\">\n Select to include or exclude selected template/file.\n </Text>\n <div style={{ width: 90 }}>\n <Combobox.Select\n disableClearSelection\n itemToKey={(item: BehaviorOption | null) =>\n item?.value ?? ''\n }\n itemToString={(item: BehaviorOption | null) =>\n item?.label ?? ''\n }\n items={[...BEHAVIOR_OPTIONS]}\n selectedItem={selectedBehavior}\n onChange={handleBehaviorChange}\n >\n <Combobox.SelectTrigger\n label=\"\"\n placeholder=\"Select...\"\n size=\"small\"\n />\n <Combobox.Content>\n {({\n items,\n }: {\n items: BehaviorOption[];\n }) => (\n <Combobox.List>\n {items.map((item, i) => (\n <Combobox.Item\n index={i}\n item={item}\n key={item.value}\n >\n {item.label}\n </Combobox.Item>\n ))}\n </Combobox.List>\n )}\n </Combobox.Content>\n </Combobox.Select>\n </div>\n </Flex>\n }\n dataPointOptions={dataPointOptions}\n formFieldOptions={formFieldOptions}\n forms={forms}\n groups={state.groups}\n matchType={matchType}\n onFormSelect={handleFormSelect}\n onMatchTypeChange={setMatchType}\n onUpdateGroup={updateGroup}\n />\n </Flex>\n </Dialog.Content>\n <Dialog.Footer sticky>\n <Flex\n justifyContent=\"flex-end\"\n alignItems=\"center\"\n gap=\"3\"\n style={{ width: '100%' }}\n >\n <Button appearance=\"secondary\" onClick={handleClose}>\n Cancel\n </Button>\n <Button appearance=\"primary\" disabled={!canSave} onClick={handleSave}>\n Save Changes\n </Button>\n </Flex>\n </Dialog.Footer>\n </Dialog>\n );\n\n if (portalContainerProp) {\n return createPortal(<ThemeProvider>{dialog}</ThemeProvider>, portalContainerProp);\n }\n\n return dialog;\n};\n"],"names":["Button","Combobox","Dialog","Flex","Text","ThemeProvider","useCallback","useEffect","useMemo","useState","createPortal","ConditionGroupsSection","defaultState","MODAL_CONTENT_MAX_HEIGHT","onDisplayCondition","buildUnlayerDisplayCondition","parseUnlayerDisplayCondition","getSchemaDataPointOptions","useConditionForms","BEHAVIOR_OPTIONS","label","value","NUMERIC_VALUE_RE","deriveMatchType","conditionState","firstGroup","groups","conditions","length","hasOr","some","c","logicalOperator","applyMatchTypeToState","matchType","logicalOp","map","group","groupIndex","i","DisplayConditionModal","props","onConditionFormSelect","onConditionalsOpen","portalContainer","portalContainerProp","schema","request","setRequest","isOpen","setIsOpen","state","setState","setMatchType","formFieldOptions","forms","isFieldDataLoading","loadForms","requestFormFields","dataPointOptions","allFieldOptions","nextRequest","existing","data","parsed","initialState","handleClose","handleSave","finalState","condition","done","updateGroup","index","prev","next","selectedBehavior","find","opt","behavior","handleBehaviorChange","item","handleFormSelect","formId","canSave","dataPointKey","operator","trimmedValue","trim","fieldType","fullKey","test","dialog","open","onClose","size","Header","Content","direction","gap","style","maxHeight","overflowY","paddingRight","width","behaviorSection","alignItems","flexWrap","subdued","variant","div","Select","disableClearSelection","itemToKey","itemToString","items","selectedItem","onChange","SelectTrigger","placeholder","List","Item","onFormSelect","onMatchTypeChange","onUpdateGroup","Footer","sticky","justifyContent","appearance","onClick","disabled"],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ import { FormFieldInfo, FormInfo } from '../shared/forms';
2
+ import { ConditionGroup, FormFieldOption } from './types';
3
+ type SendFormFields = (formId: number, fields: FormFieldInfo[]) => void;
4
+ export type ConditionFormSelectHandler = (formId: number, sendFormFields: SendFormFields) => void;
5
+ export type ConditionalsOpenHandler = (usedFormIds: number[], sendFormList: (forms: FormInfo[]) => void, sendFormFields: SendFormFields) => void;
6
+ export interface UseConditionFormsOptions {
7
+ onConditionFormSelect?: ConditionFormSelectHandler;
8
+ onConditionalsOpen?: ConditionalsOpenHandler;
9
+ }
10
+ /**
11
+ * Loads the host's forms and form fields for a condition-editing modal, so form fields can be
12
+ * picked as condition data points alongside schema fields.
13
+ */
14
+ export declare const useConditionForms: ({ onConditionFormSelect, onConditionalsOpen, }: UseConditionFormsOptions) => {
15
+ formFieldOptions: FormFieldOption[];
16
+ forms: FormInfo[];
17
+ isFieldDataLoading: boolean;
18
+ loadForms: (groups: ConditionGroup[]) => void;
19
+ requestFormFields: (formId: number) => void;
20
+ };
21
+ export {};
22
+ //# sourceMappingURL=useConditionForms.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useConditionForms.d.ts","sourceRoot":"","sources":["../../src/display-conditions/useConditionForms.ts"],"names":[],"mappings":"AACA,OAAO,EAEH,aAAa,EACb,QAAQ,EAGX,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE1D,KAAK,cAAc,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,KAAK,IAAI,CAAC;AAExE,MAAM,MAAM,0BAA0B,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,cAAc,KAAK,IAAI,CAAC;AAElG,MAAM,MAAM,uBAAuB,GAAG,CAClC,WAAW,EAAE,MAAM,EAAE,EACrB,YAAY,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,IAAI,EACzC,cAAc,EAAE,cAAc,KAC7B,IAAI,CAAC;AAEV,MAAM,WAAW,wBAAwB;IACrC,qBAAqB,CAAC,EAAE,0BAA0B,CAAC;IACnD,kBAAkB,CAAC,EAAE,uBAAuB,CAAC;CAChD;AAED;;;GAGG;AACH,eAAO,MAAM,iBAAiB,GAAI,gDAG/B,wBAAwB;;;;wBAgEV,cAAc,EAAE;gCAtBhB,MAAM;CAuEtB,CAAC"}
@@ -0,0 +1,110 @@
1
+ import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
2
+ import { buildFormFieldKey, getConditionalFieldTypeFromFormItemType, parseFormFieldKey } from '../shared/forms';
3
+ /**
4
+ * Loads the host's forms and form fields for a condition-editing modal, so form fields can be
5
+ * picked as condition data points alongside schema fields.
6
+ */ export const useConditionForms = ({ onConditionFormSelect, onConditionalsOpen })=>{
7
+ const [forms, setForms] = useState([]);
8
+ const [formFieldsByFormId, setFormFieldsByFormId] = useState({});
9
+ const [loadingFormIds, setLoadingFormIds] = useState([]);
10
+ const [isFormsListLoading, setIsFormsListLoading] = useState(false);
11
+ const formFieldsByFormIdRef = useRef({});
12
+ const loadingFormIdsRef = useRef([]);
13
+ const formFieldOptions = useMemo(()=>{
14
+ const nextOptions = [];
15
+ for (const form of forms){
16
+ const fields = formFieldsByFormId[form.id];
17
+ if (!fields) {
18
+ continue;
19
+ }
20
+ for (const field of fields){
21
+ const fieldType = getConditionalFieldTypeFromFormItemType(field.itemType);
22
+ if (!fieldType) {
23
+ continue;
24
+ }
25
+ nextOptions.push({
26
+ fieldType,
27
+ formId: form.id,
28
+ fullKey: buildFormFieldKey(form.id, field.id),
29
+ title: field.header
30
+ });
31
+ }
32
+ }
33
+ return nextOptions.sort((left, right)=>left.title.localeCompare(right.title));
34
+ }, [
35
+ forms,
36
+ formFieldsByFormId
37
+ ]);
38
+ useEffect(()=>{
39
+ formFieldsByFormIdRef.current = formFieldsByFormId;
40
+ }, [
41
+ formFieldsByFormId
42
+ ]);
43
+ useEffect(()=>{
44
+ loadingFormIdsRef.current = loadingFormIds;
45
+ }, [
46
+ loadingFormIds
47
+ ]);
48
+ const requestFormFields = useCallback((formId)=>{
49
+ if (!onConditionFormSelect) {
50
+ return;
51
+ }
52
+ if (formFieldsByFormIdRef.current[formId] || loadingFormIdsRef.current.includes(formId)) {
53
+ return;
54
+ }
55
+ setLoadingFormIds((prev)=>prev.includes(formId) ? prev : [
56
+ ...prev,
57
+ formId
58
+ ]);
59
+ onConditionFormSelect(formId, (selectedFormId, fields)=>{
60
+ setFormFieldsByFormId((prev)=>({
61
+ ...prev,
62
+ [selectedFormId]: fields
63
+ }));
64
+ setLoadingFormIds((prev)=>prev.filter((id)=>id !== selectedFormId));
65
+ });
66
+ }, [
67
+ onConditionFormSelect
68
+ ]);
69
+ /** Resets form data and requests the forms list plus fields of forms the groups already use. */ const loadForms = useCallback((groups)=>{
70
+ const usedFormIds = Array.from(new Set(groups.flatMap((group)=>group.conditions).map((condition)=>{
71
+ var _parseFormFieldKey;
72
+ return (_parseFormFieldKey = parseFormFieldKey(condition.dataPointKey)) === null || _parseFormFieldKey === void 0 ? void 0 : _parseFormFieldKey.formId;
73
+ }).filter((formId)=>formId != null)));
74
+ /*
75
+ * Reset synchronously so `requestFormFields` below does not skip forms loaded by a
76
+ * previous open whose state is being cleared.
77
+ */ formFieldsByFormIdRef.current = {};
78
+ loadingFormIdsRef.current = [];
79
+ setForms([]);
80
+ setFormFieldsByFormId({});
81
+ setIsFormsListLoading(!!onConditionalsOpen);
82
+ setLoadingFormIds([]);
83
+ if (!onConditionalsOpen) {
84
+ return;
85
+ }
86
+ onConditionalsOpen(usedFormIds, (nextForms)=>{
87
+ setForms(nextForms);
88
+ setIsFormsListLoading(false);
89
+ }, (formId, fields)=>{
90
+ setFormFieldsByFormId((prev)=>({
91
+ ...prev,
92
+ [formId]: fields
93
+ }));
94
+ setLoadingFormIds((prev)=>prev.filter((id)=>id !== formId));
95
+ });
96
+ usedFormIds.forEach((formId)=>requestFormFields(formId));
97
+ }, [
98
+ onConditionalsOpen,
99
+ requestFormFields
100
+ ]);
101
+ return {
102
+ formFieldOptions,
103
+ forms,
104
+ isFieldDataLoading: isFormsListLoading || loadingFormIds.length > 0,
105
+ loadForms,
106
+ requestFormFields
107
+ };
108
+ };
109
+
110
+ //# sourceMappingURL=useConditionForms.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/display-conditions/useConditionForms.ts"],"sourcesContent":["import { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport {\n buildFormFieldKey,\n FormFieldInfo,\n FormInfo,\n getConditionalFieldTypeFromFormItemType,\n parseFormFieldKey,\n} from '../shared/forms';\nimport { ConditionGroup, FormFieldOption } from './types';\n\ntype SendFormFields = (formId: number, fields: FormFieldInfo[]) => void;\n\nexport type ConditionFormSelectHandler = (formId: number, sendFormFields: SendFormFields) => void;\n\nexport type ConditionalsOpenHandler = (\n usedFormIds: number[],\n sendFormList: (forms: FormInfo[]) => void,\n sendFormFields: SendFormFields,\n) => void;\n\nexport interface UseConditionFormsOptions {\n onConditionFormSelect?: ConditionFormSelectHandler;\n onConditionalsOpen?: ConditionalsOpenHandler;\n}\n\n/**\n * Loads the host's forms and form fields for a condition-editing modal, so form fields can be\n * picked as condition data points alongside schema fields.\n */\nexport const useConditionForms = ({\n onConditionFormSelect,\n onConditionalsOpen,\n}: UseConditionFormsOptions) => {\n const [forms, setForms] = useState<FormInfo[]>([]);\n const [formFieldsByFormId, setFormFieldsByFormId] = useState<Record<number, FormFieldInfo[]>>(\n {},\n );\n const [loadingFormIds, setLoadingFormIds] = useState<number[]>([]);\n const [isFormsListLoading, setIsFormsListLoading] = useState(false);\n const formFieldsByFormIdRef = useRef<Record<number, FormFieldInfo[]>>({});\n const loadingFormIdsRef = useRef<number[]>([]);\n\n const formFieldOptions = useMemo<FormFieldOption[]>(() => {\n const nextOptions: FormFieldOption[] = [];\n for (const form of forms) {\n const fields = formFieldsByFormId[form.id];\n if (!fields) {\n continue;\n }\n for (const field of fields) {\n const fieldType = getConditionalFieldTypeFromFormItemType(field.itemType);\n if (!fieldType) {\n continue;\n }\n nextOptions.push({\n fieldType,\n formId: form.id,\n fullKey: buildFormFieldKey(form.id, field.id),\n title: field.header,\n });\n }\n }\n return nextOptions.sort((left, right) => left.title.localeCompare(right.title));\n }, [forms, formFieldsByFormId]);\n\n useEffect(() => {\n formFieldsByFormIdRef.current = formFieldsByFormId;\n }, [formFieldsByFormId]);\n\n useEffect(() => {\n loadingFormIdsRef.current = loadingFormIds;\n }, [loadingFormIds]);\n\n const requestFormFields = useCallback(\n (formId: number) => {\n if (!onConditionFormSelect) {\n return;\n }\n if (\n formFieldsByFormIdRef.current[formId] ||\n loadingFormIdsRef.current.includes(formId)\n ) {\n return;\n }\n\n setLoadingFormIds(prev => (prev.includes(formId) ? prev : [...prev, formId]));\n onConditionFormSelect(formId, (selectedFormId, fields) => {\n setFormFieldsByFormId(prev => ({ ...prev, [selectedFormId]: fields }));\n setLoadingFormIds(prev => prev.filter(id => id !== selectedFormId));\n });\n },\n [onConditionFormSelect],\n );\n\n /** Resets form data and requests the forms list plus fields of forms the groups already use. */\n const loadForms = useCallback(\n (groups: ConditionGroup[]) => {\n const usedFormIds = Array.from(\n new Set(\n groups\n .flatMap(group => group.conditions)\n .map(condition => parseFormFieldKey(condition.dataPointKey)?.formId)\n .filter((formId): formId is number => formId != null),\n ),\n );\n\n /*\n * Reset synchronously so `requestFormFields` below does not skip forms loaded by a\n * previous open whose state is being cleared.\n */\n formFieldsByFormIdRef.current = {};\n loadingFormIdsRef.current = [];\n setForms([]);\n setFormFieldsByFormId({});\n setIsFormsListLoading(!!onConditionalsOpen);\n setLoadingFormIds([]);\n\n if (!onConditionalsOpen) {\n return;\n }\n\n onConditionalsOpen(\n usedFormIds,\n nextForms => {\n setForms(nextForms);\n setIsFormsListLoading(false);\n },\n (formId, fields) => {\n setFormFieldsByFormId(prev => ({ ...prev, [formId]: fields }));\n setLoadingFormIds(prev => prev.filter(id => id !== formId));\n },\n );\n\n usedFormIds.forEach(formId => requestFormFields(formId));\n },\n [onConditionalsOpen, requestFormFields],\n );\n\n return {\n formFieldOptions,\n forms,\n isFieldDataLoading: isFormsListLoading || loadingFormIds.length > 0,\n loadForms,\n requestFormFields,\n };\n};\n"],"names":["useCallback","useEffect","useMemo","useRef","useState","buildFormFieldKey","getConditionalFieldTypeFromFormItemType","parseFormFieldKey","useConditionForms","onConditionFormSelect","onConditionalsOpen","forms","setForms","formFieldsByFormId","setFormFieldsByFormId","loadingFormIds","setLoadingFormIds","isFormsListLoading","setIsFormsListLoading","formFieldsByFormIdRef","loadingFormIdsRef","formFieldOptions","nextOptions","form","fields","id","field","fieldType","itemType","push","formId","fullKey","title","header","sort","left","right","localeCompare","current","requestFormFields","includes","prev","selectedFormId","filter","loadForms","groups","usedFormIds","Array","from","Set","flatMap","group","conditions","map","condition","dataPointKey","nextForms","forEach","isFieldDataLoading","length"],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import { ConditionalsOpenHandler, ConditionFormSelectHandler } from '../display-conditions/useConditionForms';
2
+ import type { SchemaObject } from '../shared/schema';
3
+ export interface ESignDateSignedOffsetModalProps {
4
+ /** Same contract as `DisplayConditionModalProps.portalContainer`. */
5
+ portalContainer?: Element | DocumentFragment | null;
6
+ onConditionFormSelect?: ConditionFormSelectHandler;
7
+ onConditionalsOpen?: ConditionalsOpenHandler;
8
+ schema?: SchemaObject;
9
+ }
10
+ export declare function ESignDateSignedOffsetModal({ onConditionFormSelect, onConditionalsOpen, portalContainer, schema, }: Readonly<ESignDateSignedOffsetModalProps>): import("react").JSX.Element | null;
11
+ //# sourceMappingURL=ESignDateSignedOffsetModal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ESignDateSignedOffsetModal.d.ts","sourceRoot":"","sources":["../../src/e-sign-offset/ESignDateSignedOffsetModal.tsx"],"names":[],"mappings":"AAMA,OAAO,EACH,uBAAuB,EACvB,0BAA0B,EAE7B,MAAM,yCAAyC,CAAC;AAcjD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAIrD,MAAM,WAAW,+BAA+B;IAC5C,qEAAqE;IACrE,eAAe,CAAC,EAAE,OAAO,GAAG,gBAAgB,GAAG,IAAI,CAAC;IACpD,qBAAqB,CAAC,EAAE,0BAA0B,CAAC;IACnD,kBAAkB,CAAC,EAAE,uBAAuB,CAAC;IAC7C,MAAM,CAAC,EAAE,YAAY,CAAC;CACzB;AAED,wBAAgB,0BAA0B,CAAC,EACvC,qBAAqB,EACrB,kBAAkB,EAClB,eAAe,EACf,MAAM,GACT,EAAE,QAAQ,CAAC,+BAA+B,CAAC,sCA2J3C"}
@@ -0,0 +1,192 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Button, Card, Dialog, Flex, Text, ThemeProvider } from '@servicetitan/anvil2';
3
+ import PlusCircleIcon from '@servicetitan/anvil2/assets/icons/material/round/add_circle.svg';
4
+ import { useCallback, useEffect, useMemo, useState } from 'react';
5
+ import { createPortal } from 'react-dom';
6
+ import { MODAL_CONTENT_MAX_HEIGHT } from '../display-conditions/constants';
7
+ import { getSchemaDataPointOptions } from '../display-conditions/schemaDataPoints';
8
+ import { useConditionForms } from '../display-conditions/useConditionForms';
9
+ import { addESignOffsetRule, buildESignOffsetSettings, canAddESignOffsetRule, createESignOffsetRule, getESignOffsetRuleCondition, isCompleteESignOffsetCondition, normalizeESignOffsetSettings, removeESignOffsetRule, splitESignOffsetSettings, updateESignOffsetRule } from '../shared/e-sign-offset';
10
+ import { onESignOffsetRequest } from './eSignOffsetController';
11
+ import { ESignOffsetDaysField, ESignOffsetRuleRow } from './ESignOffsetRuleRow';
12
+ export function ESignDateSignedOffsetModal({ onConditionFormSelect, onConditionalsOpen, portalContainer, schema }) {
13
+ const [request, setRequest] = useState(null);
14
+ const [rules, setRules] = useState([]);
15
+ const [finalDays, setFinalDays] = useState(0);
16
+ const { formFieldOptions, forms, isFieldDataLoading, loadForms, requestFormFields } = useConditionForms({
17
+ onConditionFormSelect,
18
+ onConditionalsOpen
19
+ });
20
+ const dataPointOptions = useMemo(()=>getSchemaDataPointOptions(schema), [
21
+ schema
22
+ ]);
23
+ const allFieldOptions = useMemo(()=>[
24
+ ...dataPointOptions,
25
+ ...formFieldOptions
26
+ ], [
27
+ dataPointOptions,
28
+ formFieldOptions
29
+ ]);
30
+ useEffect(()=>{
31
+ return onESignOffsetRequest((nextRequest)=>{
32
+ const { conditionedRules, finalDays: nextFinalDays } = splitESignOffsetSettings(normalizeESignOffsetSettings(nextRequest.value));
33
+ const initialRules = conditionedRules.length ? conditionedRules : [
34
+ createESignOffsetRule()
35
+ ];
36
+ loadForms(initialRules.flatMap((rule)=>rule.condition.groups));
37
+ setRules(initialRules);
38
+ setFinalDays(nextFinalDays);
39
+ setRequest(nextRequest);
40
+ });
41
+ }, [
42
+ loadForms
43
+ ]);
44
+ const canSave = useMemo(()=>{
45
+ if (isFieldDataLoading) {
46
+ return false;
47
+ }
48
+ return rules.every((rule)=>{
49
+ var _ref;
50
+ var _allFieldOptions_find;
51
+ const condition = getESignOffsetRuleCondition(rule);
52
+ const fieldType = (_ref = (_allFieldOptions_find = allFieldOptions.find((option)=>option.fullKey === (condition === null || condition === void 0 ? void 0 : condition.dataPointKey))) === null || _allFieldOptions_find === void 0 ? void 0 : _allFieldOptions_find.fieldType) !== null && _ref !== void 0 ? _ref : 'string';
53
+ return isCompleteESignOffsetCondition(condition, fieldType);
54
+ });
55
+ }, [
56
+ allFieldOptions,
57
+ isFieldDataLoading,
58
+ rules
59
+ ]);
60
+ const handleClose = useCallback(()=>{
61
+ setRequest(null);
62
+ }, []);
63
+ const handleSave = useCallback(()=>{
64
+ request === null || request === void 0 ? void 0 : request.done(buildESignOffsetSettings(rules, finalDays));
65
+ setRequest(null);
66
+ }, [
67
+ finalDays,
68
+ request,
69
+ rules
70
+ ]);
71
+ const handleClearRules = useCallback(()=>{
72
+ setRules([]);
73
+ setFinalDays(0);
74
+ }, []);
75
+ const handleAddRule = useCallback(()=>{
76
+ setRules((prev)=>addESignOffsetRule(prev));
77
+ }, []);
78
+ const handleUpdateRule = useCallback((index, rule)=>{
79
+ setRules((prev)=>updateESignOffsetRule(prev, index, rule));
80
+ }, []);
81
+ const handleRemoveRule = useCallback((index)=>{
82
+ setRules((prev)=>removeESignOffsetRule(prev, index));
83
+ }, []);
84
+ if (!request) {
85
+ return null;
86
+ }
87
+ const dialog = /*#__PURE__*/ _jsxs(Dialog, {
88
+ open: true,
89
+ onClose: handleClose,
90
+ size: "xlarge",
91
+ children: [
92
+ /*#__PURE__*/ _jsx(Dialog.Header, {
93
+ children: "Date Signed Offset Rules"
94
+ }),
95
+ /*#__PURE__*/ _jsx(Dialog.Content, {
96
+ children: /*#__PURE__*/ _jsxs(Flex, {
97
+ direction: "column",
98
+ gap: "4",
99
+ style: {
100
+ maxHeight: MODAL_CONTENT_MAX_HEIGHT,
101
+ overflowY: 'auto',
102
+ paddingRight: 8,
103
+ width: '100%'
104
+ },
105
+ children: [
106
+ rules.length === 0 && /*#__PURE__*/ _jsx(Flex, {
107
+ justifyContent: "center",
108
+ alignItems: "center",
109
+ children: /*#__PURE__*/ _jsx(Text, {
110
+ variant: "body",
111
+ size: "xlarge",
112
+ subdued: true,
113
+ children: "Rule not configured yet."
114
+ })
115
+ }),
116
+ rules.map((rule, index)=>{
117
+ var _ref;
118
+ var _rule_condition_groups_;
119
+ return /*#__PURE__*/ _jsx(ESignOffsetRuleRow, {
120
+ dataPointOptions: dataPointOptions,
121
+ formFieldOptions: formFieldOptions,
122
+ forms: forms,
123
+ onChange: (nextRule)=>handleUpdateRule(index, nextRule),
124
+ onFormSelect: requestFormFields,
125
+ onRemove: ()=>handleRemoveRule(index),
126
+ rule: rule
127
+ }, (_ref = (_rule_condition_groups_ = rule.condition.groups[0]) === null || _rule_condition_groups_ === void 0 ? void 0 : _rule_condition_groups_.id) !== null && _ref !== void 0 ? _ref : index);
128
+ }),
129
+ /*#__PURE__*/ _jsx(Flex, {
130
+ children: /*#__PURE__*/ _jsx(Button, {
131
+ size: "small",
132
+ appearance: "ghost",
133
+ icon: {
134
+ before: PlusCircleIcon
135
+ },
136
+ onClick: handleAddRule,
137
+ disabled: !canAddESignOffsetRule(rules),
138
+ children: rules.length === 0 ? 'Add Condition' : 'Add Else Condition'
139
+ })
140
+ }),
141
+ /*#__PURE__*/ _jsx(Card, {
142
+ background: "strong",
143
+ padding: "small",
144
+ children: /*#__PURE__*/ _jsx(ESignOffsetDaysField, {
145
+ chipLabel: rules.length === 0 ? 'THEN' : 'ELSE',
146
+ days: finalDays,
147
+ onChange: setFinalDays
148
+ })
149
+ })
150
+ ]
151
+ })
152
+ }),
153
+ /*#__PURE__*/ _jsx(Dialog.Footer, {
154
+ sticky: true,
155
+ children: /*#__PURE__*/ _jsxs(Flex, {
156
+ justifyContent: "flex-end",
157
+ alignItems: "center",
158
+ gap: "3",
159
+ style: {
160
+ width: '100%'
161
+ },
162
+ children: [
163
+ rules.length > 0 && /*#__PURE__*/ _jsx(Button, {
164
+ appearance: "ghost",
165
+ onClick: handleClearRules,
166
+ children: "Clear Rules"
167
+ }),
168
+ /*#__PURE__*/ _jsx(Button, {
169
+ appearance: "secondary",
170
+ onClick: handleClose,
171
+ children: "Cancel"
172
+ }),
173
+ /*#__PURE__*/ _jsx(Button, {
174
+ appearance: "primary",
175
+ disabled: !canSave,
176
+ onClick: handleSave,
177
+ children: "Save Changes"
178
+ })
179
+ ]
180
+ })
181
+ })
182
+ ]
183
+ });
184
+ if (portalContainer) {
185
+ return /*#__PURE__*/ createPortal(/*#__PURE__*/ _jsx(ThemeProvider, {
186
+ children: dialog
187
+ }), portalContainer);
188
+ }
189
+ return dialog;
190
+ }
191
+
192
+ //# sourceMappingURL=ESignDateSignedOffsetModal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/e-sign-offset/ESignDateSignedOffsetModal.tsx"],"sourcesContent":["import { Button, Card, Dialog, Flex, Text, ThemeProvider } from '@servicetitan/anvil2';\nimport PlusCircleIcon from '@servicetitan/anvil2/assets/icons/material/round/add_circle.svg';\nimport { useCallback, useEffect, useMemo, useState } from 'react';\nimport { createPortal } from 'react-dom';\nimport { MODAL_CONTENT_MAX_HEIGHT } from '../display-conditions/constants';\nimport { getSchemaDataPointOptions } from '../display-conditions/schemaDataPoints';\nimport {\n ConditionalsOpenHandler,\n ConditionFormSelectHandler,\n useConditionForms,\n} from '../display-conditions/useConditionForms';\nimport type { ESignDateSignedOffsetRule } from '../shared/const';\nimport {\n addESignOffsetRule,\n buildESignOffsetSettings,\n canAddESignOffsetRule,\n createESignOffsetRule,\n getESignOffsetRuleCondition,\n isCompleteESignOffsetCondition,\n normalizeESignOffsetSettings,\n removeESignOffsetRule,\n splitESignOffsetSettings,\n updateESignOffsetRule,\n} from '../shared/e-sign-offset';\nimport type { SchemaObject } from '../shared/schema';\nimport { ESignOffsetRequest, onESignOffsetRequest } from './eSignOffsetController';\nimport { ESignOffsetDaysField, ESignOffsetRuleRow } from './ESignOffsetRuleRow';\n\nexport interface ESignDateSignedOffsetModalProps {\n /** Same contract as `DisplayConditionModalProps.portalContainer`. */\n portalContainer?: Element | DocumentFragment | null;\n onConditionFormSelect?: ConditionFormSelectHandler;\n onConditionalsOpen?: ConditionalsOpenHandler;\n schema?: SchemaObject;\n}\n\nexport function ESignDateSignedOffsetModal({\n onConditionFormSelect,\n onConditionalsOpen,\n portalContainer,\n schema,\n}: Readonly<ESignDateSignedOffsetModalProps>) {\n const [request, setRequest] = useState<ESignOffsetRequest | null>(null);\n const [rules, setRules] = useState<ESignDateSignedOffsetRule[]>([]);\n const [finalDays, setFinalDays] = useState(0);\n const { formFieldOptions, forms, isFieldDataLoading, loadForms, requestFormFields } =\n useConditionForms({ onConditionFormSelect, onConditionalsOpen });\n\n const dataPointOptions = useMemo(() => getSchemaDataPointOptions(schema), [schema]);\n const allFieldOptions = useMemo(\n () => [...dataPointOptions, ...formFieldOptions],\n [dataPointOptions, formFieldOptions],\n );\n\n useEffect(() => {\n return onESignOffsetRequest(nextRequest => {\n const { conditionedRules, finalDays: nextFinalDays } = splitESignOffsetSettings(\n normalizeESignOffsetSettings(nextRequest.value),\n );\n const initialRules = conditionedRules.length\n ? conditionedRules\n : [createESignOffsetRule()];\n\n loadForms(initialRules.flatMap(rule => rule.condition.groups));\n setRules(initialRules);\n setFinalDays(nextFinalDays);\n setRequest(nextRequest);\n });\n }, [loadForms]);\n\n const canSave = useMemo(() => {\n if (isFieldDataLoading) {\n return false;\n }\n\n return rules.every(rule => {\n const condition = getESignOffsetRuleCondition(rule);\n const fieldType =\n allFieldOptions.find(option => option.fullKey === condition?.dataPointKey)\n ?.fieldType ?? 'string';\n\n return isCompleteESignOffsetCondition(condition, fieldType);\n });\n }, [allFieldOptions, isFieldDataLoading, rules]);\n\n const handleClose = useCallback(() => {\n setRequest(null);\n }, []);\n\n const handleSave = useCallback(() => {\n request?.done(buildESignOffsetSettings(rules, finalDays));\n setRequest(null);\n }, [finalDays, request, rules]);\n\n const handleClearRules = useCallback(() => {\n setRules([]);\n setFinalDays(0);\n }, []);\n\n const handleAddRule = useCallback(() => {\n setRules(prev => addESignOffsetRule(prev));\n }, []);\n\n const handleUpdateRule = useCallback((index: number, rule: ESignDateSignedOffsetRule) => {\n setRules(prev => updateESignOffsetRule(prev, index, rule));\n }, []);\n\n const handleRemoveRule = useCallback((index: number) => {\n setRules(prev => removeESignOffsetRule(prev, index));\n }, []);\n\n if (!request) {\n return null;\n }\n\n const dialog = (\n <Dialog open onClose={handleClose} size=\"xlarge\">\n <Dialog.Header>Date Signed Offset Rules</Dialog.Header>\n <Dialog.Content>\n <Flex\n direction=\"column\"\n gap=\"4\"\n style={{\n maxHeight: MODAL_CONTENT_MAX_HEIGHT,\n overflowY: 'auto',\n paddingRight: 8,\n width: '100%',\n }}\n >\n {rules.length === 0 && (\n <Flex justifyContent=\"center\" alignItems=\"center\">\n <Text variant=\"body\" size=\"xlarge\" subdued>\n Rule not configured yet.\n </Text>\n </Flex>\n )}\n {rules.map((rule, index) => (\n <ESignOffsetRuleRow\n key={rule.condition.groups[0]?.id ?? index}\n dataPointOptions={dataPointOptions}\n formFieldOptions={formFieldOptions}\n forms={forms}\n onChange={nextRule => handleUpdateRule(index, nextRule)}\n onFormSelect={requestFormFields}\n onRemove={() => handleRemoveRule(index)}\n rule={rule}\n />\n ))}\n <Flex>\n <Button\n size=\"small\"\n appearance=\"ghost\"\n icon={{ before: PlusCircleIcon }}\n onClick={handleAddRule}\n disabled={!canAddESignOffsetRule(rules)}\n >\n {rules.length === 0 ? 'Add Condition' : 'Add Else Condition'}\n </Button>\n </Flex>\n <Card background=\"strong\" padding=\"small\">\n <ESignOffsetDaysField\n chipLabel={rules.length === 0 ? 'THEN' : 'ELSE'}\n days={finalDays}\n onChange={setFinalDays}\n />\n </Card>\n </Flex>\n </Dialog.Content>\n <Dialog.Footer sticky>\n <Flex\n justifyContent=\"flex-end\"\n alignItems=\"center\"\n gap=\"3\"\n style={{ width: '100%' }}\n >\n {rules.length > 0 && (\n <Button appearance=\"ghost\" onClick={handleClearRules}>\n Clear Rules\n </Button>\n )}\n <Button appearance=\"secondary\" onClick={handleClose}>\n Cancel\n </Button>\n <Button appearance=\"primary\" disabled={!canSave} onClick={handleSave}>\n Save Changes\n </Button>\n </Flex>\n </Dialog.Footer>\n </Dialog>\n );\n\n if (portalContainer) {\n return createPortal(<ThemeProvider>{dialog}</ThemeProvider>, portalContainer);\n }\n\n return dialog;\n}\n"],"names":["Button","Card","Dialog","Flex","Text","ThemeProvider","PlusCircleIcon","useCallback","useEffect","useMemo","useState","createPortal","MODAL_CONTENT_MAX_HEIGHT","getSchemaDataPointOptions","useConditionForms","addESignOffsetRule","buildESignOffsetSettings","canAddESignOffsetRule","createESignOffsetRule","getESignOffsetRuleCondition","isCompleteESignOffsetCondition","normalizeESignOffsetSettings","removeESignOffsetRule","splitESignOffsetSettings","updateESignOffsetRule","onESignOffsetRequest","ESignOffsetDaysField","ESignOffsetRuleRow","ESignDateSignedOffsetModal","onConditionFormSelect","onConditionalsOpen","portalContainer","schema","request","setRequest","rules","setRules","finalDays","setFinalDays","formFieldOptions","forms","isFieldDataLoading","loadForms","requestFormFields","dataPointOptions","allFieldOptions","nextRequest","conditionedRules","nextFinalDays","value","initialRules","length","flatMap","rule","condition","groups","canSave","every","fieldType","find","option","fullKey","dataPointKey","handleClose","handleSave","done","handleClearRules","handleAddRule","prev","handleUpdateRule","index","handleRemoveRule","dialog","open","onClose","size","Header","Content","direction","gap","style","maxHeight","overflowY","paddingRight","width","justifyContent","alignItems","variant","subdued","map","onChange","nextRule","onFormSelect","onRemove","id","appearance","icon","before","onClick","disabled","background","padding","chipLabel","days","Footer","sticky"],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ import type { DataPointOption, FormFieldOption } from '../display-conditions/types';
2
+ import { type ESignDateSignedOffsetRule } from '../shared/const';
3
+ import { FormInfo } from '../shared/forms';
4
+ export interface ESignOffsetDaysFieldProps {
5
+ chipLabel: string;
6
+ days: number;
7
+ onChange: (days: number) => void;
8
+ }
9
+ export declare function ESignOffsetDaysField({ chipLabel, days, onChange, }: Readonly<ESignOffsetDaysFieldProps>): import("react").JSX.Element;
10
+ export interface ESignOffsetRuleRowProps {
11
+ dataPointOptions: DataPointOption[];
12
+ formFieldOptions: FormFieldOption[];
13
+ forms: FormInfo[];
14
+ onChange: (rule: ESignDateSignedOffsetRule) => void;
15
+ onFormSelect: (formId: number) => void;
16
+ onRemove: () => void;
17
+ rule: ESignDateSignedOffsetRule;
18
+ }
19
+ export declare function ESignOffsetRuleRow({ dataPointOptions, formFieldOptions, forms, onChange, onFormSelect, onRemove, rule, }: Readonly<ESignOffsetRuleRowProps>): import("react").JSX.Element;
20
+ //# sourceMappingURL=ESignOffsetRuleRow.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ESignOffsetRuleRow.d.ts","sourceRoot":"","sources":["../../src/e-sign-offset/ESignOffsetRuleRow.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACR,eAAe,EACf,eAAe,EAElB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,KAAK,yBAAyB,EAA0B,MAAM,iBAAiB,CAAC;AAEzF,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAE3C,MAAM,WAAW,yBAAyB;IACtC,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CACpC;AAED,wBAAgB,oBAAoB,CAAC,EACjC,SAAS,EACT,IAAI,EACJ,QAAQ,GACX,EAAE,QAAQ,CAAC,yBAAyB,CAAC,+BAmBrC;AAED,MAAM,WAAW,uBAAuB;IACpC,gBAAgB,EAAE,eAAe,EAAE,CAAC;IACpC,gBAAgB,EAAE,eAAe,EAAE,CAAC;IACpC,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,QAAQ,EAAE,CAAC,IAAI,EAAE,yBAAyB,KAAK,IAAI,CAAC;IACpD,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,IAAI,EAAE,yBAAyB,CAAC;CACnC;AAED,wBAAgB,kBAAkB,CAAC,EAC/B,gBAAgB,EAChB,gBAAgB,EAChB,KAAK,EACL,QAAQ,EACR,YAAY,EACZ,QAAQ,EACR,IAAI,GACP,EAAE,QAAQ,CAAC,uBAAuB,CAAC,+BAuCnC"}
@@ -0,0 +1,87 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Card, Chip, Flex, NumberField } from '@servicetitan/anvil2';
3
+ import { ConditionRow } from '../display-conditions/ConditionRow';
4
+ import { defaultCondition, defaultGroup } from '../display-conditions/constants';
5
+ import { MAX_E_SIGN_OFFSET_DAYS } from '../shared/const';
6
+ import { clampESignOffsetDays } from '../shared/e-sign-offset';
7
+ export function ESignOffsetDaysField({ chipLabel, days, onChange }) {
8
+ return /*#__PURE__*/ _jsxs(Flex, {
9
+ children: [
10
+ /*#__PURE__*/ _jsx(Flex, {
11
+ alignItems: "center",
12
+ style: {
13
+ padding: '8px 12px'
14
+ },
15
+ children: /*#__PURE__*/ _jsx(Chip, {
16
+ label: chipLabel,
17
+ size: "medium"
18
+ })
19
+ }),
20
+ /*#__PURE__*/ _jsx(NumberField, {
21
+ label: "Number of days",
22
+ size: "small",
23
+ value: days,
24
+ minValue: 0,
25
+ maxValue: MAX_E_SIGN_OFFSET_DAYS,
26
+ maximumFractionDigits: 0,
27
+ suffix: "days",
28
+ hint: `days range up to ${MAX_E_SIGN_OFFSET_DAYS}`,
29
+ onChange: (value)=>onChange(clampESignOffsetDays(value))
30
+ })
31
+ ]
32
+ });
33
+ }
34
+ export function ESignOffsetRuleRow({ dataPointOptions, formFieldOptions, forms, onChange, onFormSelect, onRemove, rule }) {
35
+ var _rule_condition_groups_, _group_conditions_;
36
+ const group = (_rule_condition_groups_ = rule.condition.groups[0]) !== null && _rule_condition_groups_ !== void 0 ? _rule_condition_groups_ : defaultGroup();
37
+ const condition = (_group_conditions_ = group.conditions[0]) !== null && _group_conditions_ !== void 0 ? _group_conditions_ : defaultCondition();
38
+ const handleConditionChange = (nextCondition)=>{
39
+ onChange({
40
+ ...rule,
41
+ condition: {
42
+ behavior: 'show',
43
+ groups: [
44
+ {
45
+ conditions: [
46
+ nextCondition
47
+ ],
48
+ id: group.id
49
+ }
50
+ ]
51
+ }
52
+ });
53
+ };
54
+ const handleDaysChange = (days)=>{
55
+ onChange({
56
+ ...rule,
57
+ days
58
+ });
59
+ };
60
+ return /*#__PURE__*/ _jsx(Card, {
61
+ background: "strong",
62
+ padding: "small",
63
+ children: /*#__PURE__*/ _jsxs(Flex, {
64
+ direction: "column",
65
+ gap: "3",
66
+ children: [
67
+ /*#__PURE__*/ _jsx(ConditionRow, {
68
+ canRemove: true,
69
+ condition: condition,
70
+ dataPointOptions: dataPointOptions,
71
+ formFieldOptions: formFieldOptions,
72
+ forms: forms,
73
+ onChange: handleConditionChange,
74
+ onFormSelect: onFormSelect,
75
+ onRemove: onRemove
76
+ }),
77
+ /*#__PURE__*/ _jsx(ESignOffsetDaysField, {
78
+ chipLabel: "THEN",
79
+ days: rule.days,
80
+ onChange: handleDaysChange
81
+ })
82
+ ]
83
+ })
84
+ });
85
+ }
86
+
87
+ //# sourceMappingURL=ESignOffsetRuleRow.js.map