formanitor 0.0.41 → 0.0.43
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 +792 -871
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +24 -40
- package/dist/index.d.ts +24 -40
- package/dist/index.mjs +793 -869
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -30,326 +30,6 @@ function fieldMetaRequestsMarMedicationOrdersButton(meta) {
|
|
|
30
30
|
return meta[MAR_MEDICATION_ORDERS_META_KEY] === true;
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
// src/core/urologyClinicalPathwayMetadata.ts
|
|
34
|
-
function isUrologyTemplate(template) {
|
|
35
|
-
if (!template || typeof template !== "object") return false;
|
|
36
|
-
const t = template;
|
|
37
|
-
return t.meta?.specialization === "urology" || t.specialization === "urology" || t.id === "uro_prescription";
|
|
38
|
-
}
|
|
39
|
-
function shouldFoldUrologyClinicalPathway(template, payload) {
|
|
40
|
-
if (isUrologyTemplate(template)) return true;
|
|
41
|
-
return Object.keys(payload).some(
|
|
42
|
-
(k) => k.startsWith("uro_") || k === "chief_complaints" || k === "chief_complaints_chips"
|
|
43
|
-
);
|
|
44
|
-
}
|
|
45
|
-
var UROLOGY_EXTRA_METADATA_KEYS = ["symptoms", "notes", "vitals"];
|
|
46
|
-
function isUroPlainObject(v) {
|
|
47
|
-
return v !== null && typeof v === "object" && !Array.isArray(v);
|
|
48
|
-
}
|
|
49
|
-
function coerceUrologyBool(value) {
|
|
50
|
-
if (value === true || value === false) return value;
|
|
51
|
-
if (value === "true") return true;
|
|
52
|
-
if (value === "false") return false;
|
|
53
|
-
if (Array.isArray(value)) {
|
|
54
|
-
if (value.includes("yes") || value.includes(true)) return true;
|
|
55
|
-
if (value.length === 0) return false;
|
|
56
|
-
}
|
|
57
|
-
return value;
|
|
58
|
-
}
|
|
59
|
-
function urologyIpssItem(v) {
|
|
60
|
-
const n = Number(v);
|
|
61
|
-
if (!Number.isFinite(n)) return 0;
|
|
62
|
-
return Math.min(5, Math.max(0, Math.round(n)));
|
|
63
|
-
}
|
|
64
|
-
function urologyIpssSevenTotalFromParts(ipss) {
|
|
65
|
-
return ipss.incomplete + ipss.frequency + ipss.intermittency + ipss.urgency + ipss.weakStream + ipss.straining + ipss.nocturia;
|
|
66
|
-
}
|
|
67
|
-
function buildUrologySmartHistoryFromLegacyFlat(flat) {
|
|
68
|
-
return {
|
|
69
|
-
socrates_pain_flank_suprapubic: {
|
|
70
|
-
site: flat.uro_sh_socrates_site,
|
|
71
|
-
onset: flat.uro_sh_socrates_onset,
|
|
72
|
-
character: flat.uro_sh_socrates_character,
|
|
73
|
-
radiation: flat.uro_sh_socrates_radiation,
|
|
74
|
-
associated: flat.uro_sh_socrates_associated,
|
|
75
|
-
timing: flat.uro_sh_socrates_timing,
|
|
76
|
-
exacerbating: flat.uro_sh_socrates_exacerbating,
|
|
77
|
-
severity_0_to_10: flat.uro_sh_socrates_severity
|
|
78
|
-
},
|
|
79
|
-
ipss_international_symptom_score: {
|
|
80
|
-
incomplete_emptying: flat.uro_sh_ipss_incomplete,
|
|
81
|
-
frequency_lt_2h: flat.uro_sh_ipss_frequency,
|
|
82
|
-
intermittency: flat.uro_sh_ipss_intermittency,
|
|
83
|
-
urgency: flat.uro_sh_ipss_urgency,
|
|
84
|
-
weak_stream: flat.uro_sh_ipss_weak_stream,
|
|
85
|
-
straining: flat.uro_sh_ipss_straining,
|
|
86
|
-
nocturia: flat.uro_sh_ipss_nocturia,
|
|
87
|
-
qol_0_to_6: flat.uro_sh_ipss_qol,
|
|
88
|
-
seven_item_total_computed_max_35: flat.uro_sh_ipss_total_display
|
|
89
|
-
},
|
|
90
|
-
haematuria_profile: {
|
|
91
|
-
present: flat.uro_sh_haem_present,
|
|
92
|
-
timing: flat.uro_sh_haem_timing,
|
|
93
|
-
painful: flat.uro_sh_haem_painful,
|
|
94
|
-
clots: flat.uro_sh_haem_clots
|
|
95
|
-
},
|
|
96
|
-
sexual_and_reproductive: {
|
|
97
|
-
erectile_function: flat.uro_sh_sex_erectile,
|
|
98
|
-
libido: flat.uro_sh_sex_libido,
|
|
99
|
-
ejaculation: flat.uro_sh_sex_ejaculation,
|
|
100
|
-
infertility_months: flat.uro_sh_sex_infertility_months
|
|
101
|
-
},
|
|
102
|
-
context_prior_stones_surgery_comorbidity: flat.uro_smart_notes_free ?? ""
|
|
103
|
-
};
|
|
104
|
-
}
|
|
105
|
-
function buildUrologySmartHistoryFromComposite(raw, flat) {
|
|
106
|
-
const soc = isUroPlainObject(raw.socrates) ? raw.socrates : {};
|
|
107
|
-
const ipssIn = isUroPlainObject(raw.ipss) ? raw.ipss : {};
|
|
108
|
-
const haem = isUroPlainObject(raw.haematuria) ? raw.haematuria : {};
|
|
109
|
-
const sex = isUroPlainObject(raw.sexual) ? raw.sexual : {};
|
|
110
|
-
const str2 = (x) => typeof x === "string" ? x : "";
|
|
111
|
-
const sev = Number(soc.severity);
|
|
112
|
-
const severity0to10 = Number.isFinite(sev) ? Math.min(10, Math.max(0, Math.round(sev))) : 0;
|
|
113
|
-
const ipss = {
|
|
114
|
-
incomplete: urologyIpssItem(ipssIn.incomplete),
|
|
115
|
-
frequency: urologyIpssItem(ipssIn.frequency),
|
|
116
|
-
intermittency: urologyIpssItem(ipssIn.intermittency),
|
|
117
|
-
urgency: urologyIpssItem(ipssIn.urgency),
|
|
118
|
-
weakStream: urologyIpssItem(
|
|
119
|
-
ipssIn.weakStream ?? ipssIn.weak_stream
|
|
120
|
-
),
|
|
121
|
-
straining: urologyIpssItem(ipssIn.straining),
|
|
122
|
-
nocturia: urologyIpssItem(ipssIn.nocturia)
|
|
123
|
-
};
|
|
124
|
-
const sevenTotal = urologyIpssSevenTotalFromParts(ipss);
|
|
125
|
-
const qolRaw = Number(raw.ipssQoL);
|
|
126
|
-
const qol = Number.isFinite(qolRaw) ? Math.min(6, Math.max(0, Math.round(qolRaw))) : 0;
|
|
127
|
-
const timingRaw = str2(haem.timing);
|
|
128
|
-
const pastNotes = str2(raw.pastNotes);
|
|
129
|
-
const legacyNotes = flat.uro_smart_notes_free;
|
|
130
|
-
const contextPrior = pastNotes !== "" ? pastNotes : typeof legacyNotes === "string" ? legacyNotes : legacyNotes ?? "";
|
|
131
|
-
const infertilityRaw = Number(sex.infertilityMonths);
|
|
132
|
-
const infertilityMonths = Number.isFinite(infertilityRaw) ? Math.max(0, Math.round(infertilityRaw)) : 0;
|
|
133
|
-
return {
|
|
134
|
-
socrates_pain_flank_suprapubic: {
|
|
135
|
-
site: str2(soc.site),
|
|
136
|
-
onset: str2(soc.onset),
|
|
137
|
-
character: str2(soc.character),
|
|
138
|
-
radiation: str2(soc.radiation),
|
|
139
|
-
associated: str2(soc.associated),
|
|
140
|
-
timing: str2(soc.timing),
|
|
141
|
-
exacerbating: str2(soc.exacerbating),
|
|
142
|
-
severity_0_to_10: severity0to10
|
|
143
|
-
},
|
|
144
|
-
ipss_international_symptom_score: {
|
|
145
|
-
incomplete_emptying: ipss.incomplete,
|
|
146
|
-
frequency_lt_2h: ipss.frequency,
|
|
147
|
-
intermittency: ipss.intermittency,
|
|
148
|
-
urgency: ipss.urgency,
|
|
149
|
-
weak_stream: ipss.weakStream,
|
|
150
|
-
straining: ipss.straining,
|
|
151
|
-
nocturia: ipss.nocturia,
|
|
152
|
-
qol_0_to_6: qol,
|
|
153
|
-
seven_item_total_computed_max_35: sevenTotal
|
|
154
|
-
},
|
|
155
|
-
haematuria_profile: {
|
|
156
|
-
present: haem.present === true,
|
|
157
|
-
timing: timingRaw,
|
|
158
|
-
painful: haem.painful === true,
|
|
159
|
-
clots: haem.clots === true
|
|
160
|
-
},
|
|
161
|
-
sexual_and_reproductive: {
|
|
162
|
-
erectile_function: str2(sex.erectile),
|
|
163
|
-
libido: str2(sex.libido),
|
|
164
|
-
ejaculation: str2(sex.ejaculation),
|
|
165
|
-
infertility_months: infertilityMonths
|
|
166
|
-
},
|
|
167
|
-
context_prior_stones_surgery_comorbidity: contextPrior
|
|
168
|
-
};
|
|
169
|
-
}
|
|
170
|
-
function buildUrologyExaminationFromLegacyFlat(flat) {
|
|
171
|
-
return {
|
|
172
|
-
general: {
|
|
173
|
-
pallor: flat.uro_ex_general_pallor,
|
|
174
|
-
oedema: flat.uro_ex_general_oedema,
|
|
175
|
-
icterus: flat.uro_ex_general_icterus,
|
|
176
|
-
lymphadenopathy: flat.uro_ex_general_lymph
|
|
177
|
-
},
|
|
178
|
-
abdomen: {
|
|
179
|
-
distension: flat.uro_ex_ab_distension,
|
|
180
|
-
surgical_scars: flat.uro_ex_ab_scars,
|
|
181
|
-
visible_mass: flat.uro_ex_ab_mass,
|
|
182
|
-
kidney_palpable: flat.uro_ex_ab_kidney_palpable,
|
|
183
|
-
bladder_palpable: flat.uro_ex_ab_bladder_palpable,
|
|
184
|
-
renal_angle_tender: flat.uro_ex_ab_renal_angle_tender,
|
|
185
|
-
bladder_dullness_retention: flat.uro_ex_ab_bladder_dull
|
|
186
|
-
},
|
|
187
|
-
external_genitalia_scrotum: {
|
|
188
|
-
meatus_abnormal_hypospadias_query: flat.uro_ex_gu_meatus,
|
|
189
|
-
phimosis_paraphimosis: flat.uro_ex_gu_phimosis,
|
|
190
|
-
penile_lesions_ulcers: flat.uro_ex_gu_lesions,
|
|
191
|
-
scrotal_swelling: flat.uro_ex_gu_scrotal_swelling,
|
|
192
|
-
transilluminant: flat.uro_ex_gu_transilluminant,
|
|
193
|
-
tender_testis: flat.uro_ex_gu_tender_testis,
|
|
194
|
-
hydrocele: flat.uro_ex_gu_hydrocele,
|
|
195
|
-
varicocele: flat.uro_ex_gu_varicocele,
|
|
196
|
-
suspicious_mass_urgent: flat.uro_ex_gu_suspicious_mass
|
|
197
|
-
},
|
|
198
|
-
dre_prostate: {
|
|
199
|
-
dre_performed: flat.uro_ex_dre_done,
|
|
200
|
-
estimated_size_grams: flat.uro_ex_dre_size_g,
|
|
201
|
-
consistency: flat.uro_ex_dre_consistency,
|
|
202
|
-
median_sulcus: flat.uro_ex_dre_median_sulcus,
|
|
203
|
-
tenderness_prostatitis_query: flat.uro_ex_dre_tender
|
|
204
|
-
},
|
|
205
|
-
examination_notes_free_text: flat.uro_examination_notes ?? ""
|
|
206
|
-
};
|
|
207
|
-
}
|
|
208
|
-
function buildUrologyExaminationFromComposite(raw) {
|
|
209
|
-
const regions = Array.isArray(raw.regions) ? raw.regions.filter((x) => typeof x === "string") : [];
|
|
210
|
-
const g = isUroPlainObject(raw.general) ? raw.general : {};
|
|
211
|
-
const ab = isUroPlainObject(raw.abdomen) ? raw.abdomen : {};
|
|
212
|
-
const gu = isUroPlainObject(raw.gu) ? raw.gu : {};
|
|
213
|
-
const dr = isUroPlainObject(raw.dre) ? raw.dre : {};
|
|
214
|
-
const dreConsistency = typeof dr.consistency === "string" ? dr.consistency : "";
|
|
215
|
-
const dreMedian = typeof dr.medianSulcus === "string" ? dr.medianSulcus : typeof dr.median_sulcus === "string" ? dr.median_sulcus : "";
|
|
216
|
-
const sizeG = Number(dr.sizeGrams);
|
|
217
|
-
const sizeGrams = Number.isFinite(sizeG) && sizeG >= 0 ? Math.round(sizeG) : 0;
|
|
218
|
-
const notesRaw = raw.examinationNotes;
|
|
219
|
-
const notes = typeof notesRaw === "string" ? notesRaw : "";
|
|
220
|
-
const bool = (x) => x === true;
|
|
221
|
-
return {
|
|
222
|
-
regions_reviewed: regions,
|
|
223
|
-
general: {
|
|
224
|
-
pallor: bool(g.pallor),
|
|
225
|
-
oedema: bool(g.oedema),
|
|
226
|
-
icterus: bool(g.icterus),
|
|
227
|
-
lymphadenopathy: bool(g.lymphadenopathy)
|
|
228
|
-
},
|
|
229
|
-
abdomen: {
|
|
230
|
-
distension: bool(ab.distension),
|
|
231
|
-
surgical_scars: bool(ab.scars),
|
|
232
|
-
visible_mass: bool(ab.mass),
|
|
233
|
-
kidney_palpable: bool(ab.kidneyPalpable),
|
|
234
|
-
bladder_palpable: bool(ab.bladderPalpable),
|
|
235
|
-
renal_angle_tender: bool(ab.renalAngleTender),
|
|
236
|
-
bladder_dullness_retention: bool(ab.bladderDull)
|
|
237
|
-
},
|
|
238
|
-
external_genitalia_scrotum: {
|
|
239
|
-
meatus_abnormal_hypospadias_query: bool(gu.meatusAbnormal),
|
|
240
|
-
phimosis_paraphimosis: bool(gu.phimosis),
|
|
241
|
-
penile_lesions_ulcers: bool(gu.lesions),
|
|
242
|
-
scrotal_swelling: bool(gu.scrotalSwelling),
|
|
243
|
-
transilluminant: bool(gu.transilluminant),
|
|
244
|
-
tender_testis: bool(gu.tenderTestis),
|
|
245
|
-
hydrocele: bool(gu.hydrocele),
|
|
246
|
-
varicocele: bool(gu.varicocele),
|
|
247
|
-
suspicious_mass_urgent: bool(gu.suspiciousMass)
|
|
248
|
-
},
|
|
249
|
-
dre_prostate: {
|
|
250
|
-
dre_performed: bool(dr.done),
|
|
251
|
-
estimated_size_grams: sizeGrams,
|
|
252
|
-
consistency: dreConsistency === "none" ? "" : dreConsistency,
|
|
253
|
-
median_sulcus: dreMedian === "none" ? "" : dreMedian,
|
|
254
|
-
tenderness_prostatitis_query: bool(dr.tenderness)
|
|
255
|
-
},
|
|
256
|
-
examination_notes_free_text: notes
|
|
257
|
-
};
|
|
258
|
-
}
|
|
259
|
-
function buildUrologyDecisionEngineAndRisk(flat) {
|
|
260
|
-
const comp = flat.uro_pathway;
|
|
261
|
-
if (isUroPlainObject(comp)) {
|
|
262
|
-
const riskIn = isUroPlainObject(comp.risk) ? comp.risk : {};
|
|
263
|
-
return {
|
|
264
|
-
decision_engine: {
|
|
265
|
-
stone_disease: {
|
|
266
|
-
stone_size_mm: comp.stoneSizeMm ?? 0,
|
|
267
|
-
hydronephrosis_on_imaging: coerceUrologyBool(comp.hydronephrosis)
|
|
268
|
-
},
|
|
269
|
-
prostate_bph_flow_lab: {
|
|
270
|
-
prostate_volume_cc: comp.prostateVolumeCc ?? 0,
|
|
271
|
-
psa_ng_ml: comp.psaNgMl ?? 0,
|
|
272
|
-
uroflow_qmax_ml_s: comp.uroflowQmaxMlSec ?? 0
|
|
273
|
-
}
|
|
274
|
-
},
|
|
275
|
-
risk_stratification: {
|
|
276
|
-
ckd: coerceUrologyBool(riskIn.ckd),
|
|
277
|
-
diabetes: coerceUrologyBool(riskIn.diabetes),
|
|
278
|
-
anticoagulants: coerceUrologyBool(riskIn.anticoagulants),
|
|
279
|
-
active_infection: coerceUrologyBool(riskIn.activeInfection)
|
|
280
|
-
}
|
|
281
|
-
};
|
|
282
|
-
}
|
|
283
|
-
return {
|
|
284
|
-
decision_engine: {
|
|
285
|
-
stone_disease: {
|
|
286
|
-
stone_size_mm: flat.uro_stone_size_mm,
|
|
287
|
-
hydronephrosis_on_imaging: coerceUrologyBool(flat.uro_stone_hydronephrosis)
|
|
288
|
-
},
|
|
289
|
-
prostate_bph_flow_lab: {
|
|
290
|
-
prostate_volume_cc: flat.uro_prostate_vol_cc,
|
|
291
|
-
psa_ng_ml: flat.uro_psa_ng_ml,
|
|
292
|
-
uroflow_qmax_ml_s: flat.uro_flow_qmax
|
|
293
|
-
}
|
|
294
|
-
},
|
|
295
|
-
risk_stratification: {
|
|
296
|
-
ckd: coerceUrologyBool(flat.uro_risk_ckd),
|
|
297
|
-
diabetes: coerceUrologyBool(flat.uro_risk_diabetes),
|
|
298
|
-
anticoagulants: coerceUrologyBool(flat.uro_risk_anticoag),
|
|
299
|
-
active_infection: coerceUrologyBool(flat.uro_risk_active_infection)
|
|
300
|
-
}
|
|
301
|
-
};
|
|
302
|
-
}
|
|
303
|
-
function attachUrologyClinicalPathwayMetadata(payload, template) {
|
|
304
|
-
if (!shouldFoldUrologyClinicalPathway(template, payload)) return;
|
|
305
|
-
const extra = UROLOGY_EXTRA_METADATA_KEYS;
|
|
306
|
-
const keys = Object.keys(payload).filter(
|
|
307
|
-
(k) => k.startsWith("uro_") || k === "chief_complaints" || k === "chief_complaints_chips" || extra.includes(k)
|
|
308
|
-
);
|
|
309
|
-
if (keys.length === 0) return;
|
|
310
|
-
const flat = {};
|
|
311
|
-
for (const k of keys) {
|
|
312
|
-
flat[k] = payload[k];
|
|
313
|
-
delete payload[k];
|
|
314
|
-
}
|
|
315
|
-
const triage = flat.uro_triage;
|
|
316
|
-
const chiefComplaints = {
|
|
317
|
-
narrative: flat.chief_complaints ?? "",
|
|
318
|
-
chips: flat.chief_complaints_chips ?? [],
|
|
319
|
-
duration: flat.uro_chief_duration ?? "",
|
|
320
|
-
onset: flat.uro_chief_onset ?? "",
|
|
321
|
-
progression: flat.uro_chief_progression ?? "",
|
|
322
|
-
active_syndrome: flat.uro_active_syndrome ?? ""
|
|
323
|
-
};
|
|
324
|
-
const compositeSh = flat.uro_smart_history;
|
|
325
|
-
const compositeEx = flat.uro_examination;
|
|
326
|
-
const smart_history = isUroPlainObject(compositeSh) ? buildUrologySmartHistoryFromComposite(compositeSh, flat) : buildUrologySmartHistoryFromLegacyFlat(flat);
|
|
327
|
-
const examination = isUroPlainObject(compositeEx) ? buildUrologyExaminationFromComposite(compositeEx) : buildUrologyExaminationFromLegacyFlat(flat);
|
|
328
|
-
const { decision_engine, risk_stratification } = buildUrologyDecisionEngineAndRisk(flat);
|
|
329
|
-
const structured = {
|
|
330
|
-
triage_vas_and_flags: triage ?? null,
|
|
331
|
-
chief_complaint_engine: chiefComplaints,
|
|
332
|
-
smart_history,
|
|
333
|
-
examination,
|
|
334
|
-
pathway_triggers_objective_scores: decision_engine,
|
|
335
|
-
risk_stratification,
|
|
336
|
-
encounter_narrative: {
|
|
337
|
-
symptoms: flat.symptoms ?? "",
|
|
338
|
-
notes: flat.notes ?? "",
|
|
339
|
-
vitals: flat.vitals ?? ""
|
|
340
|
-
}
|
|
341
|
-
};
|
|
342
|
-
const existingMetadata = payload.metadata ?? {};
|
|
343
|
-
const existingPathways = existingMetadata.clinical_pathways ?? {};
|
|
344
|
-
payload.metadata = {
|
|
345
|
-
...existingMetadata,
|
|
346
|
-
clinical_pathways: {
|
|
347
|
-
...existingPathways,
|
|
348
|
-
urology: structured
|
|
349
|
-
}
|
|
350
|
-
};
|
|
351
|
-
}
|
|
352
|
-
|
|
353
33
|
// src/core/validate.ts
|
|
354
34
|
var EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
355
35
|
function validateField(value, field) {
|
|
@@ -422,12 +102,82 @@ function validateForm(values, fields) {
|
|
|
422
102
|
return errors;
|
|
423
103
|
}
|
|
424
104
|
|
|
105
|
+
// src/core/suggestionTokens.ts
|
|
106
|
+
function getSuggestionTokensFromText(text) {
|
|
107
|
+
return text.split(/[,\n\r]+/).map((p) => p.trim()).filter(Boolean);
|
|
108
|
+
}
|
|
109
|
+
var DEFAULT_TOKEN_SEPARATOR = ", ";
|
|
110
|
+
function commaSplitLine(line) {
|
|
111
|
+
return line.split(",").map((p) => p.trim()).filter(Boolean);
|
|
112
|
+
}
|
|
113
|
+
function dedupeChipOrder(chips) {
|
|
114
|
+
const seen = /* @__PURE__ */ new Set();
|
|
115
|
+
const out = [];
|
|
116
|
+
for (const c of chips) {
|
|
117
|
+
if (seen.has(c)) continue;
|
|
118
|
+
seen.add(c);
|
|
119
|
+
out.push(c);
|
|
120
|
+
}
|
|
121
|
+
return out;
|
|
122
|
+
}
|
|
123
|
+
function parseProseAndChipTokens(text, allowed) {
|
|
124
|
+
const normalized = text.replace(/\r\n/g, "\n");
|
|
125
|
+
let lines = normalized.split("\n");
|
|
126
|
+
while (lines.length > 0 && lines[lines.length - 1] === "") {
|
|
127
|
+
lines.pop();
|
|
128
|
+
}
|
|
129
|
+
if (lines.length === 0) return { prose: "", chips: [] };
|
|
130
|
+
let chipStart = lines.length;
|
|
131
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
132
|
+
const toks = commaSplitLine(lines[i]);
|
|
133
|
+
if (toks.length === 0) break;
|
|
134
|
+
if (!toks.every((t) => allowed.has(t))) break;
|
|
135
|
+
chipStart = i;
|
|
136
|
+
}
|
|
137
|
+
if (chipStart < lines.length) {
|
|
138
|
+
const chipLines = lines.slice(chipStart);
|
|
139
|
+
const prose = lines.slice(0, chipStart).join("\n");
|
|
140
|
+
const chips = dedupeChipOrder(chipLines.flatMap(commaSplitLine));
|
|
141
|
+
return { prose, chips };
|
|
142
|
+
}
|
|
143
|
+
const parts = getSuggestionTokensFromText(normalized);
|
|
144
|
+
const chipsFallback = dedupeChipOrder(parts.filter((t) => allowed.has(t)));
|
|
145
|
+
const proseParts = parts.filter((t) => !allowed.has(t));
|
|
146
|
+
return { prose: proseParts.join(DEFAULT_TOKEN_SEPARATOR), chips: chipsFallback };
|
|
147
|
+
}
|
|
148
|
+
function composeProseAndChips(prose, chips, separator = DEFAULT_TOKEN_SEPARATOR) {
|
|
149
|
+
const chipStr = dedupeChipOrder(chips).join(separator);
|
|
150
|
+
const p = prose.replace(/\s+$/, "");
|
|
151
|
+
if (p && chipStr) return `${p}
|
|
152
|
+
${chipStr}`;
|
|
153
|
+
if (chipStr) return chipStr;
|
|
154
|
+
return p;
|
|
155
|
+
}
|
|
156
|
+
function toggleSuggestionTokenInText(current, token, separator = DEFAULT_TOKEN_SEPARATOR, allowedChipValues) {
|
|
157
|
+
const t = String(token).trim();
|
|
158
|
+
if (!t) return current;
|
|
159
|
+
if (!allowedChipValues || allowedChipValues.size === 0) {
|
|
160
|
+
const parts = getSuggestionTokensFromText(current);
|
|
161
|
+
const i = parts.findIndex((p) => p === t);
|
|
162
|
+
if (i >= 0) parts.splice(i, 1);
|
|
163
|
+
else parts.push(t);
|
|
164
|
+
return parts.join(separator);
|
|
165
|
+
}
|
|
166
|
+
if (!allowedChipValues.has(t)) return current;
|
|
167
|
+
let { prose, chips } = parseProseAndChipTokens(current, allowedChipValues);
|
|
168
|
+
const idx = chips.indexOf(t);
|
|
169
|
+
if (idx >= 0) chips.splice(idx, 1);
|
|
170
|
+
else chips.push(t);
|
|
171
|
+
chips = dedupeChipOrder(chips);
|
|
172
|
+
return composeProseAndChips(prose, chips, separator);
|
|
173
|
+
}
|
|
174
|
+
|
|
425
175
|
// src/core/rules.ts
|
|
426
176
|
function tokenListContainsString(text, needle) {
|
|
427
177
|
if (typeof text !== "string") return false;
|
|
428
178
|
const want = String(needle).trim();
|
|
429
179
|
if (!want) return false;
|
|
430
|
-
const parts = text
|
|
180
|
+
const parts = getSuggestionTokensFromText(text);
|
|
431
181
|
return parts.includes(want);
|
|
432
182
|
}
|
|
433
183
|
function evaluateCondition(value, condition) {
|
|
@@ -638,7 +388,7 @@ function normalizeGeneralSurgerySmartHistory(raw) {
|
|
|
638
388
|
...painIn,
|
|
639
389
|
severity: Number.isFinite(sev) ? Math.min(10, Math.max(0, Math.round(sev))) : d.pain.severity
|
|
640
390
|
};
|
|
641
|
-
const
|
|
391
|
+
const str4 = (x) => typeof x === "string" ? x : "";
|
|
642
392
|
const strArr = (x) => Array.isArray(x) ? x.filter((i) => typeof i === "string") : [];
|
|
643
393
|
const swell = v.swelling && typeof v.swelling === "object" ? v.swelling : {};
|
|
644
394
|
const gi = v.gi && typeof v.gi === "object" ? v.gi : {};
|
|
@@ -648,44 +398,44 @@ function normalizeGeneralSurgerySmartHistory(raw) {
|
|
|
648
398
|
return {
|
|
649
399
|
pain,
|
|
650
400
|
swelling: {
|
|
651
|
-
duration:
|
|
652
|
-
sizeProgression:
|
|
653
|
-
painfulPainless:
|
|
401
|
+
duration: str4(swell.duration),
|
|
402
|
+
sizeProgression: str4(swell.sizeProgression),
|
|
403
|
+
painfulPainless: str4(swell.painfulPainless),
|
|
654
404
|
checks: strArr(swell.checks)
|
|
655
405
|
},
|
|
656
406
|
gi: {
|
|
657
|
-
appetite:
|
|
658
|
-
weightLoss:
|
|
659
|
-
bowelHabits:
|
|
407
|
+
appetite: str4(gi.appetite),
|
|
408
|
+
weightLoss: str4(gi.weightLoss),
|
|
409
|
+
bowelHabits: str4(gi.bowelHabits),
|
|
660
410
|
checks: strArr(gi.checks)
|
|
661
411
|
},
|
|
662
412
|
breast: {
|
|
663
|
-
lumpDuration:
|
|
664
|
-
nippleDischarge:
|
|
413
|
+
lumpDuration: str4(breast.lumpDuration),
|
|
414
|
+
nippleDischarge: str4(breast.nippleDischarge),
|
|
665
415
|
checks: strArr(breast.checks)
|
|
666
416
|
},
|
|
667
417
|
ano: { checks: strArr(ano.checks) },
|
|
668
418
|
thyroid: {
|
|
669
|
-
swellingDuration:
|
|
419
|
+
swellingDuration: str4(thy.swellingDuration),
|
|
670
420
|
checks: strArr(thy.checks)
|
|
671
421
|
}
|
|
672
422
|
};
|
|
673
423
|
}
|
|
674
424
|
function normalizeBreastExamSide(partial) {
|
|
675
425
|
const e = defaultBreastExamSide();
|
|
676
|
-
const
|
|
677
|
-
const
|
|
426
|
+
const str4 = (x) => typeof x === "string" ? x : "";
|
|
427
|
+
const bool2 = (x) => x === true;
|
|
678
428
|
if (!partial || typeof partial !== "object") return e;
|
|
679
429
|
const p = partial;
|
|
680
430
|
return {
|
|
681
|
-
size:
|
|
682
|
-
quadrant:
|
|
683
|
-
tenderness:
|
|
684
|
-
fixity:
|
|
685
|
-
skinInvolvement:
|
|
686
|
-
consistency:
|
|
687
|
-
axillaryNodes:
|
|
688
|
-
nippleAreolarComplex:
|
|
431
|
+
size: str4(p.size),
|
|
432
|
+
quadrant: str4(p.quadrant),
|
|
433
|
+
tenderness: str4(p.tenderness),
|
|
434
|
+
fixity: str4(p.fixity),
|
|
435
|
+
skinInvolvement: str4(p.skinInvolvement),
|
|
436
|
+
consistency: str4(p.consistency),
|
|
437
|
+
axillaryNodes: bool2(p.axillaryNodes),
|
|
438
|
+
nippleAreolarComplex: bool2(p.nippleAreolarComplex)
|
|
689
439
|
};
|
|
690
440
|
}
|
|
691
441
|
function normalizeBreastExaminationBlock(raw) {
|
|
@@ -709,7 +459,7 @@ function normalizeGeneralSurgeryExamination(raw) {
|
|
|
709
459
|
const th = v.thyroid && typeof v.thyroid === "object" ? v.thyroid : {};
|
|
710
460
|
const ar = v.anorectal && typeof v.anorectal === "object" ? v.anorectal : {};
|
|
711
461
|
const lm = v.limb && typeof v.limb === "object" ? v.limb : {};
|
|
712
|
-
const
|
|
462
|
+
const bool2 = (x) => x === true;
|
|
713
463
|
return {
|
|
714
464
|
general: strArr(v.general),
|
|
715
465
|
regions: strArr(v.regions),
|
|
@@ -722,27 +472,27 @@ function normalizeGeneralSurgeryExamination(raw) {
|
|
|
722
472
|
},
|
|
723
473
|
hernia: {
|
|
724
474
|
site: typeof hb.site === "string" ? hb.site : "",
|
|
725
|
-
reducible:
|
|
726
|
-
coughImpulse:
|
|
727
|
-
tenderness:
|
|
475
|
+
reducible: bool2(hb.reducible),
|
|
476
|
+
coughImpulse: bool2(hb.coughImpulse),
|
|
477
|
+
tenderness: bool2(hb.tenderness)
|
|
728
478
|
},
|
|
729
479
|
breast: normalizeBreastExaminationBlock(br),
|
|
730
480
|
thyroid: {
|
|
731
481
|
size: typeof th.size === "string" ? th.size : "",
|
|
732
|
-
mobileDeglutition:
|
|
733
|
-
nodules:
|
|
734
|
-
cervicalNodes:
|
|
482
|
+
mobileDeglutition: bool2(th.mobileDeglutition),
|
|
483
|
+
nodules: bool2(th.nodules),
|
|
484
|
+
cervicalNodes: bool2(th.cervicalNodes)
|
|
735
485
|
},
|
|
736
486
|
anorectal: {
|
|
737
487
|
inspection: typeof ar.inspection === "string" ? ar.inspection : "",
|
|
738
|
-
dreDone:
|
|
739
|
-
proctoscopyDone:
|
|
488
|
+
dreDone: bool2(ar.dreDone),
|
|
489
|
+
proctoscopyDone: bool2(ar.proctoscopyDone),
|
|
740
490
|
notes: typeof ar.notes === "string" ? ar.notes : ""
|
|
741
491
|
},
|
|
742
492
|
limb: {
|
|
743
|
-
dilatedVeins:
|
|
744
|
-
ulcer:
|
|
745
|
-
oedema:
|
|
493
|
+
dilatedVeins: bool2(lm.dilatedVeins),
|
|
494
|
+
ulcer: bool2(lm.ulcer),
|
|
495
|
+
oedema: bool2(lm.oedema)
|
|
746
496
|
}
|
|
747
497
|
};
|
|
748
498
|
}
|
|
@@ -1019,70 +769,102 @@ function formatGeneralSurgeryExaminationToNarrative(v) {
|
|
|
1019
769
|
}
|
|
1020
770
|
|
|
1021
771
|
// src/core/urologyPathway.ts
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
772
|
+
function defaultUrologySmartHistory() {
|
|
773
|
+
return {
|
|
774
|
+
socrates: {
|
|
775
|
+
site: "",
|
|
776
|
+
onset: "",
|
|
777
|
+
character: "",
|
|
778
|
+
radiation: "",
|
|
779
|
+
associated: "",
|
|
780
|
+
timing: "",
|
|
781
|
+
exacerbating: "",
|
|
782
|
+
severity: 0
|
|
783
|
+
},
|
|
784
|
+
ipss: {
|
|
785
|
+
incomplete: 0,
|
|
786
|
+
frequency: 0,
|
|
787
|
+
intermittency: 0,
|
|
788
|
+
urgency: 0,
|
|
789
|
+
weakStream: 0,
|
|
790
|
+
straining: 0,
|
|
791
|
+
nocturia: 0
|
|
792
|
+
},
|
|
793
|
+
ipssQoL: 0,
|
|
794
|
+
haematuria: {
|
|
795
|
+
present: false,
|
|
796
|
+
timing: "none",
|
|
797
|
+
painful: false,
|
|
798
|
+
clots: false
|
|
799
|
+
},
|
|
800
|
+
sexual: {
|
|
801
|
+
erectile: "none",
|
|
802
|
+
libido: "none",
|
|
803
|
+
ejaculation: "none",
|
|
804
|
+
infertilityMonths: 0
|
|
805
|
+
},
|
|
806
|
+
pastNotes: ""
|
|
807
|
+
};
|
|
808
|
+
}
|
|
809
|
+
function defaultUrologyExamination() {
|
|
810
|
+
return {
|
|
811
|
+
regions: [],
|
|
812
|
+
general: {
|
|
813
|
+
pallor: false,
|
|
814
|
+
oedema: false,
|
|
815
|
+
icterus: false,
|
|
816
|
+
lymphadenopathy: false
|
|
817
|
+
},
|
|
818
|
+
abdomen: {
|
|
819
|
+
distension: false,
|
|
820
|
+
scars: false,
|
|
821
|
+
mass: false,
|
|
822
|
+
kidneyPalpable: false,
|
|
823
|
+
bladderPalpable: false,
|
|
824
|
+
renalAngleTender: false,
|
|
825
|
+
bladderDull: false
|
|
826
|
+
},
|
|
827
|
+
gu: {
|
|
828
|
+
meatusAbnormal: false,
|
|
829
|
+
phimosis: false,
|
|
830
|
+
lesions: false,
|
|
831
|
+
scrotalSwelling: false,
|
|
832
|
+
transilluminant: false,
|
|
833
|
+
tenderTestis: false,
|
|
834
|
+
hydrocele: false,
|
|
835
|
+
varicocele: false,
|
|
836
|
+
suspiciousMass: false
|
|
837
|
+
},
|
|
838
|
+
dre: {
|
|
839
|
+
done: false,
|
|
840
|
+
sizeGrams: 0,
|
|
841
|
+
consistency: "",
|
|
842
|
+
medianSulcus: "",
|
|
843
|
+
tenderness: false
|
|
844
|
+
},
|
|
845
|
+
examinationNotes: ""
|
|
846
|
+
};
|
|
847
|
+
}
|
|
848
|
+
function defaultUrologyPathway() {
|
|
849
|
+
return {
|
|
850
|
+
stoneSizeMm: 0,
|
|
851
|
+
hydronephrosis: false,
|
|
852
|
+
prostateVolumeCc: 0,
|
|
853
|
+
psaNgMl: 0,
|
|
854
|
+
uroflowQmaxMlSec: 0,
|
|
855
|
+
risk: {
|
|
856
|
+
ckd: false,
|
|
857
|
+
diabetes: false,
|
|
858
|
+
anticoagulants: false,
|
|
859
|
+
activeInfection: false
|
|
860
|
+
}
|
|
861
|
+
};
|
|
862
|
+
}
|
|
863
|
+
function ipssItem(v) {
|
|
864
|
+
const n = Number(v);
|
|
865
|
+
if (!Number.isFinite(n)) return 0;
|
|
866
|
+
return Math.min(5, Math.max(0, Math.round(n)));
|
|
1076
867
|
}
|
|
1077
|
-
var SOCRATES_KEYS = [
|
|
1078
|
-
"site",
|
|
1079
|
-
"onset",
|
|
1080
|
-
"character",
|
|
1081
|
-
"radiation",
|
|
1082
|
-
"associated",
|
|
1083
|
-
"timing",
|
|
1084
|
-
"exacerbating"
|
|
1085
|
-
];
|
|
1086
868
|
function urologyIpssSevenTotal(ipss) {
|
|
1087
869
|
return ipss.incomplete + ipss.frequency + ipss.intermittency + ipss.urgency + ipss.weakStream + ipss.straining + ipss.nocturia;
|
|
1088
870
|
}
|
|
@@ -1091,159 +873,269 @@ function urologyIpssBand(total) {
|
|
|
1091
873
|
if (total <= 19) return "Moderate";
|
|
1092
874
|
return "Severe";
|
|
1093
875
|
}
|
|
876
|
+
function hopcMeaningfulStr(x) {
|
|
877
|
+
if (typeof x !== "string") return "";
|
|
878
|
+
const t = x.trim();
|
|
879
|
+
if (!t || t.toLowerCase() === "none") return "";
|
|
880
|
+
return t;
|
|
881
|
+
}
|
|
882
|
+
function hopcNonEmpty(lines) {
|
|
883
|
+
return lines.map((s) => (s ?? "").trim()).filter(Boolean);
|
|
884
|
+
}
|
|
885
|
+
function formatUrologySmartHistoryToSymptomsNarrative(safe, flags) {
|
|
886
|
+
const { showPain, showLUTS, showHaem, showSex } = flags;
|
|
887
|
+
const parts = [];
|
|
888
|
+
if (showPain) {
|
|
889
|
+
const s = safe.socrates;
|
|
890
|
+
const painLines = hopcNonEmpty([
|
|
891
|
+
s.site ? `Site: ${s.site}` : "",
|
|
892
|
+
s.onset ? `Onset: ${s.onset}` : "",
|
|
893
|
+
s.character ? `Character: ${s.character}` : "",
|
|
894
|
+
s.radiation ? `Radiation: ${s.radiation}` : "",
|
|
895
|
+
s.associated ? `Associated: ${s.associated}` : "",
|
|
896
|
+
s.timing ? `Timing: ${s.timing}` : "",
|
|
897
|
+
s.exacerbating ? `Exacerbating/relieving: ${s.exacerbating}` : "",
|
|
898
|
+
`Severity: ${s.severity}/10`
|
|
899
|
+
]);
|
|
900
|
+
const hasNonDefaultPain = painLines.length > 1 || painLines.length === 1 && painLines[0] !== "Severity: 0/10";
|
|
901
|
+
if (hasNonDefaultPain) parts.push(`SOCRATES:
|
|
902
|
+
${painLines.join("\n")}`);
|
|
903
|
+
}
|
|
904
|
+
if (showLUTS) {
|
|
905
|
+
const ip = safe.ipss;
|
|
906
|
+
const any = ip.incomplete || ip.frequency || ip.intermittency || ip.urgency || ip.weakStream || ip.straining || ip.nocturia || safe.ipssQoL;
|
|
907
|
+
if (any) {
|
|
908
|
+
const ipssTotal = urologyIpssSevenTotal(safe.ipss);
|
|
909
|
+
const ipssBandLabel = urologyIpssBand(ipssTotal);
|
|
910
|
+
parts.push(`IPSS: ${ipssTotal}/35 (${ipssBandLabel}) \xB7 QoL ${safe.ipssQoL}/6`);
|
|
911
|
+
}
|
|
912
|
+
}
|
|
913
|
+
if (showHaem) {
|
|
914
|
+
const h = safe.haematuria;
|
|
915
|
+
const timing = hopcMeaningfulStr(h.timing);
|
|
916
|
+
const haemLines = hopcNonEmpty([
|
|
917
|
+
h.present ? "Haematuria present" : "",
|
|
918
|
+
timing ? `Timing: ${timing}` : "",
|
|
919
|
+
h.painful ? "Painful" : "",
|
|
920
|
+
h.clots ? "Clots" : ""
|
|
921
|
+
]);
|
|
922
|
+
if (haemLines.length) parts.push(`Haematuria:
|
|
923
|
+
${haemLines.join("\n")}`);
|
|
924
|
+
}
|
|
925
|
+
if (showSex) {
|
|
926
|
+
const sx = safe.sexual;
|
|
927
|
+
const infertility = sx.infertilityMonths;
|
|
928
|
+
const sexLines = hopcNonEmpty([
|
|
929
|
+
hopcMeaningfulStr(sx.erectile) ? `Erectile function: ${hopcMeaningfulStr(sx.erectile)}` : "",
|
|
930
|
+
hopcMeaningfulStr(sx.libido) ? `Libido: ${hopcMeaningfulStr(sx.libido)}` : "",
|
|
931
|
+
hopcMeaningfulStr(sx.ejaculation) ? `Ejaculation: ${hopcMeaningfulStr(sx.ejaculation)}` : "",
|
|
932
|
+
Number.isFinite(infertility) && infertility > 0 ? `Infertility: ${infertility} months` : ""
|
|
933
|
+
]);
|
|
934
|
+
if (sexLines.length) parts.push(`Sexual/reproductive:
|
|
935
|
+
${sexLines.join("\n")}`);
|
|
936
|
+
}
|
|
937
|
+
return parts.join("\n\n").trim();
|
|
938
|
+
}
|
|
939
|
+
function formatUrologyExaminationToClinicalExamination(v) {
|
|
940
|
+
const sections = [];
|
|
941
|
+
const generalLabels = {
|
|
942
|
+
pallor: "Pallor (chronic dz)",
|
|
943
|
+
oedema: "Oedema (renal)",
|
|
944
|
+
icterus: "Icterus",
|
|
945
|
+
lymphadenopathy: "Lymphadenopathy"
|
|
946
|
+
};
|
|
947
|
+
const general = Object.keys(generalLabels).filter((k) => v.general[k]).map((k) => generalLabels[k]);
|
|
948
|
+
if (general.length) sections.push(`General: ${general.join(", ")}`);
|
|
949
|
+
const abdLabels = {
|
|
950
|
+
distension: "Distension",
|
|
951
|
+
scars: "Surgical scars",
|
|
952
|
+
mass: "Visible mass",
|
|
953
|
+
kidneyPalpable: "Kidney palpable",
|
|
954
|
+
bladderPalpable: "Bladder palpable",
|
|
955
|
+
renalAngleTender: "Renal angle tender",
|
|
956
|
+
bladderDull: "Bladder dullness (retention)"
|
|
957
|
+
};
|
|
958
|
+
const abd = Object.keys(abdLabels).filter((k) => v.abdomen[k]).map((k) => abdLabels[k]);
|
|
959
|
+
if (abd.length) sections.push(`Abdomen: ${abd.join(", ")}`);
|
|
960
|
+
const guLabels = {
|
|
961
|
+
meatusAbnormal: "Meatus abnormal (hypospadias?)",
|
|
962
|
+
phimosis: "Phimosis / paraphimosis",
|
|
963
|
+
lesions: "Penile lesions / ulcers",
|
|
964
|
+
scrotalSwelling: "Scrotal swelling",
|
|
965
|
+
transilluminant: "Transilluminant",
|
|
966
|
+
tenderTestis: "Tender testis",
|
|
967
|
+
hydrocele: "Hydrocele",
|
|
968
|
+
varicocele: "Varicocele",
|
|
969
|
+
suspiciousMass: "Suspicious mass"
|
|
970
|
+
};
|
|
971
|
+
const gu = Object.keys(guLabels).filter((k) => v.gu[k]).map((k) => guLabels[k]);
|
|
972
|
+
if (gu.length) sections.push(`GU: ${gu.join(", ")}`);
|
|
973
|
+
const dreBits = hopcNonEmpty([
|
|
974
|
+
v.dre.done ? "Performed" : "",
|
|
975
|
+
v.dre.sizeGrams > 0 ? `Size ~${v.dre.sizeGrams} g` : "",
|
|
976
|
+
v.dre.consistency ? `Consistency: ${v.dre.consistency}` : "",
|
|
977
|
+
v.dre.medianSulcus ? `Median sulcus: ${v.dre.medianSulcus}` : "",
|
|
978
|
+
v.dre.tenderness ? "Tenderness" : ""
|
|
979
|
+
]);
|
|
980
|
+
if (dreBits.length) sections.push(`DRE: ${dreBits.join(", ")}`);
|
|
981
|
+
return sections.join("\n");
|
|
982
|
+
}
|
|
983
|
+
function str(x) {
|
|
984
|
+
return typeof x === "string" ? x : "";
|
|
985
|
+
}
|
|
986
|
+
function bool(x) {
|
|
987
|
+
return x === true;
|
|
988
|
+
}
|
|
989
|
+
function nonNegInt(x) {
|
|
990
|
+
const n = Number(x);
|
|
991
|
+
if (!Number.isFinite(n)) return 0;
|
|
992
|
+
return Math.max(0, Math.round(n));
|
|
993
|
+
}
|
|
1094
994
|
function normalizeUrologySmartHistory(raw) {
|
|
1095
|
-
const
|
|
1096
|
-
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return
|
|
1097
|
-
const
|
|
1098
|
-
const
|
|
1099
|
-
const
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
const
|
|
1123
|
-
const
|
|
995
|
+
const base = defaultUrologySmartHistory();
|
|
996
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return base;
|
|
997
|
+
const r = raw;
|
|
998
|
+
const soc = r.socrates && typeof r.socrates === "object" && !Array.isArray(r.socrates) ? r.socrates : {};
|
|
999
|
+
const socObj = soc;
|
|
1000
|
+
const sev = Number(socObj.severity);
|
|
1001
|
+
const socrates = {
|
|
1002
|
+
site: str(socObj.site),
|
|
1003
|
+
onset: str(socObj.onset),
|
|
1004
|
+
character: str(socObj.character),
|
|
1005
|
+
radiation: str(socObj.radiation),
|
|
1006
|
+
associated: str(socObj.associated),
|
|
1007
|
+
timing: str(socObj.timing),
|
|
1008
|
+
exacerbating: str(socObj.exacerbating),
|
|
1009
|
+
severity: Number.isFinite(sev) ? Math.min(10, Math.max(0, Math.round(sev))) : 0
|
|
1010
|
+
};
|
|
1011
|
+
const ipRaw = r.ipss && typeof r.ipss === "object" && !Array.isArray(r.ipss) ? r.ipss : {};
|
|
1012
|
+
const ip = ipRaw;
|
|
1013
|
+
const ipss = {
|
|
1014
|
+
incomplete: ipssItem(ip.incomplete),
|
|
1015
|
+
frequency: ipssItem(ip.frequency),
|
|
1016
|
+
intermittency: ipssItem(ip.intermittency),
|
|
1017
|
+
urgency: ipssItem(ip.urgency),
|
|
1018
|
+
weakStream: ipssItem(ip.weakStream ?? ip.weak_stream),
|
|
1019
|
+
straining: ipssItem(ip.straining),
|
|
1020
|
+
nocturia: ipssItem(ip.nocturia)
|
|
1021
|
+
};
|
|
1022
|
+
const qolRaw = Number(r.ipssQoL);
|
|
1023
|
+
const ipssQoL = Number.isFinite(qolRaw) ? Math.min(6, Math.max(0, Math.round(qolRaw))) : 0;
|
|
1024
|
+
const haRaw = r.haematuria && typeof r.haematuria === "object" && !Array.isArray(r.haematuria) ? r.haematuria : {};
|
|
1025
|
+
const ha = haRaw;
|
|
1124
1026
|
const haematuria = {
|
|
1125
|
-
present:
|
|
1126
|
-
timing:
|
|
1127
|
-
painful:
|
|
1128
|
-
clots:
|
|
1129
|
-
};
|
|
1130
|
-
const
|
|
1131
|
-
const
|
|
1132
|
-
const
|
|
1027
|
+
present: bool(ha.present),
|
|
1028
|
+
timing: str(ha.timing) || "none",
|
|
1029
|
+
painful: bool(ha.painful),
|
|
1030
|
+
clots: bool(ha.clots)
|
|
1031
|
+
};
|
|
1032
|
+
const sxRaw = r.sexual && typeof r.sexual === "object" && !Array.isArray(r.sexual) ? r.sexual : {};
|
|
1033
|
+
const sx = sxRaw;
|
|
1034
|
+
const infertilityMonths = nonNegInt(sx.infertilityMonths);
|
|
1133
1035
|
const sexual = {
|
|
1134
|
-
erectile:
|
|
1135
|
-
libido:
|
|
1136
|
-
ejaculation:
|
|
1137
|
-
infertilityMonths
|
|
1036
|
+
erectile: str(sx.erectile) || "none",
|
|
1037
|
+
libido: str(sx.libido) || "none",
|
|
1038
|
+
ejaculation: str(sx.ejaculation) || "none",
|
|
1039
|
+
infertilityMonths
|
|
1138
1040
|
};
|
|
1139
|
-
const pastNotes =
|
|
1140
|
-
return {
|
|
1041
|
+
const pastNotes = str(r.pastNotes);
|
|
1042
|
+
return {
|
|
1043
|
+
socrates,
|
|
1044
|
+
ipss,
|
|
1045
|
+
ipssQoL,
|
|
1046
|
+
haematuria,
|
|
1047
|
+
sexual,
|
|
1048
|
+
pastNotes
|
|
1049
|
+
};
|
|
1050
|
+
}
|
|
1051
|
+
function dreSelectStr(x) {
|
|
1052
|
+
const t = str(x).trim();
|
|
1053
|
+
if (!t || t.toLowerCase() === "none") return "";
|
|
1054
|
+
return t;
|
|
1141
1055
|
}
|
|
1142
1056
|
function normalizeUrologyExamination(raw) {
|
|
1143
|
-
const
|
|
1144
|
-
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return
|
|
1145
|
-
const
|
|
1146
|
-
const
|
|
1147
|
-
const
|
|
1148
|
-
const
|
|
1149
|
-
const
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
const
|
|
1057
|
+
const base = defaultUrologyExamination();
|
|
1058
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return base;
|
|
1059
|
+
const r = raw;
|
|
1060
|
+
const regions = Array.isArray(r.regions) ? r.regions.filter((x) => typeof x === "string") : [];
|
|
1061
|
+
const g = r.general && typeof r.general === "object" && !Array.isArray(r.general) ? r.general : {};
|
|
1062
|
+
const gObj = g;
|
|
1063
|
+
const general = {
|
|
1064
|
+
pallor: bool(gObj.pallor),
|
|
1065
|
+
oedema: bool(gObj.oedema),
|
|
1066
|
+
icterus: bool(gObj.icterus),
|
|
1067
|
+
lymphadenopathy: bool(gObj.lymphadenopathy)
|
|
1068
|
+
};
|
|
1069
|
+
const ab = r.abdomen && typeof r.abdomen === "object" && !Array.isArray(r.abdomen) ? r.abdomen : {};
|
|
1070
|
+
const abObj = ab;
|
|
1071
|
+
const abdomen = {
|
|
1072
|
+
distension: bool(abObj.distension),
|
|
1073
|
+
scars: bool(abObj.scars),
|
|
1074
|
+
mass: bool(abObj.mass),
|
|
1075
|
+
kidneyPalpable: bool(abObj.kidneyPalpable),
|
|
1076
|
+
bladderPalpable: bool(abObj.bladderPalpable),
|
|
1077
|
+
renalAngleTender: bool(abObj.renalAngleTender),
|
|
1078
|
+
bladderDull: bool(abObj.bladderDull)
|
|
1079
|
+
};
|
|
1080
|
+
const guRaw = r.gu && typeof r.gu === "object" && !Array.isArray(r.gu) ? r.gu : {};
|
|
1081
|
+
const guObj = guRaw;
|
|
1082
|
+
const gu = {
|
|
1083
|
+
meatusAbnormal: bool(guObj.meatusAbnormal),
|
|
1084
|
+
phimosis: bool(guObj.phimosis),
|
|
1085
|
+
lesions: bool(guObj.lesions),
|
|
1086
|
+
scrotalSwelling: bool(guObj.scrotalSwelling),
|
|
1087
|
+
transilluminant: bool(guObj.transilluminant),
|
|
1088
|
+
tenderTestis: bool(guObj.tenderTestis),
|
|
1089
|
+
hydrocele: bool(guObj.hydrocele),
|
|
1090
|
+
varicocele: bool(guObj.varicocele),
|
|
1091
|
+
suspiciousMass: bool(guObj.suspiciousMass)
|
|
1092
|
+
};
|
|
1093
|
+
const dr = r.dre && typeof r.dre === "object" && !Array.isArray(r.dre) ? r.dre : {};
|
|
1094
|
+
const drObj = dr;
|
|
1095
|
+
const sizeG = Number(drObj.sizeGrams);
|
|
1096
|
+
const dre = {
|
|
1097
|
+
done: bool(drObj.done),
|
|
1098
|
+
sizeGrams: Number.isFinite(sizeG) && sizeG >= 0 ? Math.round(sizeG) : 0,
|
|
1099
|
+
consistency: dreSelectStr(drObj.consistency),
|
|
1100
|
+
medianSulcus: dreSelectStr(drObj.medianSulcus),
|
|
1101
|
+
tenderness: bool(drObj.tenderness)
|
|
1102
|
+
};
|
|
1103
|
+
const examinationNotes = str(r.examinationNotes);
|
|
1156
1104
|
return {
|
|
1157
|
-
regions
|
|
1158
|
-
general
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
},
|
|
1164
|
-
abdomen: {
|
|
1165
|
-
distension: bool(ab.distension),
|
|
1166
|
-
scars: bool(ab.scars),
|
|
1167
|
-
mass: bool(ab.mass),
|
|
1168
|
-
kidneyPalpable: bool(ab.kidneyPalpable),
|
|
1169
|
-
bladderPalpable: bool(ab.bladderPalpable),
|
|
1170
|
-
renalAngleTender: bool(ab.renalAngleTender),
|
|
1171
|
-
bladderDull: bool(ab.bladderDull)
|
|
1172
|
-
},
|
|
1173
|
-
gu: {
|
|
1174
|
-
meatusAbnormal: bool(gu.meatusAbnormal),
|
|
1175
|
-
phimosis: bool(gu.phimosis),
|
|
1176
|
-
lesions: bool(gu.lesions),
|
|
1177
|
-
scrotalSwelling: bool(gu.scrotalSwelling),
|
|
1178
|
-
transilluminant: bool(gu.transilluminant),
|
|
1179
|
-
tenderTestis: bool(gu.tenderTestis),
|
|
1180
|
-
hydrocele: bool(gu.hydrocele),
|
|
1181
|
-
varicocele: bool(gu.varicocele),
|
|
1182
|
-
suspiciousMass: bool(gu.suspiciousMass)
|
|
1183
|
-
},
|
|
1184
|
-
dre: {
|
|
1185
|
-
done: bool(dr.done),
|
|
1186
|
-
sizeGrams: Number.isFinite(sg) && sg >= 0 ? Math.round(sg) : 0,
|
|
1187
|
-
consistency: dreEmpty(consistencyRaw) ? "" : String(consistencyRaw),
|
|
1188
|
-
medianSulcus: dreEmpty(medianRaw) ? "" : String(medianRaw),
|
|
1189
|
-
tenderness: bool(dr.tenderness)
|
|
1190
|
-
},
|
|
1191
|
-
examinationNotes: typeof v.examinationNotes === "string" ? v.examinationNotes : d.examinationNotes
|
|
1105
|
+
regions,
|
|
1106
|
+
general,
|
|
1107
|
+
abdomen,
|
|
1108
|
+
gu,
|
|
1109
|
+
dre,
|
|
1110
|
+
examinationNotes
|
|
1192
1111
|
};
|
|
1193
1112
|
}
|
|
1194
|
-
var defaultUrologyPathway = () => ({
|
|
1195
|
-
stoneSizeMm: 0,
|
|
1196
|
-
hydronephrosis: false,
|
|
1197
|
-
prostateVolumeCc: 0,
|
|
1198
|
-
psaNgMl: 0,
|
|
1199
|
-
uroflowQmaxMlSec: 0,
|
|
1200
|
-
risk: {
|
|
1201
|
-
ckd: false,
|
|
1202
|
-
diabetes: false,
|
|
1203
|
-
anticoagulants: false,
|
|
1204
|
-
activeInfection: false
|
|
1205
|
-
}
|
|
1206
|
-
});
|
|
1207
|
-
function clampNonNegativeNumber(x, fallback) {
|
|
1208
|
-
const n = Number(x);
|
|
1209
|
-
if (!Number.isFinite(n) || n < 0) return fallback;
|
|
1210
|
-
return n;
|
|
1211
|
-
}
|
|
1212
1113
|
function normalizeUrologyPathway(raw) {
|
|
1213
|
-
const
|
|
1214
|
-
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return
|
|
1215
|
-
const
|
|
1216
|
-
const
|
|
1114
|
+
const base = defaultUrologyPathway();
|
|
1115
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return base;
|
|
1116
|
+
const r = raw;
|
|
1117
|
+
const stoneSizeMm = nonNegInt(r.stoneSizeMm);
|
|
1118
|
+
const hydronephrosis = bool(r.hydronephrosis);
|
|
1119
|
+
const prostateVolumeCc = Math.max(0, Number(r.prostateVolumeCc) || 0);
|
|
1120
|
+
const psaNgMl = Math.max(0, Number(r.psaNgMl) || 0);
|
|
1121
|
+
const uroflowQmaxMlSec = Math.max(0, Number(r.uroflowQmaxMlSec) || 0);
|
|
1122
|
+
const riskRaw = r.risk && typeof r.risk === "object" && !Array.isArray(r.risk) ? r.risk : {};
|
|
1123
|
+
const rk = riskRaw;
|
|
1124
|
+
const risk = {
|
|
1125
|
+
ckd: bool(rk.ckd),
|
|
1126
|
+
diabetes: bool(rk.diabetes),
|
|
1127
|
+
anticoagulants: bool(rk.anticoagulants),
|
|
1128
|
+
activeInfection: bool(rk.activeInfection)
|
|
1129
|
+
};
|
|
1217
1130
|
return {
|
|
1218
|
-
stoneSizeMm
|
|
1219
|
-
hydronephrosis
|
|
1220
|
-
prostateVolumeCc
|
|
1221
|
-
psaNgMl
|
|
1222
|
-
uroflowQmaxMlSec
|
|
1223
|
-
risk
|
|
1224
|
-
ckd: rIn.ckd === true,
|
|
1225
|
-
diabetes: rIn.diabetes === true,
|
|
1226
|
-
anticoagulants: rIn.anticoagulants === true,
|
|
1227
|
-
activeInfection: rIn.activeInfection === true
|
|
1228
|
-
}
|
|
1131
|
+
stoneSizeMm,
|
|
1132
|
+
hydronephrosis,
|
|
1133
|
+
prostateVolumeCc,
|
|
1134
|
+
psaNgMl,
|
|
1135
|
+
uroflowQmaxMlSec,
|
|
1136
|
+
risk
|
|
1229
1137
|
};
|
|
1230
1138
|
}
|
|
1231
|
-
function urologyStoneRecommendation(sizeMm, hydronephrosis) {
|
|
1232
|
-
if (sizeMm <= 0) return { plan: "Enter stone size to auto-trigger plan.", surgical: false };
|
|
1233
|
-
if (sizeMm < 5) return { plan: "Conservative + MET (\u03B1-blocker), hydration", surgical: false };
|
|
1234
|
-
if (sizeMm <= 10)
|
|
1235
|
-
return {
|
|
1236
|
-
plan: hydronephrosis ? "URS / SWL \u2014 obstruction present" : "Medical expulsive therapy / URS",
|
|
1237
|
-
surgical: hydronephrosis
|
|
1238
|
-
};
|
|
1239
|
-
return { plan: "URS / PCNL \u2014 surgical clearance indicated", surgical: true };
|
|
1240
|
-
}
|
|
1241
|
-
function urologyProstateProcedure(volumeCc) {
|
|
1242
|
-
if (volumeCc <= 0) return "Enter prostate volume.";
|
|
1243
|
-
if (volumeCc < 30) return "Medical (\u03B1-blocker \xB1 5-ARI)";
|
|
1244
|
-
if (volumeCc <= 80) return "TURP";
|
|
1245
|
-
return "HoLEP / Open simple prostatectomy";
|
|
1246
|
-
}
|
|
1247
1139
|
|
|
1248
1140
|
// src/core/painScaleFlags.ts
|
|
1249
1141
|
function normalizePainScaleFlags(raw, bounds) {
|
|
@@ -1357,18 +1249,18 @@ var FormStore = class {
|
|
|
1357
1249
|
values[field.id] = field.defaultValue ?? defaultGeneralSurgeryExamination();
|
|
1358
1250
|
} else if (field.type === "general_surgery_grading") {
|
|
1359
1251
|
values[field.id] = field.defaultValue ?? defaultGeneralSurgeryGrading();
|
|
1360
|
-
} else if (field.type === "pain_scale_flags") {
|
|
1361
|
-
const f = field;
|
|
1362
|
-
values[field.id] = normalizePainScaleFlags(
|
|
1363
|
-
f.defaultValue ?? { pain: f.min ?? 0, flags: [] },
|
|
1364
|
-
{ min: f.min, max: f.max }
|
|
1365
|
-
);
|
|
1366
1252
|
} else if (field.type === "urology_smart_history") {
|
|
1367
1253
|
values[field.id] = field.defaultValue ?? defaultUrologySmartHistory();
|
|
1368
1254
|
} else if (field.type === "urology_examination") {
|
|
1369
1255
|
values[field.id] = field.defaultValue ?? defaultUrologyExamination();
|
|
1370
1256
|
} else if (field.type === "urology_pathway") {
|
|
1371
1257
|
values[field.id] = field.defaultValue ?? defaultUrologyPathway();
|
|
1258
|
+
} else if (field.type === "pain_scale_flags") {
|
|
1259
|
+
const f = field;
|
|
1260
|
+
values[field.id] = normalizePainScaleFlags(
|
|
1261
|
+
f.defaultValue ?? { pain: f.min ?? 0, flags: [] },
|
|
1262
|
+
{ min: f.min, max: f.max }
|
|
1263
|
+
);
|
|
1372
1264
|
} else values[field.id] = null;
|
|
1373
1265
|
}
|
|
1374
1266
|
});
|
|
@@ -1578,7 +1470,6 @@ var FormStore = class {
|
|
|
1578
1470
|
}
|
|
1579
1471
|
}
|
|
1580
1472
|
});
|
|
1581
|
-
attachUrologyClinicalPathwayMetadata(result, this.schema);
|
|
1582
1473
|
return result;
|
|
1583
1474
|
}
|
|
1584
1475
|
// --- Core Logic ---
|
|
@@ -6551,7 +6442,7 @@ function safeJsonParse(val) {
|
|
|
6551
6442
|
return null;
|
|
6552
6443
|
}
|
|
6553
6444
|
}
|
|
6554
|
-
function
|
|
6445
|
+
function clampInt(val, min, max) {
|
|
6555
6446
|
if (!Number.isFinite(val)) return min;
|
|
6556
6447
|
return Math.max(min, Math.min(max, Math.trunc(val)));
|
|
6557
6448
|
}
|
|
@@ -6561,10 +6452,10 @@ function parseLegacyString(input) {
|
|
|
6561
6452
|
if (gpalMatch) {
|
|
6562
6453
|
const [, g, p, a, l] = gpalMatch;
|
|
6563
6454
|
result.gpal = {
|
|
6564
|
-
G:
|
|
6565
|
-
P:
|
|
6566
|
-
A:
|
|
6567
|
-
L:
|
|
6455
|
+
G: clampInt(Number(g), 0, 20),
|
|
6456
|
+
P: clampInt(Number(p), 0, 20),
|
|
6457
|
+
A: clampInt(Number(a), 0, 20),
|
|
6458
|
+
L: clampInt(Number(l), 0, 20)
|
|
6568
6459
|
};
|
|
6569
6460
|
}
|
|
6570
6461
|
const lmpMatch = input.match(/LMP:\s*([^\n]+)/i);
|
|
@@ -6597,10 +6488,10 @@ function normalizeToDraft(value) {
|
|
|
6597
6488
|
isNewEntry: false,
|
|
6598
6489
|
draft: {
|
|
6599
6490
|
gpal: {
|
|
6600
|
-
G:
|
|
6601
|
-
P:
|
|
6602
|
-
A:
|
|
6603
|
-
L:
|
|
6491
|
+
G: clampInt(Number(gpal.G ?? 0), 0, 20),
|
|
6492
|
+
P: clampInt(Number(gpal.P ?? 0), 0, 20),
|
|
6493
|
+
A: clampInt(Number(gpal.A ?? 0), 0, 20),
|
|
6494
|
+
L: clampInt(Number(gpal.L ?? 0), 0, 20)
|
|
6604
6495
|
},
|
|
6605
6496
|
lmp: typeof lmp === "string" ? lmp : "",
|
|
6606
6497
|
is_pregnant,
|
|
@@ -6618,10 +6509,10 @@ function normalizeToDraft(value) {
|
|
|
6618
6509
|
}
|
|
6619
6510
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
6620
6511
|
const gpalFromFlat = {
|
|
6621
|
-
G:
|
|
6622
|
-
P:
|
|
6623
|
-
A:
|
|
6624
|
-
L:
|
|
6512
|
+
G: clampInt(Number(parsed.G ?? parsed.g ?? 0), 0, 20),
|
|
6513
|
+
P: clampInt(Number(parsed.P ?? parsed.p ?? 0), 0, 20),
|
|
6514
|
+
A: clampInt(Number(parsed.A ?? parsed.a ?? 0), 0, 20),
|
|
6515
|
+
L: clampInt(Number(parsed.L ?? parsed.l ?? 0), 0, 20)
|
|
6625
6516
|
};
|
|
6626
6517
|
return {
|
|
6627
6518
|
isNewEntry: false,
|
|
@@ -6773,7 +6664,7 @@ var ObstetricHistoryWidget = ({ fieldId }) => {
|
|
|
6773
6664
|
const sanitizeGpalInput = (raw) => {
|
|
6774
6665
|
const digits = raw.replace(/[^\d]/g, "").slice(0, 2);
|
|
6775
6666
|
if (!digits) return 0;
|
|
6776
|
-
return
|
|
6667
|
+
return clampInt(Number(digits), 0, 20);
|
|
6777
6668
|
};
|
|
6778
6669
|
const handleGpalChange = (key, raw) => {
|
|
6779
6670
|
const prevWasEmpty = draft.gpal[key] === 0 && activeGpalKey === key;
|
|
@@ -9077,26 +8968,11 @@ var DischargeMedicationOrdersWidget = ({ fieldId }) => {
|
|
|
9077
8968
|
showError && /* @__PURE__ */ jsx("p", { className: "text-xs text-red-500", children: error })
|
|
9078
8969
|
] });
|
|
9079
8970
|
};
|
|
9080
|
-
var
|
|
8971
|
+
var DEFAULT_TOKEN_SEPARATOR2 = ", ";
|
|
9081
8972
|
function getAppendSeparator(def) {
|
|
9082
|
-
const raw = def.meta && typeof def.meta.appendSeparator === "string" ? def.meta.appendSeparator :
|
|
8973
|
+
const raw = def.meta && typeof def.meta.appendSeparator === "string" ? def.meta.appendSeparator : DEFAULT_TOKEN_SEPARATOR2;
|
|
9083
8974
|
return raw;
|
|
9084
8975
|
}
|
|
9085
|
-
function getSuggestionTokensFromText(text) {
|
|
9086
|
-
return text.split(",").map((p) => p.trim()).filter(Boolean);
|
|
9087
|
-
}
|
|
9088
|
-
function toggleSuggestionTokenInText(current, token, separator = DEFAULT_TOKEN_SEPARATOR) {
|
|
9089
|
-
const t = String(token).trim();
|
|
9090
|
-
if (!t) return current;
|
|
9091
|
-
const parts = getSuggestionTokensFromText(current);
|
|
9092
|
-
const i = parts.findIndex((p) => p === t);
|
|
9093
|
-
if (i >= 0) {
|
|
9094
|
-
parts.splice(i, 1);
|
|
9095
|
-
} else {
|
|
9096
|
-
parts.push(t);
|
|
9097
|
-
}
|
|
9098
|
-
return parts.join(separator);
|
|
9099
|
-
}
|
|
9100
8976
|
function isTokenSelected(text, optionValue) {
|
|
9101
8977
|
const t = String(optionValue).trim();
|
|
9102
8978
|
if (!t) return false;
|
|
@@ -9170,8 +9046,11 @@ var SuggestionTextareaWidget = ({ fieldId }) => {
|
|
|
9170
9046
|
setOptions([]);
|
|
9171
9047
|
}
|
|
9172
9048
|
}, [def]);
|
|
9049
|
+
const chipAllowedSet = useMemo(
|
|
9050
|
+
() => new Set(options.map((o) => String(o.value).trim()).filter(Boolean)),
|
|
9051
|
+
[options]
|
|
9052
|
+
);
|
|
9173
9053
|
useEffect(() => {
|
|
9174
|
-
if (!parallelChipFieldId || !def) return;
|
|
9175
9054
|
const parallelDef = store.getFieldDef(parallelChipFieldId);
|
|
9176
9055
|
if (!parallelDef || parallelDef.type !== "multiselect") return;
|
|
9177
9056
|
const next = deriveKnownSuggestionChipValues(textValue, options);
|
|
@@ -9197,7 +9076,7 @@ var SuggestionTextareaWidget = ({ fieldId }) => {
|
|
|
9197
9076
|
const labelEl = theme ? /* @__PURE__ */ jsx(Label, { className: labelClass, children: labelContent }) : /* @__PURE__ */ jsx(Label, { children: labelContent });
|
|
9198
9077
|
const onChipClick = (optValue) => {
|
|
9199
9078
|
if (disabled) return;
|
|
9200
|
-
setValue(toggleSuggestionTokenInText(textValue, String(optValue), appendSeparator));
|
|
9079
|
+
setValue(toggleSuggestionTokenInText(textValue, String(optValue), appendSeparator, chipAllowedSet));
|
|
9201
9080
|
};
|
|
9202
9081
|
const hasSuggestions = options.length > 0;
|
|
9203
9082
|
const hasEmbedded = embeddedFieldIds.length > 0;
|
|
@@ -9636,7 +9515,7 @@ var EMPTY = {
|
|
|
9636
9515
|
specularMicroscopyDone: false,
|
|
9637
9516
|
endothelialCount: ""
|
|
9638
9517
|
};
|
|
9639
|
-
function
|
|
9518
|
+
function str2(x) {
|
|
9640
9519
|
return typeof x === "string" ? x : "";
|
|
9641
9520
|
}
|
|
9642
9521
|
function parseValue2(raw) {
|
|
@@ -9644,24 +9523,24 @@ function parseValue2(raw) {
|
|
|
9644
9523
|
const o = raw;
|
|
9645
9524
|
const m = o.method;
|
|
9646
9525
|
const method = m === "ascan_immersion" || m === "ascan_contact" || m === "optical_biometry" ? m : "optical_biometry";
|
|
9647
|
-
const formula =
|
|
9526
|
+
const formula = str2(o.formula);
|
|
9648
9527
|
return {
|
|
9649
9528
|
...EMPTY,
|
|
9650
|
-
axialLengthOD:
|
|
9651
|
-
axialLengthOS:
|
|
9652
|
-
k1k2AxisOD:
|
|
9653
|
-
k1k2AxisOS:
|
|
9654
|
-
anteriorChamberDepthOD:
|
|
9655
|
-
anteriorChamberDepthOS:
|
|
9656
|
-
iolPowerOD:
|
|
9657
|
-
iolPowerOS:
|
|
9658
|
-
targetRefractionOD:
|
|
9659
|
-
targetRefractionOS:
|
|
9529
|
+
axialLengthOD: str2(o.axialLengthOD),
|
|
9530
|
+
axialLengthOS: str2(o.axialLengthOS),
|
|
9531
|
+
k1k2AxisOD: str2(o.k1k2AxisOD),
|
|
9532
|
+
k1k2AxisOS: str2(o.k1k2AxisOS),
|
|
9533
|
+
anteriorChamberDepthOD: str2(o.anteriorChamberDepthOD),
|
|
9534
|
+
anteriorChamberDepthOS: str2(o.anteriorChamberDepthOS),
|
|
9535
|
+
iolPowerOD: str2(o.iolPowerOD),
|
|
9536
|
+
iolPowerOS: str2(o.iolPowerOS),
|
|
9537
|
+
targetRefractionOD: str2(o.targetRefractionOD),
|
|
9538
|
+
targetRefractionOS: str2(o.targetRefractionOS),
|
|
9660
9539
|
formula: formula || "SRK/T",
|
|
9661
9540
|
method,
|
|
9662
9541
|
cornealTopoUploaded: o.cornealTopoUploaded === true,
|
|
9663
9542
|
specularMicroscopyDone: o.specularMicroscopyDone === true,
|
|
9664
|
-
endothelialCount:
|
|
9543
|
+
endothelialCount: str2(o.endothelialCount)
|
|
9665
9544
|
};
|
|
9666
9545
|
}
|
|
9667
9546
|
var paramCell = "emr-biometry-param text-[11px] font-semibold leading-snug text-foreground sm:text-xs py-2";
|
|
@@ -10101,7 +9980,7 @@ var THYROID_OPTS = [
|
|
|
10101
9980
|
{ value: "voice_change", label: "Voice change" },
|
|
10102
9981
|
{ value: "thyrotoxicosis", label: "Thyrotoxicosis symptoms" }
|
|
10103
9982
|
];
|
|
10104
|
-
var
|
|
9983
|
+
var SOCRATES_KEYS = [
|
|
10105
9984
|
"site",
|
|
10106
9985
|
"onset",
|
|
10107
9986
|
"character",
|
|
@@ -10195,7 +10074,7 @@ var GsSmartHistoryWidget = ({ fieldId }) => {
|
|
|
10195
10074
|
labelEl,
|
|
10196
10075
|
/* @__PURE__ */ jsxs("div", { className: bodyClass, children: [
|
|
10197
10076
|
showPain ? /* @__PURE__ */ jsx(Panel, { title: "SOCRATES \u2014 pain", children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-2 md:grid-cols-4", children: [
|
|
10198
|
-
|
|
10077
|
+
SOCRATES_KEYS.map((k) => /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
|
|
10199
10078
|
/* @__PURE__ */ jsx("span", { className: "text-[10px] font-medium uppercase tracking-wide text-muted-foreground", children: k }),
|
|
10200
10079
|
/* @__PURE__ */ jsx(
|
|
10201
10080
|
Input,
|
|
@@ -11134,10 +11013,36 @@ var PainScaleFlagsWidget = ({ fieldId }) => {
|
|
|
11134
11013
|
};
|
|
11135
11014
|
var CHIEF_CHIPS_FIELD3 = "chief_complaints_chips";
|
|
11136
11015
|
var ACTIVE_SYNDROME_FIELD = "uro_active_syndrome";
|
|
11016
|
+
var CHIEF_TEXT_FIELD = "chief_complaints";
|
|
11017
|
+
var SYMPTOMS_FIELD = "symptoms";
|
|
11018
|
+
var DIAGNOSIS_FIELD = "diagnosis";
|
|
11019
|
+
var URO_DURATION_FIELD = "uro_chief_duration";
|
|
11020
|
+
var URO_ONSET_FIELD = "uro_chief_onset";
|
|
11021
|
+
var URO_PROGRESSION_FIELD = "uro_chief_progression";
|
|
11022
|
+
var SYNDROME_LABELS = {
|
|
11023
|
+
luts: "LUTS / BPH",
|
|
11024
|
+
stone: "Urolithiasis (stone)",
|
|
11025
|
+
haematuria: "Haematuria",
|
|
11026
|
+
scrotal: "Scrotal swelling",
|
|
11027
|
+
retention: "Acute retention",
|
|
11028
|
+
ed_infertility: "ED / Infertility",
|
|
11029
|
+
uti: "UTI / infection"
|
|
11030
|
+
};
|
|
11137
11031
|
function chipList2(state) {
|
|
11138
11032
|
const raw = state.values[CHIEF_CHIPS_FIELD3];
|
|
11139
11033
|
return Array.isArray(raw) ? raw.filter((x) => typeof x === "string") : [];
|
|
11140
11034
|
}
|
|
11035
|
+
function str3(x) {
|
|
11036
|
+
return typeof x === "string" ? x : "";
|
|
11037
|
+
}
|
|
11038
|
+
function chiefOptionalFieldDisplay(x) {
|
|
11039
|
+
const s = str3(x).trim();
|
|
11040
|
+
if (!s || s.toLowerCase() === "none") return "";
|
|
11041
|
+
return s;
|
|
11042
|
+
}
|
|
11043
|
+
function nonEmptyLines(lines) {
|
|
11044
|
+
return lines.map((s) => (s ?? "").trim()).filter(Boolean);
|
|
11045
|
+
}
|
|
11141
11046
|
var IPSS_LABELS = {
|
|
11142
11047
|
incomplete: "Incomplete emptying",
|
|
11143
11048
|
frequency: "Frequency (<2h)",
|
|
@@ -11147,7 +11052,7 @@ var IPSS_LABELS = {
|
|
|
11147
11052
|
straining: "Straining",
|
|
11148
11053
|
nocturia: "Nocturia (\xD7/night)"
|
|
11149
11054
|
};
|
|
11150
|
-
var
|
|
11055
|
+
var SOCRATES_KEYS2 = [
|
|
11151
11056
|
"site",
|
|
11152
11057
|
"onset",
|
|
11153
11058
|
"character",
|
|
@@ -11171,17 +11076,19 @@ function Panel2({
|
|
|
11171
11076
|
}
|
|
11172
11077
|
var UrologySmartHistoryWidget = ({ fieldId }) => {
|
|
11173
11078
|
const { fieldDef, value, setValue, setTouched, error, touched, disabled } = useField(fieldId);
|
|
11079
|
+
const hopcField = useField(SYMPTOMS_FIELD);
|
|
11174
11080
|
const syndromeField = useField(ACTIVE_SYNDROME_FIELD);
|
|
11175
11081
|
const { state } = useForm();
|
|
11082
|
+
const store = useFormStore();
|
|
11176
11083
|
const showError = !!error && (touched || state.submitAttempted);
|
|
11177
11084
|
const safe = useMemo(() => normalizeUrologySmartHistory(value), [value]);
|
|
11178
11085
|
const chips = useMemo(() => chipList2(state), [state]);
|
|
11179
11086
|
const rawSyndrome = syndromeField.value ?? state.values[ACTIVE_SYNDROME_FIELD];
|
|
11180
11087
|
const syndrome = typeof rawSyndrome === "string" && rawSyndrome !== "" && rawSyndrome !== "none" ? rawSyndrome : "none";
|
|
11181
|
-
const showPain = chips.includes("
|
|
11182
|
-
const showLUTS = syndrome === "luts" || syndrome === "retention" || chips.includes("
|
|
11088
|
+
const showPain = chips.includes("pain abdomen flank") || chips.includes("scrotal swelling pain") || syndrome === "stone" || syndrome === "scrotal";
|
|
11089
|
+
const showLUTS = syndrome === "luts" || syndrome === "retention" || chips.includes("frequency urgency") || chips.includes("poor stream") || chips.includes("acute retention");
|
|
11183
11090
|
const showHaem = syndrome === "haematuria" || chips.includes("haematuria");
|
|
11184
|
-
const showSex = syndrome === "ed_infertility" || chips.includes("
|
|
11091
|
+
const showSex = syndrome === "ed_infertility" || chips.includes("erectile dysfunction") || chips.includes("infertility concern");
|
|
11185
11092
|
const update = (next) => {
|
|
11186
11093
|
setValue(next);
|
|
11187
11094
|
setTouched();
|
|
@@ -11201,6 +11108,55 @@ var UrologySmartHistoryWidget = ({ fieldId }) => {
|
|
|
11201
11108
|
const setIpss = (key, v) => {
|
|
11202
11109
|
update({ ...safe, ipss: { ...safe.ipss, [key]: v } });
|
|
11203
11110
|
};
|
|
11111
|
+
const [hopcNarrativeLocked, setHopcNarrativeLocked] = useState(false);
|
|
11112
|
+
useEffect(() => {
|
|
11113
|
+
if (hopcNarrativeLocked || disabled) return;
|
|
11114
|
+
const next = formatUrologySmartHistoryToSymptomsNarrative(normalizeUrologySmartHistory(value), {
|
|
11115
|
+
showPain,
|
|
11116
|
+
showLUTS,
|
|
11117
|
+
showHaem,
|
|
11118
|
+
showSex
|
|
11119
|
+
});
|
|
11120
|
+
hopcField.setValue(next);
|
|
11121
|
+
}, [value, hopcNarrativeLocked, showPain, showLUTS, showHaem, showSex, disabled]);
|
|
11122
|
+
useEffect(() => {
|
|
11123
|
+
if (disabled) return;
|
|
11124
|
+
const label = syndrome && syndrome !== "none" ? SYNDROME_LABELS[syndrome] ?? syndrome : "";
|
|
11125
|
+
const prev = store.getFieldState(DIAGNOSIS_FIELD)?.value;
|
|
11126
|
+
const prevText = typeof prev === "string" ? prev : "";
|
|
11127
|
+
const syndromeLabels = new Set(Object.values(SYNDROME_LABELS));
|
|
11128
|
+
const keptLines = prevText.split("\n").map((l) => l.trim()).filter(Boolean).filter((l) => !syndromeLabels.has(l));
|
|
11129
|
+
const nextLines = label ? [...keptLines, label] : keptLines;
|
|
11130
|
+
const next = nextLines.join("\n");
|
|
11131
|
+
if (prevText.trim() === next.trim()) return;
|
|
11132
|
+
store.setValues({ [DIAGNOSIS_FIELD]: next }, { touch: false });
|
|
11133
|
+
}, [disabled, store, syndrome]);
|
|
11134
|
+
useEffect(() => {
|
|
11135
|
+
if (disabled) return;
|
|
11136
|
+
const duration = chiefOptionalFieldDisplay(state.values[URO_DURATION_FIELD]);
|
|
11137
|
+
const onset = chiefOptionalFieldDisplay(state.values[URO_ONSET_FIELD]);
|
|
11138
|
+
const progression = chiefOptionalFieldDisplay(state.values[URO_PROGRESSION_FIELD]);
|
|
11139
|
+
const prev = store.getFieldState(CHIEF_TEXT_FIELD)?.value;
|
|
11140
|
+
const prevText = typeof prev === "string" ? prev : "";
|
|
11141
|
+
const kept = prevText.split(",").map((t) => t.trim()).filter(Boolean).filter((t) => {
|
|
11142
|
+
const lower = t.toLowerCase();
|
|
11143
|
+
return !lower.startsWith("duration:") && !lower.startsWith("onset:") && !lower.startsWith("progression:");
|
|
11144
|
+
});
|
|
11145
|
+
const extra = nonEmptyLines([
|
|
11146
|
+
duration ? `Duration: ${duration}` : "",
|
|
11147
|
+
onset ? `Onset: ${onset}` : "",
|
|
11148
|
+
progression ? `Progression: ${progression}` : ""
|
|
11149
|
+
]);
|
|
11150
|
+
const next = [...kept, ...extra].join(", ").trim();
|
|
11151
|
+
if (prevText.trim() === next.trim()) return;
|
|
11152
|
+
store.setValues({ [CHIEF_TEXT_FIELD]: next }, { touch: false });
|
|
11153
|
+
}, [
|
|
11154
|
+
disabled,
|
|
11155
|
+
state.values[URO_DURATION_FIELD],
|
|
11156
|
+
state.values[URO_ONSET_FIELD],
|
|
11157
|
+
state.values[URO_PROGRESSION_FIELD],
|
|
11158
|
+
store
|
|
11159
|
+
]);
|
|
11204
11160
|
if (!fieldDef) return null;
|
|
11205
11161
|
const theme = getThemeConfig("textarea", fieldDef.theme);
|
|
11206
11162
|
const wrapperClass = theme?.wrapperClassName ?? "rounded-md overflow-hidden flex flex-col border border-[#D0D0D0]";
|
|
@@ -11219,7 +11175,7 @@ var UrologySmartHistoryWidget = ({ fieldId }) => {
|
|
|
11219
11175
|
/* @__PURE__ */ jsxs("div", { className: bodyClass, children: [
|
|
11220
11176
|
/* @__PURE__ */ jsx("p", { className: "text-[11px] text-muted-foreground", children: "Panels follow chief complaint chips and active syndrome (Clearsight SmartHistoryUro)." }),
|
|
11221
11177
|
showPain ? /* @__PURE__ */ jsx(Panel2, { title: "SOCRATES \u2014 Pain (flank / suprapubic / testicular)", children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-2 md:grid-cols-4", children: [
|
|
11222
|
-
|
|
11178
|
+
SOCRATES_KEYS2.map((k) => /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
|
|
11223
11179
|
/* @__PURE__ */ jsx("span", { className: "text-[10px] font-medium uppercase tracking-wide text-muted-foreground", children: k }),
|
|
11224
11180
|
/* @__PURE__ */ jsx(
|
|
11225
11181
|
Input,
|
|
@@ -11455,15 +11411,50 @@ var UrologySmartHistoryWidget = ({ fieldId }) => {
|
|
|
11455
11411
|
] })
|
|
11456
11412
|
] }) }) : null,
|
|
11457
11413
|
/* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
|
|
11458
|
-
/* @__PURE__ */
|
|
11414
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2", children: [
|
|
11415
|
+
/* @__PURE__ */ jsx(Label, { className: "text-xs font-semibold text-slate-700", children: hopcField.fieldDef?.label ?? "History of presenting complaint" }),
|
|
11416
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
11417
|
+
hopcNarrativeLocked ? /* @__PURE__ */ jsxs("span", { className: "rounded bg-amber-50 px-1.5 py-0.5 text-[10px] font-medium text-amber-900 ring-1 ring-amber-200/80", children: [
|
|
11418
|
+
"You edited this summary. Use",
|
|
11419
|
+
" ",
|
|
11420
|
+
/* @__PURE__ */ jsx("span", { className: "italic", children: "'Regenerate'" }),
|
|
11421
|
+
" to update it from the form."
|
|
11422
|
+
] }) : null,
|
|
11423
|
+
hopcNarrativeLocked ? /* @__PURE__ */ jsx(
|
|
11424
|
+
Button,
|
|
11425
|
+
{
|
|
11426
|
+
type: "button",
|
|
11427
|
+
variant: "outline",
|
|
11428
|
+
size: "sm",
|
|
11429
|
+
className: "h-7 shrink-0 px-2 text-xs",
|
|
11430
|
+
disabled: disabled || hopcField.disabled,
|
|
11431
|
+
onClick: () => {
|
|
11432
|
+
setHopcNarrativeLocked(false);
|
|
11433
|
+
hopcField.setValue(
|
|
11434
|
+
formatUrologySmartHistoryToSymptomsNarrative(
|
|
11435
|
+
normalizeUrologySmartHistory(value),
|
|
11436
|
+
{ showPain, showLUTS, showHaem, showSex }
|
|
11437
|
+
)
|
|
11438
|
+
);
|
|
11439
|
+
},
|
|
11440
|
+
children: "Regenerate"
|
|
11441
|
+
}
|
|
11442
|
+
) : null
|
|
11443
|
+
] })
|
|
11444
|
+
] }),
|
|
11445
|
+
hopcNarrativeLocked ? /* @__PURE__ */ jsx("p", { className: "text-[10px] text-muted-foreground", children: "Edit this box anytime. Use Regenerate to replace with fresh text from the structured fields." }) : null,
|
|
11459
11446
|
/* @__PURE__ */ jsx(
|
|
11460
11447
|
Textarea,
|
|
11461
11448
|
{
|
|
11462
|
-
className: "min-h-[
|
|
11463
|
-
placeholder: "
|
|
11464
|
-
value:
|
|
11465
|
-
onChange: (e) =>
|
|
11466
|
-
|
|
11449
|
+
className: "min-h-[88px] rounded-md border border-input bg-white text-sm",
|
|
11450
|
+
placeholder: "Auto-filled from chief complaints + smart history\u2026",
|
|
11451
|
+
value: typeof hopcField.value === "string" ? hopcField.value : hopcField.value == null ? "" : String(hopcField.value),
|
|
11452
|
+
onChange: (e) => {
|
|
11453
|
+
setHopcNarrativeLocked(true);
|
|
11454
|
+
hopcField.setValue(e.target.value);
|
|
11455
|
+
hopcField.setTouched();
|
|
11456
|
+
},
|
|
11457
|
+
disabled: disabled || hopcField.disabled
|
|
11467
11458
|
}
|
|
11468
11459
|
)
|
|
11469
11460
|
] })
|
|
@@ -11471,6 +11462,7 @@ var UrologySmartHistoryWidget = ({ fieldId }) => {
|
|
|
11471
11462
|
showError ? /* @__PURE__ */ jsx("p", { className: "px-3 pb-2 text-xs text-red-500", children: error }) : null
|
|
11472
11463
|
] });
|
|
11473
11464
|
};
|
|
11465
|
+
var URO_CLINICAL_EXAMINATION_FIELD = "clinical_examination";
|
|
11474
11466
|
var GENERAL_ROWS = [
|
|
11475
11467
|
{ key: "pallor", label: "Pallor (chronic dz)" },
|
|
11476
11468
|
{ key: "oedema", label: "Oedema (renal)" },
|
|
@@ -11501,21 +11493,32 @@ var DRE_CONSISTENCY = ["none", "Soft (benign)", "Firm", "Hard / nodular (maligna
|
|
|
11501
11493
|
var DRE_SULCUS = ["none", "Preserved", "Obliterated"];
|
|
11502
11494
|
var UrologyExaminationWidget = ({ fieldId }) => {
|
|
11503
11495
|
const { fieldDef, value, setValue, setTouched, error, touched, disabled } = useField(fieldId);
|
|
11496
|
+
const clinicalField = useField(URO_CLINICAL_EXAMINATION_FIELD);
|
|
11504
11497
|
const { state } = useForm();
|
|
11505
11498
|
const showError = !!error && (touched || state.submitAttempted);
|
|
11506
11499
|
const safe = useMemo(() => normalizeUrologyExamination(value), [value]);
|
|
11507
|
-
const
|
|
11500
|
+
const [clinicalNarrativeLocked, setClinicalNarrativeLocked] = useState(false);
|
|
11501
|
+
useEffect(() => {
|
|
11502
|
+
if (clinicalNarrativeLocked || disabled) return;
|
|
11503
|
+
const norm = normalizeUrologyExamination(value);
|
|
11504
|
+
const next = formatUrologyExaminationToClinicalExamination(norm);
|
|
11505
|
+
clinicalField.setValue(next);
|
|
11506
|
+
if (norm.examinationNotes !== next) {
|
|
11507
|
+
setValue({ ...norm, examinationNotes: next });
|
|
11508
|
+
}
|
|
11509
|
+
}, [value, clinicalNarrativeLocked, disabled]);
|
|
11510
|
+
const bump = (next) => {
|
|
11508
11511
|
setValue(next);
|
|
11509
11512
|
setTouched();
|
|
11510
11513
|
};
|
|
11511
11514
|
const toggleGeneral = (key) => {
|
|
11512
|
-
|
|
11515
|
+
bump({ ...safe, general: { ...safe.general, [key]: !safe.general[key] } });
|
|
11513
11516
|
};
|
|
11514
11517
|
const toggleAbdomen = (key) => {
|
|
11515
|
-
|
|
11518
|
+
bump({ ...safe, abdomen: { ...safe.abdomen, [key]: !safe.abdomen[key] } });
|
|
11516
11519
|
};
|
|
11517
11520
|
const toggleGu = (key) => {
|
|
11518
|
-
|
|
11521
|
+
bump({ ...safe, gu: { ...safe.gu, [key]: !safe.gu[key] } });
|
|
11519
11522
|
};
|
|
11520
11523
|
if (!fieldDef) return null;
|
|
11521
11524
|
const theme = getThemeConfig("textarea", fieldDef.theme);
|
|
@@ -11583,7 +11586,7 @@ var UrologyExaminationWidget = ({ fieldId }) => {
|
|
|
11583
11586
|
Checkbox,
|
|
11584
11587
|
{
|
|
11585
11588
|
checked: safe.dre.done,
|
|
11586
|
-
onCheckedChange: (c) =>
|
|
11589
|
+
onCheckedChange: (c) => bump({ ...safe, dre: { ...safe.dre, done: c === true } }),
|
|
11587
11590
|
disabled
|
|
11588
11591
|
}
|
|
11589
11592
|
),
|
|
@@ -11600,7 +11603,7 @@ var UrologyExaminationWidget = ({ fieldId }) => {
|
|
|
11600
11603
|
value: safe.dre.sizeGrams,
|
|
11601
11604
|
onChange: (e) => {
|
|
11602
11605
|
const n = Number(e.target.value);
|
|
11603
|
-
|
|
11606
|
+
bump({
|
|
11604
11607
|
...safe,
|
|
11605
11608
|
dre: {
|
|
11606
11609
|
...safe.dre,
|
|
@@ -11618,7 +11621,7 @@ var UrologyExaminationWidget = ({ fieldId }) => {
|
|
|
11618
11621
|
Select,
|
|
11619
11622
|
{
|
|
11620
11623
|
value: safe.dre.consistency || "none",
|
|
11621
|
-
onValueChange: (val) =>
|
|
11624
|
+
onValueChange: (val) => bump({
|
|
11622
11625
|
...safe,
|
|
11623
11626
|
dre: { ...safe.dre, consistency: val === "none" ? "" : val }
|
|
11624
11627
|
}),
|
|
@@ -11636,7 +11639,7 @@ var UrologyExaminationWidget = ({ fieldId }) => {
|
|
|
11636
11639
|
Select,
|
|
11637
11640
|
{
|
|
11638
11641
|
value: safe.dre.medianSulcus || "none",
|
|
11639
|
-
onValueChange: (val) =>
|
|
11642
|
+
onValueChange: (val) => bump({
|
|
11640
11643
|
...safe,
|
|
11641
11644
|
dre: { ...safe.dre, medianSulcus: val === "none" ? "" : val }
|
|
11642
11645
|
}),
|
|
@@ -11653,7 +11656,7 @@ var UrologyExaminationWidget = ({ fieldId }) => {
|
|
|
11653
11656
|
Checkbox,
|
|
11654
11657
|
{
|
|
11655
11658
|
checked: safe.dre.tenderness,
|
|
11656
|
-
onCheckedChange: (c) =>
|
|
11659
|
+
onCheckedChange: (c) => bump({ ...safe, dre: { ...safe.dre, tenderness: c === true } }),
|
|
11657
11660
|
disabled
|
|
11658
11661
|
}
|
|
11659
11662
|
),
|
|
@@ -11662,15 +11665,49 @@ var UrologyExaminationWidget = ({ fieldId }) => {
|
|
|
11662
11665
|
] })
|
|
11663
11666
|
] }),
|
|
11664
11667
|
/* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
|
|
11665
|
-
/* @__PURE__ */
|
|
11668
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2", children: [
|
|
11669
|
+
/* @__PURE__ */ jsx(Label, { className: "text-xs font-semibold text-slate-700", children: clinicalField.fieldDef?.label ?? "Clinical examination" }),
|
|
11670
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
11671
|
+
clinicalNarrativeLocked ? /* @__PURE__ */ jsxs("span", { className: "rounded bg-amber-50 px-1.5 py-0.5 text-[10px] font-medium text-amber-900 ring-1 ring-amber-200/80", children: [
|
|
11672
|
+
"You edited this summary. Use",
|
|
11673
|
+
" ",
|
|
11674
|
+
/* @__PURE__ */ jsx("span", { className: "italic", children: "'Regenerate'" }),
|
|
11675
|
+
" to update it from the form."
|
|
11676
|
+
] }) : null,
|
|
11677
|
+
clinicalNarrativeLocked ? /* @__PURE__ */ jsx(
|
|
11678
|
+
Button,
|
|
11679
|
+
{
|
|
11680
|
+
type: "button",
|
|
11681
|
+
variant: "outline",
|
|
11682
|
+
size: "sm",
|
|
11683
|
+
className: "h-7 shrink-0 px-2 text-xs",
|
|
11684
|
+
disabled: disabled || clinicalField.disabled,
|
|
11685
|
+
onClick: () => {
|
|
11686
|
+
setClinicalNarrativeLocked(false);
|
|
11687
|
+
const norm = normalizeUrologyExamination(value);
|
|
11688
|
+
clinicalField.setValue(formatUrologyExaminationToClinicalExamination(norm));
|
|
11689
|
+
},
|
|
11690
|
+
children: "Regenerate"
|
|
11691
|
+
}
|
|
11692
|
+
) : null
|
|
11693
|
+
] })
|
|
11694
|
+
] }),
|
|
11695
|
+
clinicalNarrativeLocked ? /* @__PURE__ */ jsx("p", { className: "text-[10px] text-muted-foreground", children: "Edit this box anytime. Use Regenerate to replace with fresh text from the structured examination." }) : null,
|
|
11666
11696
|
/* @__PURE__ */ jsx(
|
|
11667
11697
|
Textarea,
|
|
11668
11698
|
{
|
|
11669
11699
|
className: "min-h-[88px] rounded-md border border-input bg-white text-sm",
|
|
11670
|
-
placeholder: "
|
|
11671
|
-
value:
|
|
11672
|
-
onChange: (e) =>
|
|
11673
|
-
|
|
11700
|
+
placeholder: "Auto-filled from selections above\u2026",
|
|
11701
|
+
value: typeof clinicalField.value === "string" ? clinicalField.value : clinicalField.value == null ? "" : String(clinicalField.value),
|
|
11702
|
+
onChange: (e) => {
|
|
11703
|
+
setClinicalNarrativeLocked(true);
|
|
11704
|
+
const t = e.target.value;
|
|
11705
|
+
clinicalField.setValue(t);
|
|
11706
|
+
clinicalField.setTouched();
|
|
11707
|
+
setValue({ ...safe, examinationNotes: t });
|
|
11708
|
+
setTouched();
|
|
11709
|
+
},
|
|
11710
|
+
disabled: disabled || clinicalField.disabled
|
|
11674
11711
|
}
|
|
11675
11712
|
)
|
|
11676
11713
|
] })
|
|
@@ -11678,265 +11715,142 @@ var UrologyExaminationWidget = ({ fieldId }) => {
|
|
|
11678
11715
|
showError ? /* @__PURE__ */ jsx("p", { className: "px-3 pb-2 text-xs text-red-500", children: error }) : null
|
|
11679
11716
|
] });
|
|
11680
11717
|
};
|
|
11681
|
-
var
|
|
11682
|
-
|
|
11683
|
-
|
|
11684
|
-
|
|
11685
|
-
|
|
11686
|
-
|
|
11687
|
-
children
|
|
11688
|
-
}) {
|
|
11689
|
-
return /* @__PURE__ */ jsxs("div", { className: cn("overflow-hidden rounded-md border border-[#D0D0D0] bg-white", className), children: [
|
|
11690
|
-
/* @__PURE__ */ jsx("div", { className: "border-b border-[#D0D0D0] bg-[#FEE8EC]/50 px-3 py-1.5", children: /* @__PURE__ */ jsx("span", { className: "text-xs font-semibold text-slate-700", children: title }) }),
|
|
11691
|
-
/* @__PURE__ */ jsx("div", { className: "p-3", children })
|
|
11692
|
-
] });
|
|
11693
|
-
}
|
|
11718
|
+
var RISK_ROWS = [
|
|
11719
|
+
{ key: "ckd", label: "Chronic kidney disease" },
|
|
11720
|
+
{ key: "diabetes", label: "Diabetes" },
|
|
11721
|
+
{ key: "anticoagulants", label: "Anticoagulants" },
|
|
11722
|
+
{ key: "activeInfection", label: "Active infection" }
|
|
11723
|
+
];
|
|
11694
11724
|
var UrologyPathwayWidget = ({ fieldId }) => {
|
|
11695
11725
|
const { fieldDef, value, setValue, setTouched, error, touched, disabled } = useField(fieldId);
|
|
11696
11726
|
const { state } = useForm();
|
|
11697
11727
|
const showError = !!error && (touched || state.submitAttempted);
|
|
11698
11728
|
const safe = useMemo(() => normalizeUrologyPathway(value), [value]);
|
|
11699
|
-
const smart = useMemo(
|
|
11700
|
-
() => normalizeUrologySmartHistory(state.values[SMART_HISTORY_FIELD]),
|
|
11701
|
-
[state.values]
|
|
11702
|
-
);
|
|
11703
|
-
const exam = useMemo(
|
|
11704
|
-
() => normalizeUrologyExamination(state.values[EXAMINATION_FIELD]),
|
|
11705
|
-
[state.values]
|
|
11706
|
-
);
|
|
11707
|
-
const ipssTotal = urologyIpssSevenTotal(smart.ipss);
|
|
11708
|
-
const ipssBandCls = ipssTotal >= 20 ? "bg-red-500/15 text-red-700" : ipssTotal >= 8 ? "bg-amber-500/15 text-amber-900" : "bg-emerald-500/15 text-emerald-800";
|
|
11709
|
-
const stone = useMemo(
|
|
11710
|
-
() => urologyStoneRecommendation(safe.stoneSizeMm, safe.hydronephrosis),
|
|
11711
|
-
[safe.stoneSizeMm, safe.hydronephrosis]
|
|
11712
|
-
);
|
|
11713
|
-
const prostateLine = useMemo(
|
|
11714
|
-
() => urologyProstateProcedure(safe.prostateVolumeCc),
|
|
11715
|
-
[safe.prostateVolumeCc]
|
|
11716
|
-
);
|
|
11717
|
-
const psaHigh = safe.psaNgMl > 4;
|
|
11718
|
-
const qmaxLow = safe.uroflowQmaxMlSec > 0 && Number.isFinite(safe.uroflowQmaxMlSec) && safe.uroflowQmaxMlSec < 10;
|
|
11719
11729
|
const update = (next) => {
|
|
11720
11730
|
setValue(next);
|
|
11721
11731
|
setTouched();
|
|
11722
11732
|
};
|
|
11723
|
-
const
|
|
11724
|
-
|
|
11733
|
+
const setNum = (key, raw) => {
|
|
11734
|
+
const n = Number(raw);
|
|
11735
|
+
const v = Number.isFinite(n) && n >= 0 ? n : 0;
|
|
11736
|
+
if (key === "stoneSizeMm") {
|
|
11737
|
+
update({ ...safe, stoneSizeMm: Math.round(v) });
|
|
11738
|
+
return;
|
|
11739
|
+
}
|
|
11740
|
+
update({ ...safe, [key]: v });
|
|
11741
|
+
};
|
|
11742
|
+
const toggleRisk = (key) => {
|
|
11743
|
+
update({
|
|
11744
|
+
...safe,
|
|
11745
|
+
risk: { ...safe.risk, [key]: !safe.risk[key] }
|
|
11746
|
+
});
|
|
11725
11747
|
};
|
|
11726
11748
|
if (!fieldDef) return null;
|
|
11727
11749
|
const theme = getThemeConfig("textarea", fieldDef.theme);
|
|
11728
11750
|
const wrapperClass = theme?.wrapperClassName ?? "rounded-md overflow-hidden flex flex-col border border-[#D0D0D0]";
|
|
11729
11751
|
const labelClass = theme?.labelClassName;
|
|
11752
|
+
const subtitle = fieldDef.meta && typeof fieldDef.meta === "object" && fieldDef.meta !== null ? String(fieldDef.meta.subtitle ?? "") : "";
|
|
11730
11753
|
const labelContent = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
11731
11754
|
fieldDef.label,
|
|
11732
11755
|
fieldDef.required ? /* @__PURE__ */ jsx("span", { className: "ml-1 text-red-500", children: "*" }) : null
|
|
11733
11756
|
] });
|
|
11734
11757
|
const labelEl = theme ? /* @__PURE__ */ jsx(Label, { className: labelClass, children: labelContent }) : /* @__PURE__ */ jsx(Label, { className: "text-sm font-medium", children: labelContent });
|
|
11735
11758
|
const bodyClass = cn(
|
|
11736
|
-
"-mt-1 flex min-w-0 flex-col gap-
|
|
11759
|
+
"-mt-1 flex min-w-0 flex-col gap-4 border-t border-[#D0D0D0] bg-white px-3 py-3",
|
|
11737
11760
|
disabled && "pointer-events-none opacity-60"
|
|
11738
11761
|
);
|
|
11739
|
-
const subtitle = typeof fieldDef.meta?.subtitle === "string" && fieldDef.meta.subtitle.trim().length > 0 ? fieldDef.meta.subtitle.trim() : "";
|
|
11740
11762
|
return /* @__PURE__ */ jsxs("div", { className: cn("w-full min-w-0", wrapperClass), children: [
|
|
11741
11763
|
labelEl,
|
|
11764
|
+
subtitle ? /* @__PURE__ */ jsx("p", { className: "px-3 pt-2 text-[11px] text-muted-foreground", children: subtitle }) : null,
|
|
11742
11765
|
/* @__PURE__ */ jsxs("div", { className: bodyClass, children: [
|
|
11743
|
-
|
|
11744
|
-
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 gap-3
|
|
11745
|
-
/* @__PURE__ */ jsxs(
|
|
11746
|
-
/* @__PURE__ */
|
|
11747
|
-
/* @__PURE__ */ jsx("span", { className: "mb-1 block font-medium text-slate-700", children: "Stone size (mm)" }),
|
|
11748
|
-
/* @__PURE__ */ jsx(
|
|
11749
|
-
Input,
|
|
11750
|
-
{
|
|
11751
|
-
type: "number",
|
|
11752
|
-
min: 0,
|
|
11753
|
-
step: "any",
|
|
11754
|
-
className: cn(
|
|
11755
|
-
"h-8 text-xs",
|
|
11756
|
-
disabled && "pointer-events-none"
|
|
11757
|
-
),
|
|
11758
|
-
value: safe.stoneSizeMm,
|
|
11759
|
-
onChange: (e) => {
|
|
11760
|
-
const raw = e.target.value;
|
|
11761
|
-
const n = Number(raw);
|
|
11762
|
-
update({
|
|
11763
|
-
...safe,
|
|
11764
|
-
stoneSizeMm: raw === "" || raw === "-" ? 0 : !Number.isFinite(n) ? 0 : Math.max(0, n)
|
|
11765
|
-
});
|
|
11766
|
-
},
|
|
11767
|
-
disabled
|
|
11768
|
-
}
|
|
11769
|
-
)
|
|
11770
|
-
] }),
|
|
11771
|
-
/* @__PURE__ */ jsxs("label", { className: "mt-2 flex items-center gap-2", children: [
|
|
11772
|
-
/* @__PURE__ */ jsx(
|
|
11773
|
-
Checkbox,
|
|
11774
|
-
{
|
|
11775
|
-
checked: safe.hydronephrosis,
|
|
11776
|
-
disabled,
|
|
11777
|
-
onCheckedChange: (checked) => update({ ...safe, hydronephrosis: checked === true })
|
|
11778
|
-
}
|
|
11779
|
-
),
|
|
11780
|
-
/* @__PURE__ */ jsx("span", { className: "text-slate-700", children: "Hydronephrosis on imaging" })
|
|
11781
|
-
] }),
|
|
11766
|
+
showError ? /* @__PURE__ */ jsx("p", { className: "text-xs text-red-600", children: error }) : null,
|
|
11767
|
+
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 gap-3 md:grid-cols-2", children: [
|
|
11768
|
+
/* @__PURE__ */ jsxs("label", { className: "block space-y-1 text-xs", children: [
|
|
11769
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium", children: "Stone size (mm)" }),
|
|
11782
11770
|
/* @__PURE__ */ jsx(
|
|
11783
|
-
|
|
11771
|
+
Input,
|
|
11784
11772
|
{
|
|
11785
|
-
|
|
11786
|
-
|
|
11787
|
-
|
|
11788
|
-
|
|
11789
|
-
|
|
11773
|
+
type: "number",
|
|
11774
|
+
min: 0,
|
|
11775
|
+
className: "h-8 text-xs",
|
|
11776
|
+
value: safe.stoneSizeMm,
|
|
11777
|
+
onChange: (e) => setNum("stoneSizeMm", e.target.value),
|
|
11778
|
+
disabled
|
|
11790
11779
|
}
|
|
11791
|
-
)
|
|
11792
|
-
/* @__PURE__ */ jsx("p", { className: "mt-1 text-[10px] text-muted-foreground", children: "Trigger: >10 mm OR obstruction \u2192 surgical." })
|
|
11780
|
+
)
|
|
11793
11781
|
] }),
|
|
11794
|
-
/* @__PURE__ */ jsxs(
|
|
11795
|
-
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-2", children: [
|
|
11796
|
-
/* @__PURE__ */ jsxs("label", { className: "block", children: [
|
|
11797
|
-
/* @__PURE__ */ jsx("span", { className: "mb-1 block font-medium text-slate-700", children: "Volume (cc)" }),
|
|
11798
|
-
/* @__PURE__ */ jsx(
|
|
11799
|
-
Input,
|
|
11800
|
-
{
|
|
11801
|
-
type: "number",
|
|
11802
|
-
min: 0,
|
|
11803
|
-
step: "any",
|
|
11804
|
-
className: cn(
|
|
11805
|
-
"h-8 text-xs",
|
|
11806
|
-
disabled && "pointer-events-none"
|
|
11807
|
-
),
|
|
11808
|
-
value: safe.prostateVolumeCc,
|
|
11809
|
-
onChange: (e) => {
|
|
11810
|
-
const raw = e.target.value;
|
|
11811
|
-
const n = Number(raw);
|
|
11812
|
-
update({
|
|
11813
|
-
...safe,
|
|
11814
|
-
prostateVolumeCc: raw === "" || raw === "-" ? 0 : !Number.isFinite(n) ? 0 : Math.max(0, n)
|
|
11815
|
-
});
|
|
11816
|
-
},
|
|
11817
|
-
disabled
|
|
11818
|
-
}
|
|
11819
|
-
)
|
|
11820
|
-
] }),
|
|
11821
|
-
/* @__PURE__ */ jsxs("label", { className: "block", children: [
|
|
11822
|
-
/* @__PURE__ */ jsx("span", { className: "mb-1 block font-medium text-slate-700", children: "PSA (ng/ml)" }),
|
|
11823
|
-
/* @__PURE__ */ jsx(
|
|
11824
|
-
Input,
|
|
11825
|
-
{
|
|
11826
|
-
type: "number",
|
|
11827
|
-
min: 0,
|
|
11828
|
-
step: 0.1,
|
|
11829
|
-
className: cn(
|
|
11830
|
-
"h-8 text-xs",
|
|
11831
|
-
psaHigh && "border-red-400 text-red-800",
|
|
11832
|
-
disabled && "pointer-events-none"
|
|
11833
|
-
),
|
|
11834
|
-
value: safe.psaNgMl,
|
|
11835
|
-
onChange: (e) => {
|
|
11836
|
-
const raw = e.target.value;
|
|
11837
|
-
const n = Number(raw);
|
|
11838
|
-
update({
|
|
11839
|
-
...safe,
|
|
11840
|
-
psaNgMl: raw === "" || raw === "-" ? 0 : !Number.isFinite(n) ? 0 : Math.max(0, n)
|
|
11841
|
-
});
|
|
11842
|
-
},
|
|
11843
|
-
disabled
|
|
11844
|
-
}
|
|
11845
|
-
)
|
|
11846
|
-
] }),
|
|
11847
|
-
/* @__PURE__ */ jsxs("label", { className: "col-span-2 block", children: [
|
|
11848
|
-
/* @__PURE__ */ jsx("span", { className: "mb-1 block font-medium text-slate-700", children: "Uroflow Qmax (ml/s)" }),
|
|
11849
|
-
/* @__PURE__ */ jsx(
|
|
11850
|
-
Input,
|
|
11851
|
-
{
|
|
11852
|
-
type: "number",
|
|
11853
|
-
min: 0,
|
|
11854
|
-
step: 0.1,
|
|
11855
|
-
className: cn(
|
|
11856
|
-
"h-8 text-xs",
|
|
11857
|
-
qmaxLow && "border-amber-500 text-amber-900",
|
|
11858
|
-
disabled && "pointer-events-none"
|
|
11859
|
-
),
|
|
11860
|
-
value: safe.uroflowQmaxMlSec,
|
|
11861
|
-
onChange: (e) => {
|
|
11862
|
-
const raw = e.target.value;
|
|
11863
|
-
const n = Number(raw);
|
|
11864
|
-
update({
|
|
11865
|
-
...safe,
|
|
11866
|
-
uroflowQmaxMlSec: raw === "" || raw === "-" ? 0 : !Number.isFinite(n) ? 0 : Math.max(0, n)
|
|
11867
|
-
});
|
|
11868
|
-
},
|
|
11869
|
-
disabled
|
|
11870
|
-
}
|
|
11871
|
-
)
|
|
11872
|
-
] })
|
|
11873
|
-
] }),
|
|
11782
|
+
/* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2 pt-6 text-xs", children: [
|
|
11874
11783
|
/* @__PURE__ */ jsx(
|
|
11875
|
-
|
|
11784
|
+
Checkbox,
|
|
11876
11785
|
{
|
|
11877
|
-
|
|
11878
|
-
|
|
11879
|
-
|
|
11880
|
-
),
|
|
11881
|
-
children: prostateLine
|
|
11786
|
+
checked: safe.hydronephrosis,
|
|
11787
|
+
onCheckedChange: (c) => update({ ...safe, hydronephrosis: c === true }),
|
|
11788
|
+
disabled
|
|
11882
11789
|
}
|
|
11883
11790
|
),
|
|
11884
|
-
|
|
11791
|
+
"Hydronephrosis on imaging"
|
|
11885
11792
|
] }),
|
|
11886
|
-
/* @__PURE__ */ jsxs(
|
|
11887
|
-
/* @__PURE__ */
|
|
11888
|
-
|
|
11889
|
-
|
|
11890
|
-
ipssTotal,
|
|
11891
|
-
"/35 \xB7 ",
|
|
11892
|
-
urologyIpssBand(ipssTotal)
|
|
11893
|
-
] })
|
|
11894
|
-
] }),
|
|
11895
|
-
/* @__PURE__ */ jsx("div", { className: "mb-3 h-1.5 overflow-hidden rounded-full bg-slate-200", children: /* @__PURE__ */ jsx(
|
|
11896
|
-
"div",
|
|
11793
|
+
/* @__PURE__ */ jsxs("label", { className: "block space-y-1 text-xs", children: [
|
|
11794
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium", children: "Prostate volume (cc)" }),
|
|
11795
|
+
/* @__PURE__ */ jsx(
|
|
11796
|
+
Input,
|
|
11897
11797
|
{
|
|
11898
|
-
|
|
11899
|
-
|
|
11900
|
-
|
|
11901
|
-
|
|
11902
|
-
|
|
11798
|
+
type: "number",
|
|
11799
|
+
min: 0,
|
|
11800
|
+
step: 0.1,
|
|
11801
|
+
className: "h-8 text-xs",
|
|
11802
|
+
value: safe.prostateVolumeCc,
|
|
11803
|
+
onChange: (e) => setNum("prostateVolumeCc", e.target.value),
|
|
11804
|
+
disabled
|
|
11903
11805
|
}
|
|
11904
|
-
)
|
|
11905
|
-
|
|
11906
|
-
|
|
11907
|
-
|
|
11908
|
-
|
|
11909
|
-
|
|
11910
|
-
|
|
11911
|
-
|
|
11912
|
-
|
|
11913
|
-
|
|
11914
|
-
"
|
|
11915
|
-
|
|
11916
|
-
|
|
11917
|
-
|
|
11918
|
-
|
|
11919
|
-
|
|
11806
|
+
)
|
|
11807
|
+
] }),
|
|
11808
|
+
/* @__PURE__ */ jsxs("label", { className: "block space-y-1 text-xs", children: [
|
|
11809
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium", children: "PSA (ng/mL)" }),
|
|
11810
|
+
/* @__PURE__ */ jsx(
|
|
11811
|
+
Input,
|
|
11812
|
+
{
|
|
11813
|
+
type: "number",
|
|
11814
|
+
min: 0,
|
|
11815
|
+
step: 0.01,
|
|
11816
|
+
className: "h-8 text-xs",
|
|
11817
|
+
value: safe.psaNgMl,
|
|
11818
|
+
onChange: (e) => setNum("psaNgMl", e.target.value),
|
|
11819
|
+
disabled
|
|
11820
|
+
}
|
|
11821
|
+
)
|
|
11920
11822
|
] }),
|
|
11921
|
-
/* @__PURE__ */
|
|
11922
|
-
|
|
11923
|
-
|
|
11924
|
-
|
|
11925
|
-
|
|
11926
|
-
|
|
11823
|
+
/* @__PURE__ */ jsxs("label", { className: "block space-y-1 text-xs md:col-span-2", children: [
|
|
11824
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium", children: "Uroflow Qmax (mL/s)" }),
|
|
11825
|
+
/* @__PURE__ */ jsx(
|
|
11826
|
+
Input,
|
|
11827
|
+
{
|
|
11828
|
+
type: "number",
|
|
11829
|
+
min: 0,
|
|
11830
|
+
step: 0.1,
|
|
11831
|
+
className: "h-8 text-xs",
|
|
11832
|
+
value: safe.uroflowQmaxMlSec,
|
|
11833
|
+
onChange: (e) => setNum("uroflowQmaxMlSec", e.target.value),
|
|
11834
|
+
disabled
|
|
11835
|
+
}
|
|
11836
|
+
)
|
|
11837
|
+
] })
|
|
11838
|
+
] }),
|
|
11839
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-2 border-t border-muted-foreground/20 pt-3", children: [
|
|
11840
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs font-semibold text-slate-800", children: "Risk stratification" }),
|
|
11841
|
+
/* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 gap-2 sm:grid-cols-2", children: RISK_ROWS.map((r) => /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2 text-xs", children: [
|
|
11927
11842
|
/* @__PURE__ */ jsx(
|
|
11928
11843
|
Checkbox,
|
|
11929
11844
|
{
|
|
11930
|
-
checked: safe.risk[key],
|
|
11931
|
-
|
|
11932
|
-
|
|
11845
|
+
checked: safe.risk[r.key],
|
|
11846
|
+
onCheckedChange: () => toggleRisk(r.key),
|
|
11847
|
+
disabled
|
|
11933
11848
|
}
|
|
11934
11849
|
),
|
|
11935
|
-
|
|
11936
|
-
] }, key)) })
|
|
11850
|
+
r.label
|
|
11851
|
+
] }, r.key)) })
|
|
11937
11852
|
] })
|
|
11938
|
-
] })
|
|
11939
|
-
showError ? /* @__PURE__ */ jsx("p", { className: "px-3 pb-2 text-xs text-red-500", children: error }) : null
|
|
11853
|
+
] })
|
|
11940
11854
|
] });
|
|
11941
11855
|
};
|
|
11942
11856
|
var FieldRenderer = ({ fieldId }) => {
|
|
@@ -12889,22 +12803,32 @@ var ReadOnlyFieldRenderer = ({
|
|
|
12889
12803
|
].join("\n");
|
|
12890
12804
|
return /* @__PURE__ */ jsx(ReadOnlyText, { fieldDef, value: lines });
|
|
12891
12805
|
}
|
|
12892
|
-
case "urology_smart_history":
|
|
12893
|
-
|
|
12894
|
-
|
|
12895
|
-
|
|
12896
|
-
|
|
12897
|
-
|
|
12898
|
-
}
|
|
12899
|
-
|
|
12900
|
-
|
|
12901
|
-
|
|
12902
|
-
|
|
12903
|
-
|
|
12904
|
-
|
|
12905
|
-
|
|
12906
|
-
|
|
12907
|
-
);
|
|
12806
|
+
case "urology_smart_history": {
|
|
12807
|
+
const structuredDisplay = value && typeof value === "object" ? JSON.stringify(normalizeUrologySmartHistory(value), null, 2) : value == null || value === "" ? "\u2014" : String(value);
|
|
12808
|
+
const hopcDef = resolveFieldDef?.("symptoms");
|
|
12809
|
+
const hopcRaw = allValues?.["symptoms"];
|
|
12810
|
+
const hopcStr = typeof hopcRaw === "string" ? hopcRaw : hopcRaw != null && hopcRaw !== "" ? String(hopcRaw) : "";
|
|
12811
|
+
return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
|
|
12812
|
+
/* @__PURE__ */ jsx(ReadOnlyText, { fieldDef, value: structuredDisplay }),
|
|
12813
|
+
hopcDef ? /* @__PURE__ */ jsx(ReadOnlyText, { fieldDef: hopcDef, value: hopcStr }) : hopcStr ? /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
12814
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-gray-700", children: "History of presenting complaint" }),
|
|
12815
|
+
/* @__PURE__ */ jsx("div", { className: "text-gray-900 border border-gray-200 rounded-md p-3 bg-gray-50 min-h-[2.5rem] whitespace-pre-wrap", children: hopcStr })
|
|
12816
|
+
] }) : null
|
|
12817
|
+
] });
|
|
12818
|
+
}
|
|
12819
|
+
case "urology_examination": {
|
|
12820
|
+
const structuredDisplay = value && typeof value === "object" ? JSON.stringify(value, null, 2) : value == null || value === "" ? "\u2014" : String(value);
|
|
12821
|
+
const clinicalDef = resolveFieldDef?.("clinical_examination");
|
|
12822
|
+
const clinicalRaw = allValues?.["clinical_examination"];
|
|
12823
|
+
const clinicalStr = typeof clinicalRaw === "string" ? clinicalRaw : clinicalRaw != null && clinicalRaw !== "" ? String(clinicalRaw) : "";
|
|
12824
|
+
return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
|
|
12825
|
+
/* @__PURE__ */ jsx(ReadOnlyText, { fieldDef, value: structuredDisplay }),
|
|
12826
|
+
clinicalDef ? /* @__PURE__ */ jsx(ReadOnlyText, { fieldDef: clinicalDef, value: clinicalStr }) : clinicalStr ? /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
12827
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-gray-700", children: "Clinical examination" }),
|
|
12828
|
+
/* @__PURE__ */ jsx("div", { className: "text-gray-900 border border-gray-200 rounded-md p-3 bg-gray-50 min-h-[2.5rem] whitespace-pre-wrap", children: clinicalStr })
|
|
12829
|
+
] }) : null
|
|
12830
|
+
] });
|
|
12831
|
+
}
|
|
12908
12832
|
case "urology_pathway":
|
|
12909
12833
|
return /* @__PURE__ */ jsx(
|
|
12910
12834
|
ReadOnlyText,
|
|
@@ -13154,6 +13078,6 @@ function createUploadHandler(options) {
|
|
|
13154
13078
|
};
|
|
13155
13079
|
}
|
|
13156
13080
|
|
|
13157
|
-
export { AddInvestigationField, AddMedicationField, DifferentialDiagnosis, DynamicForm, EMAIL_REGEX, FieldRenderer, FormControls, FormProvider, FormStore, ImageUploadWidget, MAR_MEDICATION_ORDERS_META_KEY, MediaUploadWidget, ReadOnlyForm, ReadOnlyImageUpload, ReadOnlyMediaUpload, ReadOnlySignature, ReadOnlyTable, RichTextWidget, SignatureUploadWidget, SmartForm, SmartTextareaWidget,
|
|
13081
|
+
export { AddInvestigationField, AddMedicationField, DifferentialDiagnosis, DynamicForm, EMAIL_REGEX, FieldRenderer, FormControls, FormProvider, FormStore, ImageUploadWidget, MAR_MEDICATION_ORDERS_META_KEY, MediaUploadWidget, ReadOnlyForm, ReadOnlyImageUpload, ReadOnlyMediaUpload, ReadOnlySignature, ReadOnlyTable, RichTextWidget, SignatureUploadWidget, SmartForm, SmartTextareaWidget, createUploadHandler, evaluateRules, fieldMetaRequestsMarMedicationOrdersButton, useField, useFieldHandlers, useForm, useFormStore, useFrequentItems, usePackages, useSmartKeywords, validateField, validateForm };
|
|
13158
13082
|
//# sourceMappingURL=index.mjs.map
|
|
13159
13083
|
//# sourceMappingURL=index.mjs.map
|