@servicetitan/dte-unlayer 0.154.0 → 0.156.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.
- package/dist/display-conditions/ConditionRow.d.ts.map +1 -1
- package/dist/display-conditions/ConditionRow.js +111 -95
- package/dist/display-conditions/ConditionRow.js.map +1 -1
- package/dist/display-conditions/DisplayConditionModal.d.ts +3 -3
- package/dist/display-conditions/DisplayConditionModal.d.ts.map +1 -1
- package/dist/display-conditions/DisplayConditionModal.js +8 -95
- package/dist/display-conditions/DisplayConditionModal.js.map +1 -1
- package/dist/display-conditions/useConditionForms.d.ts +22 -0
- package/dist/display-conditions/useConditionForms.d.ts.map +1 -0
- package/dist/display-conditions/useConditionForms.js +110 -0
- package/dist/display-conditions/useConditionForms.js.map +1 -0
- package/dist/e-sign-offset/ESignDateSignedOffsetModal.d.ts +11 -0
- package/dist/e-sign-offset/ESignDateSignedOffsetModal.d.ts.map +1 -0
- package/dist/e-sign-offset/ESignDateSignedOffsetModal.js +192 -0
- package/dist/e-sign-offset/ESignDateSignedOffsetModal.js.map +1 -0
- package/dist/e-sign-offset/ESignOffsetRuleRow.d.ts +20 -0
- package/dist/e-sign-offset/ESignOffsetRuleRow.d.ts.map +1 -0
- package/dist/e-sign-offset/ESignOffsetRuleRow.js +87 -0
- package/dist/e-sign-offset/ESignOffsetRuleRow.js.map +1 -0
- package/dist/e-sign-offset/eSignOffsetController.d.ts +10 -0
- package/dist/e-sign-offset/eSignOffsetController.d.ts.map +1 -0
- package/dist/e-sign-offset/eSignOffsetController.js +27 -0
- package/dist/e-sign-offset/eSignOffsetController.js.map +1 -0
- package/dist/editor-core-source.d.ts +2 -2
- package/dist/editor-core-source.d.ts.map +1 -1
- package/dist/editor-core-source.js +2 -2
- package/dist/editor-core-source.js.map +1 -1
- package/dist/editor.d.ts.map +1 -1
- package/dist/editor.js +8 -0
- package/dist/editor.js.map +1 -1
- package/dist/image-upload-error.d.ts +5 -0
- package/dist/image-upload-error.d.ts.map +1 -0
- package/dist/image-upload-error.js +8 -0
- package/dist/image-upload-error.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/shared/const.d.ts +30 -0
- package/dist/shared/const.d.ts.map +1 -1
- package/dist/shared/const.js +5 -0
- package/dist/shared/const.js.map +1 -1
- package/dist/shared/e-sign-offset.d.ts +21 -0
- package/dist/shared/e-sign-offset.d.ts.map +1 -0
- package/dist/shared/e-sign-offset.js +130 -0
- package/dist/shared/e-sign-offset.js.map +1 -0
- package/dist/store.d.ts +1 -0
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +36 -11
- package/dist/store.js.map +1 -1
- package/dist/tools.d.ts +6 -0
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +21 -1
- package/dist/tools.js.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/e-sign-offset.test.ts +281 -0
- package/src/__tests__/store.image-upload.test.ts +132 -0
- package/src/display-conditions/ConditionRow.tsx +86 -81
- package/src/display-conditions/DisplayConditionModal.tsx +12 -116
- package/src/display-conditions/useConditionForms.ts +146 -0
- package/src/e-sign-offset/ESignDateSignedOffsetModal.tsx +197 -0
- package/src/e-sign-offset/ESignOffsetRuleRow.tsx +101 -0
- package/src/e-sign-offset/eSignOffsetController.ts +39 -0
- package/src/editor-core-source.ts +2 -2
- package/src/editor.tsx +9 -0
- package/src/image-upload-error.ts +7 -0
- package/src/index.ts +1 -0
- package/src/shared/const.ts +37 -0
- package/src/shared/e-sign-offset.ts +173 -0
- package/src/store.ts +53 -8
- 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":"AAAA,SAASA,WAAW,EAAEC,SAAS,EAAEC,OAAO,EAAEC,MAAM,EAAEC,QAAQ,QAAQ,QAAQ;AAC1E,SACIC,iBAAiB,EAGjBC,uCAAuC,EACvCC,iBAAiB,QACd,kBAAkB;AAkBzB;;;CAGC,GACD,OAAO,MAAMC,oBAAoB,CAAC,EAC9BC,qBAAqB,EACrBC,kBAAkB,EACK;IACvB,MAAM,CAACC,OAAOC,SAAS,GAAGR,SAAqB,EAAE;IACjD,MAAM,CAACS,oBAAoBC,sBAAsB,GAAGV,SAChD,CAAC;IAEL,MAAM,CAACW,gBAAgBC,kBAAkB,GAAGZ,SAAmB,EAAE;IACjE,MAAM,CAACa,oBAAoBC,sBAAsB,GAAGd,SAAS;IAC7D,MAAMe,wBAAwBhB,OAAwC,CAAC;IACvE,MAAMiB,oBAAoBjB,OAAiB,EAAE;IAE7C,MAAMkB,mBAAmBnB,QAA2B;QAChD,MAAMoB,cAAiC,EAAE;QACzC,KAAK,MAAMC,QAAQZ,MAAO;YACtB,MAAMa,SAASX,kBAAkB,CAACU,KAAKE,EAAE,CAAC;YAC1C,IAAI,CAACD,QAAQ;gBACT;YACJ;YACA,KAAK,MAAME,SAASF,OAAQ;gBACxB,MAAMG,YAAYrB,wCAAwCoB,MAAME,QAAQ;gBACxE,IAAI,CAACD,WAAW;oBACZ;gBACJ;gBACAL,YAAYO,IAAI,CAAC;oBACbF;oBACAG,QAAQP,KAAKE,EAAE;oBACfM,SAAS1B,kBAAkBkB,KAAKE,EAAE,EAAEC,MAAMD,EAAE;oBAC5CO,OAAON,MAAMO,MAAM;gBACvB;YACJ;QACJ;QACA,OAAOX,YAAYY,IAAI,CAAC,CAACC,MAAMC,QAAUD,KAAKH,KAAK,CAACK,aAAa,CAACD,MAAMJ,KAAK;IACjF,GAAG;QAACrB;QAAOE;KAAmB;IAE9BZ,UAAU;QACNkB,sBAAsBmB,OAAO,GAAGzB;IACpC,GAAG;QAACA;KAAmB;IAEvBZ,UAAU;QACNmB,kBAAkBkB,OAAO,GAAGvB;IAChC,GAAG;QAACA;KAAe;IAEnB,MAAMwB,oBAAoBvC,YACtB,CAAC8B;QACG,IAAI,CAACrB,uBAAuB;YACxB;QACJ;QACA,IACIU,sBAAsBmB,OAAO,CAACR,OAAO,IACrCV,kBAAkBkB,OAAO,CAACE,QAAQ,CAACV,SACrC;YACE;QACJ;QAEAd,kBAAkByB,CAAAA,OAASA,KAAKD,QAAQ,CAACV,UAAUW,OAAO;mBAAIA;gBAAMX;aAAO;QAC3ErB,sBAAsBqB,QAAQ,CAACY,gBAAgBlB;YAC3CV,sBAAsB2B,CAAAA,OAAS,CAAA;oBAAE,GAAGA,IAAI;oBAAE,CAACC,eAAe,EAAElB;gBAAO,CAAA;YACnER,kBAAkByB,CAAAA,OAAQA,KAAKE,MAAM,CAAClB,CAAAA,KAAMA,OAAOiB;QACvD;IACJ,GACA;QAACjC;KAAsB;IAG3B,8FAA8F,GAC9F,MAAMmC,YAAY5C,YACd,CAAC6C;QACG,MAAMC,cAAcC,MAAMC,IAAI,CAC1B,IAAIC,IACAJ,OACKK,OAAO,CAACC,CAAAA,QAASA,MAAMC,UAAU,EACjCC,GAAG,CAACC,CAAAA;gBAAa/C;oBAAAA,qBAAAA,kBAAkB+C,UAAUC,YAAY,eAAxChD,yCAAAA,mBAA2CuB,MAAM;WAClEa,MAAM,CAAC,CAACb,SAA6BA,UAAU;QAI5D;;;aAGC,GACDX,sBAAsBmB,OAAO,GAAG,CAAC;QACjClB,kBAAkBkB,OAAO,GAAG,EAAE;QAC9B1B,SAAS,EAAE;QACXE,sBAAsB,CAAC;QACvBI,sBAAsB,CAAC,CAACR;QACxBM,kBAAkB,EAAE;QAEpB,IAAI,CAACN,oBAAoB;YACrB;QACJ;QAEAA,mBACIoC,aACAU,CAAAA;YACI5C,SAAS4C;YACTtC,sBAAsB;QAC1B,GACA,CAACY,QAAQN;YACLV,sBAAsB2B,CAAAA,OAAS,CAAA;oBAAE,GAAGA,IAAI;oBAAE,CAACX,OAAO,EAAEN;gBAAO,CAAA;YAC3DR,kBAAkByB,CAAAA,OAAQA,KAAKE,MAAM,CAAClB,CAAAA,KAAMA,OAAOK;QACvD;QAGJgB,YAAYW,OAAO,CAAC3B,CAAAA,SAAUS,kBAAkBT;IACpD,GACA;QAACpB;QAAoB6B;KAAkB;IAG3C,OAAO;QACHlB;QACAV;QACA+C,oBAAoBzC,sBAAsBF,eAAe4C,MAAM,GAAG;QAClEf;QACAL;IACJ;AACJ,EAAE"}
|
|
@@ -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
|