formanitor 0.0.26 → 0.0.28
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/index.cjs +196 -17
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +35 -3
- package/dist/index.d.ts +35 -3
- package/dist/index.mjs +196 -17
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
|
|
3
|
-
type FieldType = 'text' | 'number' | 'textarea' | 'richtext' | 'select' | 'multiselect' | 'radio' | 'repeatable' | 'checkbox' | 'image_upload' | 'signature' | 'date' | 'datetime' | 'editable_table' | 'static_text' | 'medications' | 'investigations' | 'procedures' | 'vitals' | 'hidden_vitals' | 'referral' | 'followup' | string;
|
|
3
|
+
type FieldType = 'text' | 'number' | 'textarea' | 'diagnosis_textarea' | 'richtext' | 'select' | 'multiselect' | 'radio' | 'repeatable' | 'checkbox' | 'image_upload' | 'signature' | 'date' | 'datetime' | 'editable_table' | 'static_text' | 'medications' | 'investigations' | 'procedures' | 'vitals' | 'hidden_vitals' | 'referral' | 'followup' | string;
|
|
4
4
|
interface ValidationRule {
|
|
5
5
|
min?: number;
|
|
6
6
|
max?: number;
|
|
@@ -209,6 +209,20 @@ interface SmartTextareaValue {
|
|
|
209
209
|
text: string;
|
|
210
210
|
extractedKeywords: ExtractedKeywordMatch[];
|
|
211
211
|
}
|
|
212
|
+
/** Selected diagnosis grade chip (single-selection). */
|
|
213
|
+
interface DiagnosisGradeSelection {
|
|
214
|
+
condition: string;
|
|
215
|
+
grade: string;
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Structured value for diagnosis_textarea fields.
|
|
219
|
+
* - `text` is the textarea content (what will be submitted).
|
|
220
|
+
* - `selectedGradesByCondition` stores one selected chip per condition for later metadata/preview use.
|
|
221
|
+
*/
|
|
222
|
+
interface DiagnosisTextareaValue {
|
|
223
|
+
text: string;
|
|
224
|
+
selectedGradesByCondition: Record<string, string>;
|
|
225
|
+
}
|
|
212
226
|
/**
|
|
213
227
|
* Smart textarea that performs client-side NLP keyword extraction and searches
|
|
214
228
|
* matched terms against backend master tables via `fieldHandlers[fieldId].onSearch`.
|
|
@@ -223,6 +237,19 @@ interface SmartTextareaFieldDef extends BaseFieldDef {
|
|
|
223
237
|
/** Debounce delay in ms before NLP + search triggers. Default: 1000. */
|
|
224
238
|
debounceDelay?: number;
|
|
225
239
|
}
|
|
240
|
+
/**
|
|
241
|
+
* Diagnosis textarea that can display condition-wise grade chips based on
|
|
242
|
+
* asynchronous API response.
|
|
243
|
+
*
|
|
244
|
+
* Value shape in form state can be plain text (legacy) or `DiagnosisTextareaValue`.
|
|
245
|
+
*/
|
|
246
|
+
interface DiagnosisTextareaFieldDef extends BaseFieldDef {
|
|
247
|
+
type: 'diagnosis_textarea';
|
|
248
|
+
/** Height in pixels. If omitted, uses default min height (80px). */
|
|
249
|
+
height?: number;
|
|
250
|
+
/** Debounce delay in ms before API call triggers. Default: 700. */
|
|
251
|
+
debounceDelay?: number;
|
|
252
|
+
}
|
|
226
253
|
interface MedicationFrequentItem {
|
|
227
254
|
id: string;
|
|
228
255
|
name: string;
|
|
@@ -269,7 +296,7 @@ interface DoctorFrequentItems {
|
|
|
269
296
|
investigations?: InvestigationFrequentItem[];
|
|
270
297
|
procedures?: ProcedureFrequentItem[];
|
|
271
298
|
}
|
|
272
|
-
type FieldDef = TextFieldDef | RichTextFieldDef | NumberFieldDef | SelectFieldDef | RadioFieldDef | CheckboxFieldDef | RepeatableFieldDef | ImageUploadFieldDef | SignatureFieldDef | EditableTableFieldDef | StaticTextFieldDef | MedicationsFieldDef | InvestigationsFieldDef | ProceduresFieldDef | DifferentialDiagnosisFieldDef | VitalsFieldDef | ReferralFieldDef | FollowupFieldDef | SmartTextareaFieldDef | BaseFieldDef;
|
|
299
|
+
type FieldDef = TextFieldDef | RichTextFieldDef | NumberFieldDef | SelectFieldDef | RadioFieldDef | CheckboxFieldDef | RepeatableFieldDef | ImageUploadFieldDef | SignatureFieldDef | EditableTableFieldDef | StaticTextFieldDef | MedicationsFieldDef | InvestigationsFieldDef | ProceduresFieldDef | DifferentialDiagnosisFieldDef | VitalsFieldDef | ReferralFieldDef | FollowupFieldDef | SmartTextareaFieldDef | DiagnosisTextareaFieldDef | BaseFieldDef;
|
|
273
300
|
interface Condition {
|
|
274
301
|
field?: string;
|
|
275
302
|
op: '==' | '!=' | '>' | '<' | '>=' | '<=' | 'in' | 'contains';
|
|
@@ -542,6 +569,11 @@ type FieldHandler = {
|
|
|
542
569
|
label: string;
|
|
543
570
|
value: any;
|
|
544
571
|
}[]>;
|
|
572
|
+
/**
|
|
573
|
+
* Called by diagnosis_textarea widgets to fetch condition-wise grades
|
|
574
|
+
* from diagnosis text input.
|
|
575
|
+
*/
|
|
576
|
+
onFetchDiagnosisGrades?: (query: string) => Promise<any>;
|
|
545
577
|
};
|
|
546
578
|
type FieldHandlersMap = Record<string, FieldHandler>;
|
|
547
579
|
declare function useFieldHandlers(fieldId: string): FieldHandler;
|
|
@@ -860,4 +892,4 @@ declare const SmartTextareaWidget: React.FC<{
|
|
|
860
892
|
fieldId: string;
|
|
861
893
|
}>;
|
|
862
894
|
|
|
863
|
-
export { type AIDifferentialDiagnosisItem, AddInvestigationField, type AddInvestigationFieldProps, AddMedicationField, type AddMedicationFieldProps, type BaseFieldDef, type CheckboxFieldDef, type ColumnLayout, type Computation, type Condition, type CreateUploadHandlerOptions, type DataSource, DifferentialDiagnosis, type DifferentialDiagnosisFieldDef, type DifferentialDiagnosisItem, type DifferentialDiagnosisProps, type DoctorFrequentItems, DynamicForm, EMAIL_REGEX, type EditableTableColumnDef, type EditableTableFieldDef, type EventDefinition, type ExtractedKeywordMatch, type FieldDef, type FieldHandler, type FieldHandlersMap, type FieldPrefill, FieldRenderer, type FieldState, type FieldType, type FollowupFieldDef, type FollowupValue, FormControls, type FormControlsProps, type FormDef, type FormErrors, FormProvider, type FormState, FormStore, type FormValues, type FormulaComputation, type FormulaExpr, type ImageUploadFieldDef, ImageUploadWidget, type Investigation, type InvestigationFrequentItem, type InvestigationSearchResult, type InvestigationsFieldDef, type LayoutNode, type MatchedCondition, type Medication, type MedicationFrequentItem, type MedicationSearchResult, type MedicationsFieldDef, type NumberFieldDef, type Permission, type PresignedUploadResponse, type ProcedureFrequentItem, type ProceduresFieldDef, type RadioFieldDef, ReadOnlyForm, ReadOnlyImageUpload, ReadOnlySignature, ReadOnlyTable, type ReferralFieldDef, type ReferralItem, type RepeatableFieldDef, type RichTextFieldDef, RichTextWidget, type Rule, type RuleAction, type RuleResult, type ScoreComputation, type ScoreRange, type Section, type SectionChild, type SelectFieldDef, type SelectOption, type SignatureFieldDef, SignatureUploadWidget, SmartForm, type SmartFormProps, type SmartKeywordsResult, type SmartTextareaFieldDef, type SmartTextareaValue, SmartTextareaWidget, type StaticTextFieldDef, type StoreConfig, type SubmissionData, type SumComputation, type TextFieldDef, type ValidationRule, type VitalsFieldDef, type WebhookDef, type Workflow, type WorkflowTransition, createUploadHandler, evaluateRules, useField, useFieldHandlers, useForm, useFormStore, useFrequentItems, useSmartKeywords, validateField, validateForm };
|
|
895
|
+
export { type AIDifferentialDiagnosisItem, AddInvestigationField, type AddInvestigationFieldProps, AddMedicationField, type AddMedicationFieldProps, type BaseFieldDef, type CheckboxFieldDef, type ColumnLayout, type Computation, type Condition, type CreateUploadHandlerOptions, type DataSource, type DiagnosisGradeSelection, type DiagnosisTextareaFieldDef, type DiagnosisTextareaValue, DifferentialDiagnosis, type DifferentialDiagnosisFieldDef, type DifferentialDiagnosisItem, type DifferentialDiagnosisProps, type DoctorFrequentItems, DynamicForm, EMAIL_REGEX, type EditableTableColumnDef, type EditableTableFieldDef, type EventDefinition, type ExtractedKeywordMatch, type FieldDef, type FieldHandler, type FieldHandlersMap, type FieldPrefill, FieldRenderer, type FieldState, type FieldType, type FollowupFieldDef, type FollowupValue, FormControls, type FormControlsProps, type FormDef, type FormErrors, FormProvider, type FormState, FormStore, type FormValues, type FormulaComputation, type FormulaExpr, type ImageUploadFieldDef, ImageUploadWidget, type Investigation, type InvestigationFrequentItem, type InvestigationSearchResult, type InvestigationsFieldDef, type LayoutNode, type MatchedCondition, type Medication, type MedicationFrequentItem, type MedicationSearchResult, type MedicationsFieldDef, type NumberFieldDef, type Permission, type PresignedUploadResponse, type ProcedureFrequentItem, type ProceduresFieldDef, type RadioFieldDef, ReadOnlyForm, ReadOnlyImageUpload, ReadOnlySignature, ReadOnlyTable, type ReferralFieldDef, type ReferralItem, type RepeatableFieldDef, type RichTextFieldDef, RichTextWidget, type Rule, type RuleAction, type RuleResult, type ScoreComputation, type ScoreRange, type Section, type SectionChild, type SelectFieldDef, type SelectOption, type SignatureFieldDef, SignatureUploadWidget, SmartForm, type SmartFormProps, type SmartKeywordsResult, type SmartTextareaFieldDef, type SmartTextareaValue, SmartTextareaWidget, type StaticTextFieldDef, type StoreConfig, type SubmissionData, type SumComputation, type TextFieldDef, type ValidationRule, type VitalsFieldDef, type WebhookDef, type Workflow, type WorkflowTransition, createUploadHandler, evaluateRules, useField, useFieldHandlers, useForm, useFormStore, useFrequentItems, useSmartKeywords, validateField, validateForm };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
|
|
3
|
-
type FieldType = 'text' | 'number' | 'textarea' | 'richtext' | 'select' | 'multiselect' | 'radio' | 'repeatable' | 'checkbox' | 'image_upload' | 'signature' | 'date' | 'datetime' | 'editable_table' | 'static_text' | 'medications' | 'investigations' | 'procedures' | 'vitals' | 'hidden_vitals' | 'referral' | 'followup' | string;
|
|
3
|
+
type FieldType = 'text' | 'number' | 'textarea' | 'diagnosis_textarea' | 'richtext' | 'select' | 'multiselect' | 'radio' | 'repeatable' | 'checkbox' | 'image_upload' | 'signature' | 'date' | 'datetime' | 'editable_table' | 'static_text' | 'medications' | 'investigations' | 'procedures' | 'vitals' | 'hidden_vitals' | 'referral' | 'followup' | string;
|
|
4
4
|
interface ValidationRule {
|
|
5
5
|
min?: number;
|
|
6
6
|
max?: number;
|
|
@@ -209,6 +209,20 @@ interface SmartTextareaValue {
|
|
|
209
209
|
text: string;
|
|
210
210
|
extractedKeywords: ExtractedKeywordMatch[];
|
|
211
211
|
}
|
|
212
|
+
/** Selected diagnosis grade chip (single-selection). */
|
|
213
|
+
interface DiagnosisGradeSelection {
|
|
214
|
+
condition: string;
|
|
215
|
+
grade: string;
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Structured value for diagnosis_textarea fields.
|
|
219
|
+
* - `text` is the textarea content (what will be submitted).
|
|
220
|
+
* - `selectedGradesByCondition` stores one selected chip per condition for later metadata/preview use.
|
|
221
|
+
*/
|
|
222
|
+
interface DiagnosisTextareaValue {
|
|
223
|
+
text: string;
|
|
224
|
+
selectedGradesByCondition: Record<string, string>;
|
|
225
|
+
}
|
|
212
226
|
/**
|
|
213
227
|
* Smart textarea that performs client-side NLP keyword extraction and searches
|
|
214
228
|
* matched terms against backend master tables via `fieldHandlers[fieldId].onSearch`.
|
|
@@ -223,6 +237,19 @@ interface SmartTextareaFieldDef extends BaseFieldDef {
|
|
|
223
237
|
/** Debounce delay in ms before NLP + search triggers. Default: 1000. */
|
|
224
238
|
debounceDelay?: number;
|
|
225
239
|
}
|
|
240
|
+
/**
|
|
241
|
+
* Diagnosis textarea that can display condition-wise grade chips based on
|
|
242
|
+
* asynchronous API response.
|
|
243
|
+
*
|
|
244
|
+
* Value shape in form state can be plain text (legacy) or `DiagnosisTextareaValue`.
|
|
245
|
+
*/
|
|
246
|
+
interface DiagnosisTextareaFieldDef extends BaseFieldDef {
|
|
247
|
+
type: 'diagnosis_textarea';
|
|
248
|
+
/** Height in pixels. If omitted, uses default min height (80px). */
|
|
249
|
+
height?: number;
|
|
250
|
+
/** Debounce delay in ms before API call triggers. Default: 700. */
|
|
251
|
+
debounceDelay?: number;
|
|
252
|
+
}
|
|
226
253
|
interface MedicationFrequentItem {
|
|
227
254
|
id: string;
|
|
228
255
|
name: string;
|
|
@@ -269,7 +296,7 @@ interface DoctorFrequentItems {
|
|
|
269
296
|
investigations?: InvestigationFrequentItem[];
|
|
270
297
|
procedures?: ProcedureFrequentItem[];
|
|
271
298
|
}
|
|
272
|
-
type FieldDef = TextFieldDef | RichTextFieldDef | NumberFieldDef | SelectFieldDef | RadioFieldDef | CheckboxFieldDef | RepeatableFieldDef | ImageUploadFieldDef | SignatureFieldDef | EditableTableFieldDef | StaticTextFieldDef | MedicationsFieldDef | InvestigationsFieldDef | ProceduresFieldDef | DifferentialDiagnosisFieldDef | VitalsFieldDef | ReferralFieldDef | FollowupFieldDef | SmartTextareaFieldDef | BaseFieldDef;
|
|
299
|
+
type FieldDef = TextFieldDef | RichTextFieldDef | NumberFieldDef | SelectFieldDef | RadioFieldDef | CheckboxFieldDef | RepeatableFieldDef | ImageUploadFieldDef | SignatureFieldDef | EditableTableFieldDef | StaticTextFieldDef | MedicationsFieldDef | InvestigationsFieldDef | ProceduresFieldDef | DifferentialDiagnosisFieldDef | VitalsFieldDef | ReferralFieldDef | FollowupFieldDef | SmartTextareaFieldDef | DiagnosisTextareaFieldDef | BaseFieldDef;
|
|
273
300
|
interface Condition {
|
|
274
301
|
field?: string;
|
|
275
302
|
op: '==' | '!=' | '>' | '<' | '>=' | '<=' | 'in' | 'contains';
|
|
@@ -542,6 +569,11 @@ type FieldHandler = {
|
|
|
542
569
|
label: string;
|
|
543
570
|
value: any;
|
|
544
571
|
}[]>;
|
|
572
|
+
/**
|
|
573
|
+
* Called by diagnosis_textarea widgets to fetch condition-wise grades
|
|
574
|
+
* from diagnosis text input.
|
|
575
|
+
*/
|
|
576
|
+
onFetchDiagnosisGrades?: (query: string) => Promise<any>;
|
|
545
577
|
};
|
|
546
578
|
type FieldHandlersMap = Record<string, FieldHandler>;
|
|
547
579
|
declare function useFieldHandlers(fieldId: string): FieldHandler;
|
|
@@ -860,4 +892,4 @@ declare const SmartTextareaWidget: React.FC<{
|
|
|
860
892
|
fieldId: string;
|
|
861
893
|
}>;
|
|
862
894
|
|
|
863
|
-
export { type AIDifferentialDiagnosisItem, AddInvestigationField, type AddInvestigationFieldProps, AddMedicationField, type AddMedicationFieldProps, type BaseFieldDef, type CheckboxFieldDef, type ColumnLayout, type Computation, type Condition, type CreateUploadHandlerOptions, type DataSource, DifferentialDiagnosis, type DifferentialDiagnosisFieldDef, type DifferentialDiagnosisItem, type DifferentialDiagnosisProps, type DoctorFrequentItems, DynamicForm, EMAIL_REGEX, type EditableTableColumnDef, type EditableTableFieldDef, type EventDefinition, type ExtractedKeywordMatch, type FieldDef, type FieldHandler, type FieldHandlersMap, type FieldPrefill, FieldRenderer, type FieldState, type FieldType, type FollowupFieldDef, type FollowupValue, FormControls, type FormControlsProps, type FormDef, type FormErrors, FormProvider, type FormState, FormStore, type FormValues, type FormulaComputation, type FormulaExpr, type ImageUploadFieldDef, ImageUploadWidget, type Investigation, type InvestigationFrequentItem, type InvestigationSearchResult, type InvestigationsFieldDef, type LayoutNode, type MatchedCondition, type Medication, type MedicationFrequentItem, type MedicationSearchResult, type MedicationsFieldDef, type NumberFieldDef, type Permission, type PresignedUploadResponse, type ProcedureFrequentItem, type ProceduresFieldDef, type RadioFieldDef, ReadOnlyForm, ReadOnlyImageUpload, ReadOnlySignature, ReadOnlyTable, type ReferralFieldDef, type ReferralItem, type RepeatableFieldDef, type RichTextFieldDef, RichTextWidget, type Rule, type RuleAction, type RuleResult, type ScoreComputation, type ScoreRange, type Section, type SectionChild, type SelectFieldDef, type SelectOption, type SignatureFieldDef, SignatureUploadWidget, SmartForm, type SmartFormProps, type SmartKeywordsResult, type SmartTextareaFieldDef, type SmartTextareaValue, SmartTextareaWidget, type StaticTextFieldDef, type StoreConfig, type SubmissionData, type SumComputation, type TextFieldDef, type ValidationRule, type VitalsFieldDef, type WebhookDef, type Workflow, type WorkflowTransition, createUploadHandler, evaluateRules, useField, useFieldHandlers, useForm, useFormStore, useFrequentItems, useSmartKeywords, validateField, validateForm };
|
|
895
|
+
export { type AIDifferentialDiagnosisItem, AddInvestigationField, type AddInvestigationFieldProps, AddMedicationField, type AddMedicationFieldProps, type BaseFieldDef, type CheckboxFieldDef, type ColumnLayout, type Computation, type Condition, type CreateUploadHandlerOptions, type DataSource, type DiagnosisGradeSelection, type DiagnosisTextareaFieldDef, type DiagnosisTextareaValue, DifferentialDiagnosis, type DifferentialDiagnosisFieldDef, type DifferentialDiagnosisItem, type DifferentialDiagnosisProps, type DoctorFrequentItems, DynamicForm, EMAIL_REGEX, type EditableTableColumnDef, type EditableTableFieldDef, type EventDefinition, type ExtractedKeywordMatch, type FieldDef, type FieldHandler, type FieldHandlersMap, type FieldPrefill, FieldRenderer, type FieldState, type FieldType, type FollowupFieldDef, type FollowupValue, FormControls, type FormControlsProps, type FormDef, type FormErrors, FormProvider, type FormState, FormStore, type FormValues, type FormulaComputation, type FormulaExpr, type ImageUploadFieldDef, ImageUploadWidget, type Investigation, type InvestigationFrequentItem, type InvestigationSearchResult, type InvestigationsFieldDef, type LayoutNode, type MatchedCondition, type Medication, type MedicationFrequentItem, type MedicationSearchResult, type MedicationsFieldDef, type NumberFieldDef, type Permission, type PresignedUploadResponse, type ProcedureFrequentItem, type ProceduresFieldDef, type RadioFieldDef, ReadOnlyForm, ReadOnlyImageUpload, ReadOnlySignature, ReadOnlyTable, type ReferralFieldDef, type ReferralItem, type RepeatableFieldDef, type RichTextFieldDef, RichTextWidget, type Rule, type RuleAction, type RuleResult, type ScoreComputation, type ScoreRange, type Section, type SectionChild, type SelectFieldDef, type SelectOption, type SignatureFieldDef, SignatureUploadWidget, SmartForm, type SmartFormProps, type SmartKeywordsResult, type SmartTextareaFieldDef, type SmartTextareaValue, SmartTextareaWidget, type StaticTextFieldDef, type StoreConfig, type SubmissionData, type SumComputation, type TextFieldDef, type ValidationRule, type VitalsFieldDef, type WebhookDef, type Workflow, type WorkflowTransition, createUploadHandler, evaluateRules, useField, useFieldHandlers, useForm, useFormStore, useFrequentItems, useSmartKeywords, validateField, validateForm };
|
package/dist/index.mjs
CHANGED
|
@@ -395,6 +395,11 @@ var FormStore = class {
|
|
|
395
395
|
result[field.id] = raw?.text ?? null;
|
|
396
396
|
return;
|
|
397
397
|
}
|
|
398
|
+
if (field.type === "diagnosis_textarea") {
|
|
399
|
+
const raw = values[field.id];
|
|
400
|
+
result[field.id] = typeof raw === "string" ? raw : raw && typeof raw === "object" ? raw.text ?? null : null;
|
|
401
|
+
return;
|
|
402
|
+
}
|
|
398
403
|
if (field.type === "ophthal_diagnosis") {
|
|
399
404
|
const raw = values[field.id];
|
|
400
405
|
const formatEye = (eyeData, eyeLabel) => {
|
|
@@ -3325,8 +3330,9 @@ var AddInvestigationField = ({
|
|
|
3325
3330
|
const debounceRef = useRef(null);
|
|
3326
3331
|
const valueRef = useRef([]);
|
|
3327
3332
|
const searchInputRef = useRef(null);
|
|
3328
|
-
|
|
3329
|
-
|
|
3333
|
+
const safeValue = Array.isArray(value) ? value : [];
|
|
3334
|
+
valueRef.current = safeValue;
|
|
3335
|
+
const addedIds = new Set(safeValue.map((inv) => inv.id));
|
|
3330
3336
|
useEffect(() => {
|
|
3331
3337
|
if (!open) {
|
|
3332
3338
|
setQuery("");
|
|
@@ -3369,7 +3375,7 @@ var AddInvestigationField = ({
|
|
|
3369
3375
|
}, ADD_FEEDBACK_MS2);
|
|
3370
3376
|
}
|
|
3371
3377
|
function removeInvestigation(id) {
|
|
3372
|
-
onChange(
|
|
3378
|
+
onChange(safeValue.filter((inv) => inv.id !== id));
|
|
3373
3379
|
}
|
|
3374
3380
|
function handleRecentlyUsedToggle(result) {
|
|
3375
3381
|
if (addedIds.has(result.id)) {
|
|
@@ -3381,10 +3387,10 @@ var AddInvestigationField = ({
|
|
|
3381
3387
|
async function handleFrequentItemToggle(item) {
|
|
3382
3388
|
const id = String(item.id);
|
|
3383
3389
|
const addedById = addedIds.has(id);
|
|
3384
|
-
const addedByName =
|
|
3390
|
+
const addedByName = safeValue.some((inv) => inv.name === item.name);
|
|
3385
3391
|
if (addedById || addedByName) {
|
|
3386
3392
|
if (addedById) removeInvestigation(id);
|
|
3387
|
-
else onChange(
|
|
3393
|
+
else onChange(safeValue.filter((inv) => inv.name !== item.name));
|
|
3388
3394
|
return;
|
|
3389
3395
|
}
|
|
3390
3396
|
setAddingFrequentId(id);
|
|
@@ -3420,7 +3426,7 @@ var AddInvestigationField = ({
|
|
|
3420
3426
|
const limitedFrequentItems = frequentItems.slice(0, 25);
|
|
3421
3427
|
const frequentItemChips = limitedFrequentItems.length > 0 ? limitedFrequentItems.map((item) => {
|
|
3422
3428
|
const id = String(item.id);
|
|
3423
|
-
const isAdded =
|
|
3429
|
+
const isAdded = safeValue.some((inv) => inv.id === id) || safeValue.some((inv) => inv.name === item.name);
|
|
3424
3430
|
const isAdding = addingFrequentId === id;
|
|
3425
3431
|
return /* @__PURE__ */ jsxs(
|
|
3426
3432
|
"button",
|
|
@@ -3454,7 +3460,7 @@ var AddInvestigationField = ({
|
|
|
3454
3460
|
}
|
|
3455
3461
|
)
|
|
3456
3462
|
] }),
|
|
3457
|
-
|
|
3463
|
+
safeValue.length > 0 && /* @__PURE__ */ jsx("div", { className: "divide-y divide-border rounded-lg border border-border overflow-hidden", children: safeValue.map((inv) => /* @__PURE__ */ jsxs(
|
|
3458
3464
|
"div",
|
|
3459
3465
|
{
|
|
3460
3466
|
className: "flex items-center justify-between px-3 py-2 bg-white hover:bg-gray-50",
|
|
@@ -3521,10 +3527,11 @@ var AddInvestigationWidget = ({ fieldId }) => {
|
|
|
3521
3527
|
const { value, setValue } = useField(fieldId);
|
|
3522
3528
|
const handlers = useFieldHandlers(fieldId);
|
|
3523
3529
|
const { investigations: frequentInvestigations } = useFrequentItems();
|
|
3530
|
+
const safeValue = Array.isArray(value) ? value : [];
|
|
3524
3531
|
return /* @__PURE__ */ jsx(
|
|
3525
3532
|
AddInvestigationField,
|
|
3526
3533
|
{
|
|
3527
|
-
value:
|
|
3534
|
+
value: safeValue,
|
|
3528
3535
|
onChange: setValue,
|
|
3529
3536
|
onSearch: handlers.onSearch,
|
|
3530
3537
|
recentlyUsed: handlers.recentlyUsed,
|
|
@@ -3561,9 +3568,10 @@ var AddProcedureField = ({
|
|
|
3561
3568
|
const debounceRef = useRef(null);
|
|
3562
3569
|
const valueRef = useRef([]);
|
|
3563
3570
|
const searchInputRef = useRef(null);
|
|
3564
|
-
|
|
3571
|
+
const safeValue = Array.isArray(value) ? value : [];
|
|
3572
|
+
valueRef.current = safeValue;
|
|
3565
3573
|
const addedIds = new Set(
|
|
3566
|
-
|
|
3574
|
+
safeValue.filter((proc) => !proc.is_custom).map((proc) => proc.id)
|
|
3567
3575
|
);
|
|
3568
3576
|
useEffect(() => {
|
|
3569
3577
|
if (!open) {
|
|
@@ -3607,10 +3615,10 @@ var AddProcedureField = ({
|
|
|
3607
3615
|
}, ADD_FEEDBACK_MS3);
|
|
3608
3616
|
}
|
|
3609
3617
|
function removeAt(index) {
|
|
3610
|
-
onChange(
|
|
3618
|
+
onChange(safeValue.filter((_, i) => i !== index));
|
|
3611
3619
|
}
|
|
3612
3620
|
function removeBySearchId(id) {
|
|
3613
|
-
onChange(
|
|
3621
|
+
onChange(safeValue.filter((proc) => proc.is_custom || proc.id !== id));
|
|
3614
3622
|
}
|
|
3615
3623
|
function handleAddCustom() {
|
|
3616
3624
|
const trimmed = query.trim();
|
|
@@ -3630,10 +3638,10 @@ var AddProcedureField = ({
|
|
|
3630
3638
|
async function handleFrequentItemToggle(item) {
|
|
3631
3639
|
const id = String(item.id);
|
|
3632
3640
|
const addedById = addedIds.has(id);
|
|
3633
|
-
const addedByName =
|
|
3641
|
+
const addedByName = safeValue.some((proc) => proc.name === item.name);
|
|
3634
3642
|
if (addedById || addedByName) {
|
|
3635
3643
|
if (addedById) removeBySearchId(id);
|
|
3636
|
-
else onChange(
|
|
3644
|
+
else onChange(safeValue.filter((proc) => proc.name !== item.name));
|
|
3637
3645
|
return;
|
|
3638
3646
|
}
|
|
3639
3647
|
setAddingFrequentId(id);
|
|
@@ -3669,7 +3677,7 @@ var AddProcedureField = ({
|
|
|
3669
3677
|
const limitedFrequentItems = frequentItems.slice(0, 25);
|
|
3670
3678
|
const frequentItemChips = limitedFrequentItems.length > 0 ? limitedFrequentItems.map((item) => {
|
|
3671
3679
|
const id = String(item.id);
|
|
3672
|
-
const isAdded =
|
|
3680
|
+
const isAdded = safeValue.some((proc) => !proc.is_custom && proc.id === id) || safeValue.some((proc) => proc.name === item.name);
|
|
3673
3681
|
const isAdding = addingFrequentId === id;
|
|
3674
3682
|
return /* @__PURE__ */ jsxs(
|
|
3675
3683
|
"button",
|
|
@@ -3703,7 +3711,7 @@ var AddProcedureField = ({
|
|
|
3703
3711
|
}
|
|
3704
3712
|
)
|
|
3705
3713
|
] }),
|
|
3706
|
-
|
|
3714
|
+
safeValue.length > 0 && /* @__PURE__ */ jsx("div", { className: "divide-y divide-border rounded-lg border border-border overflow-hidden", children: safeValue.map((proc, index) => /* @__PURE__ */ jsxs(
|
|
3707
3715
|
"div",
|
|
3708
3716
|
{
|
|
3709
3717
|
className: "flex items-center justify-between px-3 py-2 bg-white hover:bg-gray-50",
|
|
@@ -3783,10 +3791,11 @@ var AddProcedureWidget = ({ fieldId }) => {
|
|
|
3783
3791
|
const { value, setValue } = useField(fieldId);
|
|
3784
3792
|
const handlers = useFieldHandlers(fieldId);
|
|
3785
3793
|
const { procedures: frequentProcedures } = useFrequentItems();
|
|
3794
|
+
const safeValue = Array.isArray(value) ? value : [];
|
|
3786
3795
|
return /* @__PURE__ */ jsx(
|
|
3787
3796
|
AddProcedureField,
|
|
3788
3797
|
{
|
|
3789
|
-
value:
|
|
3798
|
+
value: safeValue,
|
|
3790
3799
|
onChange: setValue,
|
|
3791
3800
|
onSearch: handlers.onSearch,
|
|
3792
3801
|
recentlyUsed: handlers.recentlyUsed,
|
|
@@ -4755,6 +4764,174 @@ var SmartTextareaWidget = ({ fieldId }) => {
|
|
|
4755
4764
|
showError && /* @__PURE__ */ jsx("p", { className: "text-xs text-red-500", children: error })
|
|
4756
4765
|
] });
|
|
4757
4766
|
};
|
|
4767
|
+
function normalizeDiagnosisGrades(payload) {
|
|
4768
|
+
const result = [];
|
|
4769
|
+
const pushGroup = (conditionRaw, gradesRaw) => {
|
|
4770
|
+
const condition = typeof conditionRaw === "string" ? conditionRaw.trim() : "";
|
|
4771
|
+
if (!condition) return;
|
|
4772
|
+
if (!Array.isArray(gradesRaw)) return;
|
|
4773
|
+
const grades = Array.from(
|
|
4774
|
+
new Set(
|
|
4775
|
+
gradesRaw.map((grade) => typeof grade === "string" ? grade.trim() : "").filter(Boolean)
|
|
4776
|
+
)
|
|
4777
|
+
);
|
|
4778
|
+
if (grades.length === 0) return;
|
|
4779
|
+
result.push({ condition, grades });
|
|
4780
|
+
};
|
|
4781
|
+
const asArrayResponse = payload;
|
|
4782
|
+
if (Array.isArray(asArrayResponse?.diagnosisGrades)) {
|
|
4783
|
+
asArrayResponse.diagnosisGrades.forEach((item) => {
|
|
4784
|
+
pushGroup(item?.condition, item?.grades);
|
|
4785
|
+
});
|
|
4786
|
+
return result;
|
|
4787
|
+
}
|
|
4788
|
+
const asMapResponse = payload;
|
|
4789
|
+
const mapLike = asMapResponse?.field === "diagnosisgrade" && asMapResponse?.value && typeof asMapResponse.value === "object" ? asMapResponse.value : null;
|
|
4790
|
+
if (mapLike) {
|
|
4791
|
+
Object.entries(mapLike).forEach(([condition, grades]) => {
|
|
4792
|
+
pushGroup(condition, grades);
|
|
4793
|
+
});
|
|
4794
|
+
}
|
|
4795
|
+
return result;
|
|
4796
|
+
}
|
|
4797
|
+
var DiagnosisTextareaWidget = ({ fieldId }) => {
|
|
4798
|
+
const { fieldDef, value, setValue, setTouched, error, disabled, touched } = useField(fieldId);
|
|
4799
|
+
const { state } = useForm();
|
|
4800
|
+
const handler = useFieldHandlers(fieldId);
|
|
4801
|
+
const def = fieldDef;
|
|
4802
|
+
const [gradeGroups, setGradeGroups] = React13__default.useState([]);
|
|
4803
|
+
const [isLoadingGrades, setIsLoadingGrades] = React13__default.useState(false);
|
|
4804
|
+
const normalized = React13__default.useMemo(() => {
|
|
4805
|
+
const raw = value;
|
|
4806
|
+
if (typeof raw === "string") {
|
|
4807
|
+
return { text: raw, selectedGradesByCondition: {} };
|
|
4808
|
+
}
|
|
4809
|
+
if (!raw || typeof raw !== "object") {
|
|
4810
|
+
return { text: "", selectedGradesByCondition: {} };
|
|
4811
|
+
}
|
|
4812
|
+
const text = typeof raw.text === "string" ? raw.text : "";
|
|
4813
|
+
const mapRaw = raw.selectedGradesByCondition;
|
|
4814
|
+
let selectedGradesByCondition = {};
|
|
4815
|
+
if (mapRaw && typeof mapRaw === "object" && !Array.isArray(mapRaw)) {
|
|
4816
|
+
const entries = Object.entries(mapRaw);
|
|
4817
|
+
for (const [condition, gradeRaw] of entries) {
|
|
4818
|
+
if (typeof condition !== "string") continue;
|
|
4819
|
+
if (typeof gradeRaw === "string" && gradeRaw.trim()) {
|
|
4820
|
+
selectedGradesByCondition[condition] = gradeRaw;
|
|
4821
|
+
}
|
|
4822
|
+
}
|
|
4823
|
+
}
|
|
4824
|
+
const sg = raw.selectedGrade;
|
|
4825
|
+
if (sg && typeof sg === "object" && typeof sg.condition === "string" && typeof sg.grade === "string") {
|
|
4826
|
+
const condition = sg.condition.trim();
|
|
4827
|
+
const grade = sg.grade.trim();
|
|
4828
|
+
if (condition && grade && !selectedGradesByCondition[condition]) {
|
|
4829
|
+
selectedGradesByCondition = { ...selectedGradesByCondition, [condition]: grade };
|
|
4830
|
+
}
|
|
4831
|
+
}
|
|
4832
|
+
return { text, selectedGradesByCondition };
|
|
4833
|
+
}, [value]);
|
|
4834
|
+
const textValue = normalized.text;
|
|
4835
|
+
const showError = !!error && (touched || state.submitAttempted);
|
|
4836
|
+
React13__default.useEffect(() => {
|
|
4837
|
+
const query = textValue.trim();
|
|
4838
|
+
const fetchGrades = handler.onFetchDiagnosisGrades;
|
|
4839
|
+
const debounceMs = def?.debounceDelay ?? 1e3;
|
|
4840
|
+
if (!query || !fetchGrades) {
|
|
4841
|
+
setGradeGroups([]);
|
|
4842
|
+
setIsLoadingGrades(false);
|
|
4843
|
+
return;
|
|
4844
|
+
}
|
|
4845
|
+
let isActive = true;
|
|
4846
|
+
const timer = window.setTimeout(async () => {
|
|
4847
|
+
setIsLoadingGrades(true);
|
|
4848
|
+
try {
|
|
4849
|
+
const response = await fetchGrades(query);
|
|
4850
|
+
if (!isActive) return;
|
|
4851
|
+
setGradeGroups(normalizeDiagnosisGrades(response));
|
|
4852
|
+
} catch {
|
|
4853
|
+
if (!isActive) return;
|
|
4854
|
+
setGradeGroups([]);
|
|
4855
|
+
} finally {
|
|
4856
|
+
if (isActive) setIsLoadingGrades(false);
|
|
4857
|
+
}
|
|
4858
|
+
}, debounceMs);
|
|
4859
|
+
return () => {
|
|
4860
|
+
isActive = false;
|
|
4861
|
+
window.clearTimeout(timer);
|
|
4862
|
+
};
|
|
4863
|
+
}, [textValue, handler.onFetchDiagnosisGrades, def?.debounceDelay]);
|
|
4864
|
+
if (!def) return null;
|
|
4865
|
+
const theme = getThemeConfig("textarea", def.theme);
|
|
4866
|
+
const wrapperClass = theme?.wrapperClassName ?? "space-y-2";
|
|
4867
|
+
const labelClass = theme?.labelClassName;
|
|
4868
|
+
const inputClass = cn(theme?.inputClassName, showError && "border-red-500");
|
|
4869
|
+
const toggleSelectedGrade = (condition, grade) => {
|
|
4870
|
+
if (disabled) return;
|
|
4871
|
+
const current = normalized.selectedGradesByCondition[condition];
|
|
4872
|
+
const nextForCondition = current === grade ? "" : grade;
|
|
4873
|
+
const nextMap = { ...normalized.selectedGradesByCondition };
|
|
4874
|
+
if (!nextForCondition) {
|
|
4875
|
+
delete nextMap[condition];
|
|
4876
|
+
} else {
|
|
4877
|
+
nextMap[condition] = nextForCondition;
|
|
4878
|
+
}
|
|
4879
|
+
setValue({ text: normalized.text, selectedGradesByCondition: nextMap });
|
|
4880
|
+
setTouched();
|
|
4881
|
+
};
|
|
4882
|
+
const labelContent = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
4883
|
+
def.label,
|
|
4884
|
+
" ",
|
|
4885
|
+
def.required && /* @__PURE__ */ jsx("span", { className: "text-red-500", children: "*" })
|
|
4886
|
+
] });
|
|
4887
|
+
return /* @__PURE__ */ jsxs("div", { className: wrapperClass, children: [
|
|
4888
|
+
theme ? /* @__PURE__ */ jsx(Label, { htmlFor: fieldId, className: labelClass, children: labelContent }) : /* @__PURE__ */ jsx(Label, { htmlFor: fieldId, children: labelContent }),
|
|
4889
|
+
/* @__PURE__ */ jsx(
|
|
4890
|
+
Textarea,
|
|
4891
|
+
{
|
|
4892
|
+
id: fieldId,
|
|
4893
|
+
value: textValue,
|
|
4894
|
+
onChange: (e) => setValue({ text: e.target.value, selectedGradesByCondition: normalized.selectedGradesByCondition }),
|
|
4895
|
+
onBlur: setTouched,
|
|
4896
|
+
disabled,
|
|
4897
|
+
placeholder: def.placeholder,
|
|
4898
|
+
className: inputClass,
|
|
4899
|
+
...def.height != null ? { height: def.height } : {}
|
|
4900
|
+
}
|
|
4901
|
+
),
|
|
4902
|
+
isLoadingGrades && /* @__PURE__ */ jsx("p", { className: "mt-2 text-xs text-muted-foreground", children: "Checking diagnosis grades..." }),
|
|
4903
|
+
!isLoadingGrades && gradeGroups.length > 0 && /* @__PURE__ */ jsx(
|
|
4904
|
+
"div",
|
|
4905
|
+
{
|
|
4906
|
+
className: "mt-2 space-y-3 rounded-lg border border-border bg-muted/30 p-3",
|
|
4907
|
+
role: "group",
|
|
4908
|
+
"aria-label": "Diagnosis grade options",
|
|
4909
|
+
children: gradeGroups.map((group) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5", children: [
|
|
4910
|
+
/* @__PURE__ */ jsxs("span", { className: "text-xs font-medium leading-none text-muted-foreground", children: [
|
|
4911
|
+
group.condition,
|
|
4912
|
+
":"
|
|
4913
|
+
] }),
|
|
4914
|
+
/* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2", children: group.grades.map((grade) => /* @__PURE__ */ jsx(
|
|
4915
|
+
"button",
|
|
4916
|
+
{
|
|
4917
|
+
type: "button",
|
|
4918
|
+
onClick: () => toggleSelectedGrade(group.condition, grade),
|
|
4919
|
+
disabled,
|
|
4920
|
+
className: cn(
|
|
4921
|
+
"inline-flex min-h-8 items-center rounded-full border px-3 py-1 text-xs font-medium leading-none transition-colors",
|
|
4922
|
+
normalized.selectedGradesByCondition[group.condition] === grade ? "border-primary bg-primary/15 text-primary shadow-sm" : "border-border/80 bg-background text-foreground hover:bg-muted/80",
|
|
4923
|
+
disabled && "cursor-not-allowed opacity-60"
|
|
4924
|
+
),
|
|
4925
|
+
children: grade
|
|
4926
|
+
},
|
|
4927
|
+
`${group.condition}-${grade}`
|
|
4928
|
+
)) })
|
|
4929
|
+
] }, group.condition))
|
|
4930
|
+
}
|
|
4931
|
+
),
|
|
4932
|
+
showError && /* @__PURE__ */ jsx("p", { className: "text-xs text-red-500", children: error })
|
|
4933
|
+
] });
|
|
4934
|
+
};
|
|
4758
4935
|
var DEFAULT_DRAFT = {
|
|
4759
4936
|
gpal: { G: 0, P: 0, A: 0, L: 0 },
|
|
4760
4937
|
lmp: "",
|
|
@@ -7108,6 +7285,8 @@ var FieldRenderer = ({ fieldId }) => {
|
|
|
7108
7285
|
return /* @__PURE__ */ jsx(FollowupWidget, { fieldId });
|
|
7109
7286
|
case "smart_textarea":
|
|
7110
7287
|
return /* @__PURE__ */ jsx(SmartTextareaWidget, { fieldId });
|
|
7288
|
+
case "diagnosis_textarea":
|
|
7289
|
+
return /* @__PURE__ */ jsx(DiagnosisTextareaWidget, { fieldId });
|
|
7111
7290
|
case "obstetric_history":
|
|
7112
7291
|
return /* @__PURE__ */ jsx(ObstetricHistoryWidget, { fieldId });
|
|
7113
7292
|
case "eye_prescription":
|