formanitor 0.0.39 → 0.0.41
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 +1903 -92
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +34 -3
- package/dist/index.d.ts +34 -3
- package/dist/index.mjs +1901 -93
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -30,6 +30,326 @@ 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
|
+
|
|
33
353
|
// src/core/validate.ts
|
|
34
354
|
var EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
35
355
|
function validateField(value, field) {
|
|
@@ -225,8 +545,21 @@ var defaultGeneralSurgerySmartHistory = () => ({
|
|
|
225
545
|
gi: { appetite: "", weightLoss: "", bowelHabits: "", checks: [] },
|
|
226
546
|
breast: { lumpDuration: "", nippleDischarge: "", checks: [] },
|
|
227
547
|
ano: { checks: [] },
|
|
228
|
-
thyroid: { swellingDuration: "", checks: [] }
|
|
229
|
-
|
|
548
|
+
thyroid: { swellingDuration: "", checks: [] }
|
|
549
|
+
});
|
|
550
|
+
var defaultBreastExamSide = () => ({
|
|
551
|
+
size: "",
|
|
552
|
+
quadrant: "",
|
|
553
|
+
tenderness: "",
|
|
554
|
+
fixity: "",
|
|
555
|
+
skinInvolvement: "",
|
|
556
|
+
consistency: "",
|
|
557
|
+
axillaryNodes: false,
|
|
558
|
+
nippleAreolarComplex: false
|
|
559
|
+
});
|
|
560
|
+
var defaultBreastExaminationBlock = () => ({
|
|
561
|
+
left: defaultBreastExamSide(),
|
|
562
|
+
right: defaultBreastExamSide()
|
|
230
563
|
});
|
|
231
564
|
var defaultGeneralSurgeryExamination = () => ({
|
|
232
565
|
general: [],
|
|
@@ -239,7 +572,7 @@ var defaultGeneralSurgeryExamination = () => ({
|
|
|
239
572
|
bowelSounds: "none"
|
|
240
573
|
},
|
|
241
574
|
hernia: { site: "", reducible: false, coughImpulse: false, tenderness: false },
|
|
242
|
-
breast:
|
|
575
|
+
breast: defaultBreastExaminationBlock(),
|
|
243
576
|
thyroid: { size: "", mobileDeglutition: false, nodules: false, cervicalNodes: false },
|
|
244
577
|
anorectal: { inspection: "", dreDone: false, proctoscopyDone: false, notes: "" },
|
|
245
578
|
limb: { dilatedVeins: false, ulcer: false, oedema: false }
|
|
@@ -335,8 +668,32 @@ function normalizeGeneralSurgerySmartHistory(raw) {
|
|
|
335
668
|
thyroid: {
|
|
336
669
|
swellingDuration: str2(thy.swellingDuration),
|
|
337
670
|
checks: strArr(thy.checks)
|
|
338
|
-
}
|
|
339
|
-
|
|
671
|
+
}
|
|
672
|
+
};
|
|
673
|
+
}
|
|
674
|
+
function normalizeBreastExamSide(partial) {
|
|
675
|
+
const e = defaultBreastExamSide();
|
|
676
|
+
const str2 = (x) => typeof x === "string" ? x : "";
|
|
677
|
+
const bool = (x) => x === true;
|
|
678
|
+
if (!partial || typeof partial !== "object") return e;
|
|
679
|
+
const p = partial;
|
|
680
|
+
return {
|
|
681
|
+
size: str2(p.size),
|
|
682
|
+
quadrant: str2(p.quadrant),
|
|
683
|
+
tenderness: str2(p.tenderness),
|
|
684
|
+
fixity: str2(p.fixity),
|
|
685
|
+
skinInvolvement: str2(p.skinInvolvement),
|
|
686
|
+
consistency: str2(p.consistency),
|
|
687
|
+
axillaryNodes: bool(p.axillaryNodes),
|
|
688
|
+
nippleAreolarComplex: bool(p.nippleAreolarComplex)
|
|
689
|
+
};
|
|
690
|
+
}
|
|
691
|
+
function normalizeBreastExaminationBlock(raw) {
|
|
692
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return defaultBreastExaminationBlock();
|
|
693
|
+
const br = raw;
|
|
694
|
+
return {
|
|
695
|
+
left: normalizeBreastExamSide(br.left),
|
|
696
|
+
right: normalizeBreastExamSide(br.right)
|
|
340
697
|
};
|
|
341
698
|
}
|
|
342
699
|
function normalizeGeneralSurgeryExamination(raw) {
|
|
@@ -369,12 +726,7 @@ function normalizeGeneralSurgeryExamination(raw) {
|
|
|
369
726
|
coughImpulse: bool(hb.coughImpulse),
|
|
370
727
|
tenderness: bool(hb.tenderness)
|
|
371
728
|
},
|
|
372
|
-
breast:
|
|
373
|
-
lumpSizeCm: typeof br.lumpSizeCm === "string" ? br.lumpSizeCm : "",
|
|
374
|
-
mobile: bool(br.mobile),
|
|
375
|
-
skinInvolvement: bool(br.skinInvolvement),
|
|
376
|
-
axillaryNodes: bool(br.axillaryNodes)
|
|
377
|
-
},
|
|
729
|
+
breast: normalizeBreastExaminationBlock(br),
|
|
378
730
|
thyroid: {
|
|
379
731
|
size: typeof th.size === "string" ? th.size : "",
|
|
380
732
|
mobileDeglutition: bool(th.mobileDeglutition),
|
|
@@ -412,6 +764,486 @@ function gsGradingRowVisible(cond, chips, regions, grade) {
|
|
|
412
764
|
if (t.regions.some((r) => regions.includes(r))) return true;
|
|
413
765
|
return false;
|
|
414
766
|
}
|
|
767
|
+
var SWELLING_OPT_LABELS = {
|
|
768
|
+
reducible_hernia: "Reducible (hernia)",
|
|
769
|
+
cough_impulse: "Cough impulse",
|
|
770
|
+
skin_changes: "Skin changes"
|
|
771
|
+
};
|
|
772
|
+
var GI_OPT_LABELS = {
|
|
773
|
+
bleeding_pr: "Bleeding PR",
|
|
774
|
+
vomiting: "Vomiting",
|
|
775
|
+
haematemesis: "Haematemesis"
|
|
776
|
+
};
|
|
777
|
+
var BREAST_OPT_LABELS = {
|
|
778
|
+
pain: "Pain",
|
|
779
|
+
fh_ca_breast: "Family history of Ca breast"
|
|
780
|
+
};
|
|
781
|
+
var ANO_OPT_LABELS = {
|
|
782
|
+
pain_defecation: "Pain during defecation",
|
|
783
|
+
bleeding: "Bleeding",
|
|
784
|
+
constipation: "Constipation",
|
|
785
|
+
discharge: "Discharge"
|
|
786
|
+
};
|
|
787
|
+
var THYROID_OPT_LABELS = {
|
|
788
|
+
dysphagia: "Dysphagia",
|
|
789
|
+
voice_change: "Voice change",
|
|
790
|
+
thyrotoxicosis: "Thyrotoxicosis symptoms"
|
|
791
|
+
};
|
|
792
|
+
var SOCRATES_LABELS = {
|
|
793
|
+
site: "Site",
|
|
794
|
+
onset: "Onset",
|
|
795
|
+
character: "Character",
|
|
796
|
+
radiation: "Radiation",
|
|
797
|
+
associated: "Associated",
|
|
798
|
+
timing: "Timing",
|
|
799
|
+
exacerbating: "Exacerbating / relieving"
|
|
800
|
+
};
|
|
801
|
+
var GENERAL_EXAM_LABELS = {
|
|
802
|
+
pallor: "Pallor",
|
|
803
|
+
icterus: "Icterus",
|
|
804
|
+
cyanosis: "Cyanosis",
|
|
805
|
+
clubbing: "Clubbing",
|
|
806
|
+
lymphadenopathy: "Lymphadenopathy",
|
|
807
|
+
oedema: "Oedema"
|
|
808
|
+
};
|
|
809
|
+
var REGION_EXAM_LABELS = {
|
|
810
|
+
abdomen: "Abdomen",
|
|
811
|
+
hernia: "Hernia",
|
|
812
|
+
breast: "Breast",
|
|
813
|
+
thyroid: "Thyroid",
|
|
814
|
+
anorectal: "Anorectal",
|
|
815
|
+
limb: "Limb / varicose"
|
|
816
|
+
};
|
|
817
|
+
var ABD_INSP_LABELS = {
|
|
818
|
+
distension: "Distension",
|
|
819
|
+
scars: "Scars",
|
|
820
|
+
visible_peristalsis: "Visible peristalsis"
|
|
821
|
+
};
|
|
822
|
+
var ABD_PALP_LABELS = {
|
|
823
|
+
tenderness: "Tenderness",
|
|
824
|
+
guarding: "Guarding",
|
|
825
|
+
rigidity: "Rigidity",
|
|
826
|
+
mass: "Palpable mass"
|
|
827
|
+
};
|
|
828
|
+
var ABD_PERC_LABELS = {
|
|
829
|
+
tympany: "Tympany",
|
|
830
|
+
shifting_dullness: "Shifting dullness"
|
|
831
|
+
};
|
|
832
|
+
function trimLine(s) {
|
|
833
|
+
return s.replace(/\s+/g, " ").trim();
|
|
834
|
+
}
|
|
835
|
+
var SK_ORDER = ["site", "onset", "character", "radiation", "associated", "timing", "exacerbating"];
|
|
836
|
+
function formatGeneralSurgerySmartHistoryToNarrative(v, chips) {
|
|
837
|
+
const blocks = [];
|
|
838
|
+
const showPain = chips.includes("pain");
|
|
839
|
+
const showSwelling = chips.includes("swelling_lump");
|
|
840
|
+
const showGI = chips.includes("bleeding") || chips.includes("obstruction");
|
|
841
|
+
const showBreast = chips.includes("breast");
|
|
842
|
+
const showAno = chips.includes("anorectal");
|
|
843
|
+
const showThyroid = chips.includes("thyroid");
|
|
844
|
+
if (showPain) {
|
|
845
|
+
const painLines = [];
|
|
846
|
+
for (const key of SK_ORDER) {
|
|
847
|
+
const raw = v.pain[key];
|
|
848
|
+
if (typeof raw === "string" && raw.trim()) {
|
|
849
|
+
painLines.push(`${SOCRATES_LABELS[key]}: ${trimLine(raw)}`);
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
if (v.pain.severity > 0) {
|
|
853
|
+
painLines.push(`Severity (0\u201310): ${v.pain.severity}`);
|
|
854
|
+
}
|
|
855
|
+
if (painLines.length > 0) {
|
|
856
|
+
blocks.push(["SOCRATES \u2014 pain", ...painLines.map((l) => `\u2022 ${l}`)].join("\n"));
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
if (showSwelling) {
|
|
860
|
+
const parts = [];
|
|
861
|
+
if (v.swelling.duration.trim()) parts.push(`Duration: ${trimLine(v.swelling.duration)}`);
|
|
862
|
+
if (v.swelling.sizeProgression.trim())
|
|
863
|
+
parts.push(`Size progression: ${trimLine(v.swelling.sizeProgression)}`);
|
|
864
|
+
if (v.swelling.painfulPainless.trim())
|
|
865
|
+
parts.push(`Painful / painless: ${trimLine(v.swelling.painfulPainless)}`);
|
|
866
|
+
for (const c of v.swelling.checks) {
|
|
867
|
+
const lb = SWELLING_OPT_LABELS[c] ?? c;
|
|
868
|
+
parts.push(lb);
|
|
869
|
+
}
|
|
870
|
+
if (parts.length > 0) {
|
|
871
|
+
blocks.push(["Swelling history", ...parts.map((p) => `\u2022 ${p}`)].join("\n"));
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
if (showGI) {
|
|
875
|
+
const parts = [];
|
|
876
|
+
if (v.gi.appetite.trim()) parts.push(`Appetite: ${trimLine(v.gi.appetite)}`);
|
|
877
|
+
if (v.gi.weightLoss.trim()) parts.push(`Weight loss: ${trimLine(v.gi.weightLoss)}`);
|
|
878
|
+
if (v.gi.bowelHabits.trim()) parts.push(`Bowel habits: ${trimLine(v.gi.bowelHabits)}`);
|
|
879
|
+
for (const c of v.gi.checks) {
|
|
880
|
+
parts.push(GI_OPT_LABELS[c] ?? c);
|
|
881
|
+
}
|
|
882
|
+
if (parts.length > 0) {
|
|
883
|
+
blocks.push(["GI history", ...parts.map((p) => `\u2022 ${p}`)].join("\n"));
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
if (showBreast) {
|
|
887
|
+
const parts = [];
|
|
888
|
+
if (v.breast.lumpDuration.trim()) parts.push(`Lump duration: ${trimLine(v.breast.lumpDuration)}`);
|
|
889
|
+
if (v.breast.nippleDischarge.trim())
|
|
890
|
+
parts.push(`Nipple discharge: ${trimLine(v.breast.nippleDischarge)}`);
|
|
891
|
+
for (const c of v.breast.checks) {
|
|
892
|
+
parts.push(BREAST_OPT_LABELS[c] ?? c);
|
|
893
|
+
}
|
|
894
|
+
if (parts.length > 0) {
|
|
895
|
+
blocks.push(["Breast history", ...parts.map((p) => `\u2022 ${p}`)].join("\n"));
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
if (showAno) {
|
|
899
|
+
const parts = [];
|
|
900
|
+
for (const c of v.ano.checks) {
|
|
901
|
+
parts.push(ANO_OPT_LABELS[c] ?? c);
|
|
902
|
+
}
|
|
903
|
+
if (parts.length > 0) {
|
|
904
|
+
blocks.push(["Anorectal history", ...parts.map((p) => `\u2022 ${p}`)].join("\n"));
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
if (showThyroid) {
|
|
908
|
+
const parts = [];
|
|
909
|
+
if (v.thyroid.swellingDuration.trim())
|
|
910
|
+
parts.push(`Swelling duration: ${trimLine(v.thyroid.swellingDuration)}`);
|
|
911
|
+
for (const c of v.thyroid.checks) {
|
|
912
|
+
parts.push(THYROID_OPT_LABELS[c] ?? c);
|
|
913
|
+
}
|
|
914
|
+
if (parts.length > 0) {
|
|
915
|
+
blocks.push(["Thyroid history", ...parts.map((p) => `\u2022 ${p}`)].join("\n"));
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
return blocks.join("\n\n");
|
|
919
|
+
}
|
|
920
|
+
var BOWEL_SOUND_LABELS = {
|
|
921
|
+
none: "\u2014",
|
|
922
|
+
normal: "Normal",
|
|
923
|
+
up: "Increased (\u2191)",
|
|
924
|
+
down: "Decreased (\u2193)",
|
|
925
|
+
absent: "Absent"
|
|
926
|
+
};
|
|
927
|
+
function formatGeneralSurgeryExaminationToNarrative(v) {
|
|
928
|
+
const blocks = [];
|
|
929
|
+
const generalPositive = v.general.map((k) => GENERAL_EXAM_LABELS[k] ?? k).filter(Boolean);
|
|
930
|
+
if (generalPositive.length > 0) {
|
|
931
|
+
blocks.push(
|
|
932
|
+
["General examination", ...generalPositive.map((g) => `\u2022 ${g}`)].join("\n")
|
|
933
|
+
);
|
|
934
|
+
}
|
|
935
|
+
if (v.regions.length > 0) {
|
|
936
|
+
const names = v.regions.map((r) => REGION_EXAM_LABELS[r] ?? r);
|
|
937
|
+
blocks.push(`Regional examination: ${names.join(", ")}`);
|
|
938
|
+
}
|
|
939
|
+
if (v.regions.includes("abdomen")) {
|
|
940
|
+
const sub = [];
|
|
941
|
+
const ins = v.abdomen.inspection.map((x) => ABD_INSP_LABELS[x] ?? x);
|
|
942
|
+
const pal = v.abdomen.palpation.map((x) => ABD_PALP_LABELS[x] ?? x);
|
|
943
|
+
const per = v.abdomen.percussion.map((x) => ABD_PERC_LABELS[x] ?? x);
|
|
944
|
+
if (ins.length) sub.push(`Inspection: ${ins.join(", ")}`);
|
|
945
|
+
if (pal.length) sub.push(`Palpation: ${pal.join(", ")}`);
|
|
946
|
+
if (v.abdomen.massNotes.trim()) sub.push(`Mass / mobility: ${trimLine(v.abdomen.massNotes)}`);
|
|
947
|
+
if (per.length) sub.push(`Percussion: ${per.join(", ")}`);
|
|
948
|
+
const bs = BOWEL_SOUND_LABELS[v.abdomen.bowelSounds];
|
|
949
|
+
if (v.abdomen.bowelSounds !== "none") {
|
|
950
|
+
sub.push(`Bowel sounds: ${bs}`);
|
|
951
|
+
}
|
|
952
|
+
if (sub.length > 0) {
|
|
953
|
+
blocks.push(["Abdomen", ...sub.map((s) => `\u2022 ${s}`)].join("\n"));
|
|
954
|
+
}
|
|
955
|
+
}
|
|
956
|
+
if (v.regions.includes("hernia")) {
|
|
957
|
+
const sub = [];
|
|
958
|
+
if (v.hernia.site.trim()) sub.push(`Site: ${trimLine(v.hernia.site)}`);
|
|
959
|
+
if (v.hernia.reducible) sub.push("Reducible");
|
|
960
|
+
if (v.hernia.coughImpulse) sub.push("Cough impulse positive");
|
|
961
|
+
if (v.hernia.tenderness) sub.push("Tenderness");
|
|
962
|
+
if (sub.length > 0) {
|
|
963
|
+
blocks.push(["Hernia", ...sub.map((s) => `\u2022 ${s}`)].join("\n"));
|
|
964
|
+
}
|
|
965
|
+
}
|
|
966
|
+
if (v.regions.includes("breast")) {
|
|
967
|
+
const sub = [];
|
|
968
|
+
const appendSide = (label, s) => {
|
|
969
|
+
const lines = [];
|
|
970
|
+
if (s.size.trim()) lines.push(`Size: ${trimLine(s.size)}`);
|
|
971
|
+
if (s.quadrant.trim()) lines.push(`Quadrant: ${trimLine(s.quadrant)}`);
|
|
972
|
+
if (s.tenderness.trim()) lines.push(`Tenderness: ${trimLine(s.tenderness)}`);
|
|
973
|
+
if (s.fixity.trim()) lines.push(`Fixity: ${trimLine(s.fixity)}`);
|
|
974
|
+
if (s.skinInvolvement.trim()) lines.push(`Skin involvement: ${trimLine(s.skinInvolvement)}`);
|
|
975
|
+
if (s.consistency.trim()) lines.push(`Consistency: ${trimLine(s.consistency)}`);
|
|
976
|
+
if (s.axillaryNodes) lines.push("Axillary nodes");
|
|
977
|
+
if (s.nippleAreolarComplex) lines.push("Nipple-areolar complex");
|
|
978
|
+
if (lines.length > 0) {
|
|
979
|
+
sub.push(`${label}: ${lines.join("; ")}`);
|
|
980
|
+
}
|
|
981
|
+
};
|
|
982
|
+
appendSide("Left breast", v.breast.left);
|
|
983
|
+
appendSide("Right breast", v.breast.right);
|
|
984
|
+
if (sub.length > 0) {
|
|
985
|
+
blocks.push(["Breast", ...sub.map((s) => `\u2022 ${s}`)].join("\n"));
|
|
986
|
+
}
|
|
987
|
+
}
|
|
988
|
+
if (v.regions.includes("thyroid")) {
|
|
989
|
+
const sub = [];
|
|
990
|
+
if (v.thyroid.size.trim()) sub.push(`Size: ${trimLine(v.thyroid.size)}`);
|
|
991
|
+
if (v.thyroid.mobileDeglutition) sub.push("Mobile with deglutition");
|
|
992
|
+
if (v.thyroid.nodules) sub.push("Nodules");
|
|
993
|
+
if (v.thyroid.cervicalNodes) sub.push("Cervical lymph nodes");
|
|
994
|
+
if (sub.length > 0) {
|
|
995
|
+
blocks.push(["Thyroid", ...sub.map((s) => `\u2022 ${s}`)].join("\n"));
|
|
996
|
+
}
|
|
997
|
+
}
|
|
998
|
+
if (v.regions.includes("anorectal")) {
|
|
999
|
+
const sub = [];
|
|
1000
|
+
if (v.anorectal.inspection.trim())
|
|
1001
|
+
sub.push(`Inspection: ${trimLine(v.anorectal.inspection)}`);
|
|
1002
|
+
if (v.anorectal.dreDone) sub.push("DRE done");
|
|
1003
|
+
if (v.anorectal.proctoscopyDone) sub.push("Proctoscopy done");
|
|
1004
|
+
if (v.anorectal.notes.trim()) sub.push(`DRE / proctoscopy notes: ${trimLine(v.anorectal.notes)}`);
|
|
1005
|
+
if (sub.length > 0) {
|
|
1006
|
+
blocks.push(["Anorectal", ...sub.map((s) => `\u2022 ${s}`)].join("\n"));
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
if (v.regions.includes("limb")) {
|
|
1010
|
+
const sub = [];
|
|
1011
|
+
if (v.limb.dilatedVeins) sub.push("Dilated veins");
|
|
1012
|
+
if (v.limb.ulcer) sub.push("Ulcer");
|
|
1013
|
+
if (v.limb.oedema) sub.push("Oedema");
|
|
1014
|
+
if (sub.length > 0) {
|
|
1015
|
+
blocks.push(["Limb / varicose", ...sub.map((s) => `\u2022 ${s}`)].join("\n"));
|
|
1016
|
+
}
|
|
1017
|
+
}
|
|
1018
|
+
return blocks.join("\n\n");
|
|
1019
|
+
}
|
|
1020
|
+
|
|
1021
|
+
// src/core/urologyPathway.ts
|
|
1022
|
+
var defaultUrologySmartHistory = () => ({
|
|
1023
|
+
socrates: {
|
|
1024
|
+
site: "",
|
|
1025
|
+
onset: "",
|
|
1026
|
+
character: "",
|
|
1027
|
+
radiation: "",
|
|
1028
|
+
associated: "",
|
|
1029
|
+
timing: "",
|
|
1030
|
+
exacerbating: "",
|
|
1031
|
+
severity: 0
|
|
1032
|
+
},
|
|
1033
|
+
ipss: {
|
|
1034
|
+
incomplete: 0,
|
|
1035
|
+
frequency: 0,
|
|
1036
|
+
intermittency: 0,
|
|
1037
|
+
urgency: 0,
|
|
1038
|
+
weakStream: 0,
|
|
1039
|
+
straining: 0,
|
|
1040
|
+
nocturia: 0
|
|
1041
|
+
},
|
|
1042
|
+
ipssQoL: 0,
|
|
1043
|
+
haematuria: { present: false, timing: "", painful: false, clots: false },
|
|
1044
|
+
sexual: { erectile: "", libido: "", ejaculation: "", infertilityMonths: 0 },
|
|
1045
|
+
pastNotes: ""
|
|
1046
|
+
});
|
|
1047
|
+
var defaultUrologyExamination = () => ({
|
|
1048
|
+
regions: [],
|
|
1049
|
+
general: { pallor: false, oedema: false, icterus: false, lymphadenopathy: false },
|
|
1050
|
+
abdomen: {
|
|
1051
|
+
distension: false,
|
|
1052
|
+
scars: false,
|
|
1053
|
+
mass: false,
|
|
1054
|
+
kidneyPalpable: false,
|
|
1055
|
+
bladderPalpable: false,
|
|
1056
|
+
renalAngleTender: false,
|
|
1057
|
+
bladderDull: false
|
|
1058
|
+
},
|
|
1059
|
+
gu: {
|
|
1060
|
+
meatusAbnormal: false,
|
|
1061
|
+
phimosis: false,
|
|
1062
|
+
lesions: false,
|
|
1063
|
+
scrotalSwelling: false,
|
|
1064
|
+
transilluminant: false,
|
|
1065
|
+
tenderTestis: false,
|
|
1066
|
+
hydrocele: false,
|
|
1067
|
+
varicocele: false,
|
|
1068
|
+
suspiciousMass: false
|
|
1069
|
+
},
|
|
1070
|
+
dre: { done: false, sizeGrams: 0, consistency: "", medianSulcus: "", tenderness: false },
|
|
1071
|
+
examinationNotes: ""
|
|
1072
|
+
});
|
|
1073
|
+
function clampInt(n, lo, hi) {
|
|
1074
|
+
if (!Number.isFinite(n)) return lo;
|
|
1075
|
+
return Math.min(hi, Math.max(lo, Math.round(n)));
|
|
1076
|
+
}
|
|
1077
|
+
var SOCRATES_KEYS = [
|
|
1078
|
+
"site",
|
|
1079
|
+
"onset",
|
|
1080
|
+
"character",
|
|
1081
|
+
"radiation",
|
|
1082
|
+
"associated",
|
|
1083
|
+
"timing",
|
|
1084
|
+
"exacerbating"
|
|
1085
|
+
];
|
|
1086
|
+
function urologyIpssSevenTotal(ipss) {
|
|
1087
|
+
return ipss.incomplete + ipss.frequency + ipss.intermittency + ipss.urgency + ipss.weakStream + ipss.straining + ipss.nocturia;
|
|
1088
|
+
}
|
|
1089
|
+
function urologyIpssBand(total) {
|
|
1090
|
+
if (total <= 7) return "Mild";
|
|
1091
|
+
if (total <= 19) return "Moderate";
|
|
1092
|
+
return "Severe";
|
|
1093
|
+
}
|
|
1094
|
+
function normalizeUrologySmartHistory(raw) {
|
|
1095
|
+
const d = defaultUrologySmartHistory();
|
|
1096
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return d;
|
|
1097
|
+
const v = raw;
|
|
1098
|
+
const socIn = v.socrates && typeof v.socrates === "object" ? v.socrates : {};
|
|
1099
|
+
const socrates = { ...d.socrates };
|
|
1100
|
+
for (const k of SOCRATES_KEYS) {
|
|
1101
|
+
const x = socIn[k];
|
|
1102
|
+
socrates[k] = typeof x === "string" ? x : "";
|
|
1103
|
+
}
|
|
1104
|
+
const sev = Number(socIn.severity);
|
|
1105
|
+
socrates.severity = clampInt(Number.isFinite(sev) ? sev : d.socrates.severity, 0, 10);
|
|
1106
|
+
const ipIn = v.ipss && typeof v.ipss === "object" ? v.ipss : {};
|
|
1107
|
+
const ipss = { ...d.ipss };
|
|
1108
|
+
for (const k of [
|
|
1109
|
+
"incomplete",
|
|
1110
|
+
"frequency",
|
|
1111
|
+
"intermittency",
|
|
1112
|
+
"urgency",
|
|
1113
|
+
"weakStream",
|
|
1114
|
+
"straining",
|
|
1115
|
+
"nocturia"
|
|
1116
|
+
]) {
|
|
1117
|
+
const n = Number(ipIn[k]);
|
|
1118
|
+
ipss[k] = clampInt(Number.isFinite(n) ? n : 0, 0, 5);
|
|
1119
|
+
}
|
|
1120
|
+
const qol = Number(v.ipssQoL);
|
|
1121
|
+
const ipssQoL = clampInt(Number.isFinite(qol) ? qol : d.ipssQoL, 0, 6);
|
|
1122
|
+
const haIn = v.haematuria && typeof v.haematuria === "object" ? v.haematuria : {};
|
|
1123
|
+
const timingRaw = haIn.timing;
|
|
1124
|
+
const haematuria = {
|
|
1125
|
+
present: haIn.present === true,
|
|
1126
|
+
timing: typeof timingRaw === "string" && timingRaw !== "none" && timingRaw.length > 0 ? timingRaw : "",
|
|
1127
|
+
painful: haIn.painful === true,
|
|
1128
|
+
clots: haIn.clots === true
|
|
1129
|
+
};
|
|
1130
|
+
const sxIn = v.sexual && typeof v.sexual === "object" ? v.sexual : {};
|
|
1131
|
+
const str2 = (x) => typeof x === "string" && x.length > 0 && x !== "none" ? x : "";
|
|
1132
|
+
const inf = Number(sxIn.infertilityMonths);
|
|
1133
|
+
const sexual = {
|
|
1134
|
+
erectile: str2(sxIn.erectile),
|
|
1135
|
+
libido: str2(sxIn.libido),
|
|
1136
|
+
ejaculation: str2(sxIn.ejaculation),
|
|
1137
|
+
infertilityMonths: Number.isFinite(inf) && inf >= 0 ? Math.round(inf) : 0
|
|
1138
|
+
};
|
|
1139
|
+
const pastNotes = typeof v.pastNotes === "string" ? v.pastNotes : d.pastNotes;
|
|
1140
|
+
return { socrates, ipss, ipssQoL, haematuria, sexual, pastNotes };
|
|
1141
|
+
}
|
|
1142
|
+
function normalizeUrologyExamination(raw) {
|
|
1143
|
+
const d = defaultUrologyExamination();
|
|
1144
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return d;
|
|
1145
|
+
const v = raw;
|
|
1146
|
+
const strArr = (x) => Array.isArray(x) ? x.filter((i) => typeof i === "string") : [];
|
|
1147
|
+
const bool = (x) => x === true;
|
|
1148
|
+
const g = v.general && typeof v.general === "object" ? v.general : {};
|
|
1149
|
+
const ab = v.abdomen && typeof v.abdomen === "object" ? v.abdomen : {};
|
|
1150
|
+
const gu = v.gu && typeof v.gu === "object" ? v.gu : {};
|
|
1151
|
+
const dr = v.dre && typeof v.dre === "object" ? v.dre : {};
|
|
1152
|
+
const sg = Number(dr.sizeGrams);
|
|
1153
|
+
const consistencyRaw = dr.consistency;
|
|
1154
|
+
const medianRaw = dr.medianSulcus;
|
|
1155
|
+
const dreEmpty = (x) => !(typeof x === "string" && x.length > 0 && x !== "none");
|
|
1156
|
+
return {
|
|
1157
|
+
regions: strArr(v.regions),
|
|
1158
|
+
general: {
|
|
1159
|
+
pallor: bool(g.pallor),
|
|
1160
|
+
oedema: bool(g.oedema),
|
|
1161
|
+
icterus: bool(g.icterus),
|
|
1162
|
+
lymphadenopathy: bool(g.lymphadenopathy)
|
|
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
|
|
1192
|
+
};
|
|
1193
|
+
}
|
|
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
|
+
function normalizeUrologyPathway(raw) {
|
|
1213
|
+
const d = defaultUrologyPathway();
|
|
1214
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return d;
|
|
1215
|
+
const v = raw;
|
|
1216
|
+
const rIn = v.risk && typeof v.risk === "object" && !Array.isArray(v.risk) ? v.risk : {};
|
|
1217
|
+
return {
|
|
1218
|
+
stoneSizeMm: clampNonNegativeNumber(v.stoneSizeMm, d.stoneSizeMm),
|
|
1219
|
+
hydronephrosis: v.hydronephrosis === true,
|
|
1220
|
+
prostateVolumeCc: clampNonNegativeNumber(v.prostateVolumeCc, d.prostateVolumeCc),
|
|
1221
|
+
psaNgMl: clampNonNegativeNumber(v.psaNgMl, d.psaNgMl),
|
|
1222
|
+
uroflowQmaxMlSec: clampNonNegativeNumber(v.uroflowQmaxMlSec, d.uroflowQmaxMlSec),
|
|
1223
|
+
risk: {
|
|
1224
|
+
ckd: rIn.ckd === true,
|
|
1225
|
+
diabetes: rIn.diabetes === true,
|
|
1226
|
+
anticoagulants: rIn.anticoagulants === true,
|
|
1227
|
+
activeInfection: rIn.activeInfection === true
|
|
1228
|
+
}
|
|
1229
|
+
};
|
|
1230
|
+
}
|
|
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
|
+
}
|
|
415
1247
|
|
|
416
1248
|
// src/core/painScaleFlags.ts
|
|
417
1249
|
function normalizePainScaleFlags(raw, bounds) {
|
|
@@ -531,6 +1363,12 @@ var FormStore = class {
|
|
|
531
1363
|
f.defaultValue ?? { pain: f.min ?? 0, flags: [] },
|
|
532
1364
|
{ min: f.min, max: f.max }
|
|
533
1365
|
);
|
|
1366
|
+
} else if (field.type === "urology_smart_history") {
|
|
1367
|
+
values[field.id] = field.defaultValue ?? defaultUrologySmartHistory();
|
|
1368
|
+
} else if (field.type === "urology_examination") {
|
|
1369
|
+
values[field.id] = field.defaultValue ?? defaultUrologyExamination();
|
|
1370
|
+
} else if (field.type === "urology_pathway") {
|
|
1371
|
+
values[field.id] = field.defaultValue ?? defaultUrologyPathway();
|
|
534
1372
|
} else values[field.id] = null;
|
|
535
1373
|
}
|
|
536
1374
|
});
|
|
@@ -740,6 +1578,7 @@ var FormStore = class {
|
|
|
740
1578
|
}
|
|
741
1579
|
}
|
|
742
1580
|
});
|
|
1581
|
+
attachUrologyClinicalPathwayMetadata(result, this.schema);
|
|
743
1582
|
return result;
|
|
744
1583
|
}
|
|
745
1584
|
// --- Core Logic ---
|
|
@@ -5712,7 +6551,7 @@ function safeJsonParse(val) {
|
|
|
5712
6551
|
return null;
|
|
5713
6552
|
}
|
|
5714
6553
|
}
|
|
5715
|
-
function
|
|
6554
|
+
function clampInt2(val, min, max) {
|
|
5716
6555
|
if (!Number.isFinite(val)) return min;
|
|
5717
6556
|
return Math.max(min, Math.min(max, Math.trunc(val)));
|
|
5718
6557
|
}
|
|
@@ -5722,10 +6561,10 @@ function parseLegacyString(input) {
|
|
|
5722
6561
|
if (gpalMatch) {
|
|
5723
6562
|
const [, g, p, a, l] = gpalMatch;
|
|
5724
6563
|
result.gpal = {
|
|
5725
|
-
G:
|
|
5726
|
-
P:
|
|
5727
|
-
A:
|
|
5728
|
-
L:
|
|
6564
|
+
G: clampInt2(Number(g), 0, 20),
|
|
6565
|
+
P: clampInt2(Number(p), 0, 20),
|
|
6566
|
+
A: clampInt2(Number(a), 0, 20),
|
|
6567
|
+
L: clampInt2(Number(l), 0, 20)
|
|
5729
6568
|
};
|
|
5730
6569
|
}
|
|
5731
6570
|
const lmpMatch = input.match(/LMP:\s*([^\n]+)/i);
|
|
@@ -5758,10 +6597,10 @@ function normalizeToDraft(value) {
|
|
|
5758
6597
|
isNewEntry: false,
|
|
5759
6598
|
draft: {
|
|
5760
6599
|
gpal: {
|
|
5761
|
-
G:
|
|
5762
|
-
P:
|
|
5763
|
-
A:
|
|
5764
|
-
L:
|
|
6600
|
+
G: clampInt2(Number(gpal.G ?? 0), 0, 20),
|
|
6601
|
+
P: clampInt2(Number(gpal.P ?? 0), 0, 20),
|
|
6602
|
+
A: clampInt2(Number(gpal.A ?? 0), 0, 20),
|
|
6603
|
+
L: clampInt2(Number(gpal.L ?? 0), 0, 20)
|
|
5765
6604
|
},
|
|
5766
6605
|
lmp: typeof lmp === "string" ? lmp : "",
|
|
5767
6606
|
is_pregnant,
|
|
@@ -5779,10 +6618,10 @@ function normalizeToDraft(value) {
|
|
|
5779
6618
|
}
|
|
5780
6619
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
5781
6620
|
const gpalFromFlat = {
|
|
5782
|
-
G:
|
|
5783
|
-
P:
|
|
5784
|
-
A:
|
|
5785
|
-
L:
|
|
6621
|
+
G: clampInt2(Number(parsed.G ?? parsed.g ?? 0), 0, 20),
|
|
6622
|
+
P: clampInt2(Number(parsed.P ?? parsed.p ?? 0), 0, 20),
|
|
6623
|
+
A: clampInt2(Number(parsed.A ?? parsed.a ?? 0), 0, 20),
|
|
6624
|
+
L: clampInt2(Number(parsed.L ?? parsed.l ?? 0), 0, 20)
|
|
5786
6625
|
};
|
|
5787
6626
|
return {
|
|
5788
6627
|
isNewEntry: false,
|
|
@@ -5934,7 +6773,7 @@ var ObstetricHistoryWidget = ({ fieldId }) => {
|
|
|
5934
6773
|
const sanitizeGpalInput = (raw) => {
|
|
5935
6774
|
const digits = raw.replace(/[^\d]/g, "").slice(0, 2);
|
|
5936
6775
|
if (!digits) return 0;
|
|
5937
|
-
return
|
|
6776
|
+
return clampInt2(Number(digits), 0, 20);
|
|
5938
6777
|
};
|
|
5939
6778
|
const handleGpalChange = (key, raw) => {
|
|
5940
6779
|
const prevWasEmpty = draft.gpal[key] === 0 && activeGpalKey === key;
|
|
@@ -6634,7 +7473,11 @@ var OphthalmologyWidget = ({ fieldId }) => {
|
|
|
6634
7473
|
] })
|
|
6635
7474
|
] }),
|
|
6636
7475
|
/* @__PURE__ */ jsx("tbody", { children: /* @__PURE__ */ jsxs("tr", { children: [
|
|
6637
|
-
/* @__PURE__ */ jsx("td", { className: refractionLabelCellClass
|
|
7476
|
+
/* @__PURE__ */ jsx("td", { className: `${refractionLabelCellClass} whitespace-normal`, children: /* @__PURE__ */ jsxs("span", { className: "block leading-tight", children: [
|
|
7477
|
+
"Current",
|
|
7478
|
+
/* @__PURE__ */ jsx("br", {}),
|
|
7479
|
+
"Glass"
|
|
7480
|
+
] }) }),
|
|
6638
7481
|
/* @__PURE__ */ jsx("td", { className: refractionDataCellClass, children: /* @__PURE__ */ jsx(
|
|
6639
7482
|
Input,
|
|
6640
7483
|
{
|
|
@@ -6889,12 +7732,12 @@ var OphthalmologyWidget = ({ fieldId }) => {
|
|
|
6889
7732
|
/* @__PURE__ */ jsx("th", { className: refractionHeaderCellClass, children: "Sph" }),
|
|
6890
7733
|
/* @__PURE__ */ jsx("th", { className: refractionHeaderCellClass, children: "Cyl" }),
|
|
6891
7734
|
/* @__PURE__ */ jsx("th", { className: refractionHeaderCellClass, children: "Axis" }),
|
|
6892
|
-
/* @__PURE__ */ jsx("th", { className: refractionHeaderCellClass, children: "
|
|
7735
|
+
/* @__PURE__ */ jsx("th", { className: refractionHeaderCellClass, children: "BCVA" }),
|
|
6893
7736
|
/* @__PURE__ */ jsx("th", { className: refractionHeaderCellClass, children: "P/D" }),
|
|
6894
7737
|
/* @__PURE__ */ jsx("th", { className: refractionHeaderCellClass, children: "Sph" }),
|
|
6895
7738
|
/* @__PURE__ */ jsx("th", { className: refractionHeaderCellClass, children: "Cyl" }),
|
|
6896
7739
|
/* @__PURE__ */ jsx("th", { className: refractionHeaderCellClass, children: "Axis" }),
|
|
6897
|
-
/* @__PURE__ */ jsx("th", { className: refractionHeaderCellClass, children: "
|
|
7740
|
+
/* @__PURE__ */ jsx("th", { className: refractionHeaderCellClass, children: "BCVA" }),
|
|
6898
7741
|
/* @__PURE__ */ jsx("th", { className: refractionHeaderCellClass, children: "P/D" })
|
|
6899
7742
|
] })
|
|
6900
7743
|
] }),
|
|
@@ -9232,6 +10075,7 @@ var SliderWidget = ({ fieldId }) => {
|
|
|
9232
10075
|
] });
|
|
9233
10076
|
};
|
|
9234
10077
|
var CHIEF_CHIPS_FIELD = "chief_complaints_chips";
|
|
10078
|
+
var GS_SYMPTOMS_FIELD = "symptoms";
|
|
9235
10079
|
var SWELLING_OPTS = [
|
|
9236
10080
|
{ value: "reducible_hernia", label: "Reducible (hernia)" },
|
|
9237
10081
|
{ value: "cough_impulse", label: "Cough impulse" },
|
|
@@ -9257,7 +10101,7 @@ var THYROID_OPTS = [
|
|
|
9257
10101
|
{ value: "voice_change", label: "Voice change" },
|
|
9258
10102
|
{ value: "thyrotoxicosis", label: "Thyrotoxicosis symptoms" }
|
|
9259
10103
|
];
|
|
9260
|
-
var
|
|
10104
|
+
var SOCRATES_KEYS2 = [
|
|
9261
10105
|
"site",
|
|
9262
10106
|
"onset",
|
|
9263
10107
|
"character",
|
|
@@ -9272,16 +10116,26 @@ function Panel({ title, children }) {
|
|
|
9272
10116
|
/* @__PURE__ */ jsx("div", { className: "p-3", children })
|
|
9273
10117
|
] });
|
|
9274
10118
|
}
|
|
9275
|
-
function
|
|
9276
|
-
const raw = state.values[CHIEF_CHIPS_FIELD];
|
|
10119
|
+
function chipListFromRaw(raw) {
|
|
9277
10120
|
return Array.isArray(raw) ? raw.filter((x) => typeof x === "string") : [];
|
|
9278
10121
|
}
|
|
9279
10122
|
var GsSmartHistoryWidget = ({ fieldId }) => {
|
|
9280
10123
|
const { fieldDef, value, setValue, setTouched, error, touched, disabled } = useField(fieldId);
|
|
10124
|
+
const hopcField = useField(GS_SYMPTOMS_FIELD);
|
|
9281
10125
|
const { state } = useForm();
|
|
9282
10126
|
const showError = !!error && (touched || state.submitAttempted);
|
|
9283
10127
|
const safe = useMemo(() => normalizeGeneralSurgerySmartHistory(value), [value]);
|
|
9284
|
-
const
|
|
10128
|
+
const chiefChipsRaw = state.values[CHIEF_CHIPS_FIELD];
|
|
10129
|
+
const chips = useMemo(() => chipListFromRaw(chiefChipsRaw), [chiefChipsRaw]);
|
|
10130
|
+
const [hopcNarrativeLocked, setHopcNarrativeLocked] = useState(false);
|
|
10131
|
+
useEffect(() => {
|
|
10132
|
+
if (hopcNarrativeLocked) return;
|
|
10133
|
+
const next = formatGeneralSurgerySmartHistoryToNarrative(
|
|
10134
|
+
normalizeGeneralSurgerySmartHistory(value),
|
|
10135
|
+
chips
|
|
10136
|
+
);
|
|
10137
|
+
hopcField.setValue(next);
|
|
10138
|
+
}, [value, chips, hopcNarrativeLocked]);
|
|
9285
10139
|
const showPain = chips.includes("pain");
|
|
9286
10140
|
const showSwelling = chips.includes("swelling_lump");
|
|
9287
10141
|
const showGI = chips.includes("bleeding") || chips.includes("obstruction");
|
|
@@ -9341,7 +10195,7 @@ var GsSmartHistoryWidget = ({ fieldId }) => {
|
|
|
9341
10195
|
labelEl,
|
|
9342
10196
|
/* @__PURE__ */ jsxs("div", { className: bodyClass, children: [
|
|
9343
10197
|
showPain ? /* @__PURE__ */ jsx(Panel, { title: "SOCRATES \u2014 pain", children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-2 md:grid-cols-4", children: [
|
|
9344
|
-
|
|
10198
|
+
SOCRATES_KEYS2.map((k) => /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
|
|
9345
10199
|
/* @__PURE__ */ jsx("span", { className: "text-[10px] font-medium uppercase tracking-wide text-muted-foreground", children: k }),
|
|
9346
10200
|
/* @__PURE__ */ jsx(
|
|
9347
10201
|
Input,
|
|
@@ -9547,15 +10401,51 @@ var GsSmartHistoryWidget = ({ fieldId }) => {
|
|
|
9547
10401
|
] }, o.value)) })
|
|
9548
10402
|
] }) : null,
|
|
9549
10403
|
/* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
|
|
9550
|
-
/* @__PURE__ */
|
|
10404
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2", children: [
|
|
10405
|
+
/* @__PURE__ */ jsx(Label, { className: "text-xs font-semibold text-slate-700", children: hopcField.fieldDef?.label ?? "History of presenting complaint" }),
|
|
10406
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
10407
|
+
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: [
|
|
10408
|
+
"You edited this summary. Use",
|
|
10409
|
+
" ",
|
|
10410
|
+
/* @__PURE__ */ jsx("span", { className: "italic", children: "'Regenerate'" }),
|
|
10411
|
+
" ",
|
|
10412
|
+
"to update it from the form."
|
|
10413
|
+
] }) : null,
|
|
10414
|
+
hopcNarrativeLocked ? /* @__PURE__ */ jsx(
|
|
10415
|
+
Button,
|
|
10416
|
+
{
|
|
10417
|
+
type: "button",
|
|
10418
|
+
variant: "outline",
|
|
10419
|
+
size: "sm",
|
|
10420
|
+
className: "h-7 shrink-0 px-2 text-xs",
|
|
10421
|
+
disabled: disabled || hopcField.disabled,
|
|
10422
|
+
onClick: () => {
|
|
10423
|
+
setHopcNarrativeLocked(false);
|
|
10424
|
+
hopcField.setValue(
|
|
10425
|
+
formatGeneralSurgerySmartHistoryToNarrative(
|
|
10426
|
+
normalizeGeneralSurgerySmartHistory(value),
|
|
10427
|
+
chips
|
|
10428
|
+
)
|
|
10429
|
+
);
|
|
10430
|
+
},
|
|
10431
|
+
children: "Regenerate"
|
|
10432
|
+
}
|
|
10433
|
+
) : null
|
|
10434
|
+
] })
|
|
10435
|
+
] }),
|
|
10436
|
+
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,
|
|
9551
10437
|
/* @__PURE__ */ jsx(
|
|
9552
10438
|
Textarea,
|
|
9553
10439
|
{
|
|
9554
|
-
className: "min-h-[
|
|
9555
|
-
placeholder: "
|
|
9556
|
-
value:
|
|
9557
|
-
onChange: (e) =>
|
|
9558
|
-
|
|
10440
|
+
className: "min-h-[88px] rounded-md border border-input bg-white text-sm",
|
|
10441
|
+
placeholder: "Onset, progression, associated symptoms, relevant negatives\u2026",
|
|
10442
|
+
value: typeof hopcField.value === "string" ? hopcField.value : hopcField.value == null ? "" : String(hopcField.value),
|
|
10443
|
+
onChange: (e) => {
|
|
10444
|
+
setHopcNarrativeLocked(true);
|
|
10445
|
+
hopcField.setValue(e.target.value);
|
|
10446
|
+
hopcField.setTouched();
|
|
10447
|
+
},
|
|
10448
|
+
disabled: disabled || hopcField.disabled
|
|
9559
10449
|
}
|
|
9560
10450
|
)
|
|
9561
10451
|
] })
|
|
@@ -9607,12 +10497,72 @@ function RegionCard({ title, children }) {
|
|
|
9607
10497
|
/* @__PURE__ */ jsx("div", { className: "p-3", children })
|
|
9608
10498
|
] });
|
|
9609
10499
|
}
|
|
10500
|
+
var BREAST_TEXT_KEYS = [
|
|
10501
|
+
{ key: "size", label: "Size" },
|
|
10502
|
+
{ key: "quadrant", label: "Quadrant" },
|
|
10503
|
+
{ key: "tenderness", label: "Tenderness" },
|
|
10504
|
+
{ key: "fixity", label: "Fixity" },
|
|
10505
|
+
{ key: "skinInvolvement", label: "Skin involvement" },
|
|
10506
|
+
{ key: "consistency", label: "Consistency" }
|
|
10507
|
+
];
|
|
10508
|
+
function BreastLumpColumn({
|
|
10509
|
+
title,
|
|
10510
|
+
data,
|
|
10511
|
+
onChange,
|
|
10512
|
+
disabled
|
|
10513
|
+
}) {
|
|
10514
|
+
return /* @__PURE__ */ jsxs("div", { className: "space-y-2 rounded-md border border-[#D0D0D0] bg-slate-50/50 p-3", children: [
|
|
10515
|
+
/* @__PURE__ */ jsx("p", { className: "text-[11px] font-semibold uppercase tracking-wide text-muted-foreground", children: title }),
|
|
10516
|
+
/* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 gap-2 sm:grid-cols-2", children: BREAST_TEXT_KEYS.map(({ key, label }) => /* @__PURE__ */ jsxs("label", { className: "block", children: [
|
|
10517
|
+
/* @__PURE__ */ jsx("span", { className: "mb-1 block font-medium", children: label }),
|
|
10518
|
+
/* @__PURE__ */ jsx(
|
|
10519
|
+
Input,
|
|
10520
|
+
{
|
|
10521
|
+
className: "h-8 text-xs",
|
|
10522
|
+
value: data[key],
|
|
10523
|
+
onChange: (e) => onChange({ [key]: e.target.value }),
|
|
10524
|
+
disabled
|
|
10525
|
+
}
|
|
10526
|
+
)
|
|
10527
|
+
] }, key)) }),
|
|
10528
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-x-4 gap-y-2 pt-1", children: [
|
|
10529
|
+
/* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2", children: [
|
|
10530
|
+
/* @__PURE__ */ jsx(
|
|
10531
|
+
Checkbox,
|
|
10532
|
+
{
|
|
10533
|
+
checked: data.axillaryNodes,
|
|
10534
|
+
onCheckedChange: (c) => onChange({ axillaryNodes: c === true }),
|
|
10535
|
+
disabled
|
|
10536
|
+
}
|
|
10537
|
+
),
|
|
10538
|
+
"Axillary nodes"
|
|
10539
|
+
] }),
|
|
10540
|
+
/* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2", children: [
|
|
10541
|
+
/* @__PURE__ */ jsx(
|
|
10542
|
+
Checkbox,
|
|
10543
|
+
{
|
|
10544
|
+
checked: data.nippleAreolarComplex,
|
|
10545
|
+
onCheckedChange: (c) => onChange({ nippleAreolarComplex: c === true }),
|
|
10546
|
+
disabled
|
|
10547
|
+
}
|
|
10548
|
+
),
|
|
10549
|
+
"Nipple-areolar complex"
|
|
10550
|
+
] })
|
|
10551
|
+
] })
|
|
10552
|
+
] });
|
|
10553
|
+
}
|
|
9610
10554
|
var GsExaminationWidget = ({ fieldId }) => {
|
|
9611
10555
|
const { fieldDef, value, setValue, setTouched, error, touched, disabled } = useField(fieldId);
|
|
9612
10556
|
const clinicalField = useField(GS_CLINICAL_EXAMINATION_FIELD);
|
|
9613
10557
|
const { state } = useForm();
|
|
9614
10558
|
const showError = !!error && (touched || state.submitAttempted);
|
|
9615
10559
|
const safe = useMemo(() => normalizeGeneralSurgeryExamination(value), [value]);
|
|
10560
|
+
const [clinicalNarrativeLocked, setClinicalNarrativeLocked] = useState(false);
|
|
10561
|
+
useEffect(() => {
|
|
10562
|
+
if (clinicalNarrativeLocked) return;
|
|
10563
|
+
const next = formatGeneralSurgeryExaminationToNarrative(normalizeGeneralSurgeryExamination(value));
|
|
10564
|
+
clinicalField.setValue(next);
|
|
10565
|
+
}, [value, clinicalNarrativeLocked]);
|
|
9616
10566
|
const update = (next) => {
|
|
9617
10567
|
setValue(next);
|
|
9618
10568
|
setTouched();
|
|
@@ -9804,56 +10754,35 @@ var GsExaminationWidget = ({ fieldId }) => {
|
|
|
9804
10754
|
"Tenderness"
|
|
9805
10755
|
] })
|
|
9806
10756
|
] }) }) : null,
|
|
9807
|
-
has("breast") ? /* @__PURE__ */ jsx(RegionCard, { title: "Breast exam", children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 gap-
|
|
10757
|
+
has("breast") ? /* @__PURE__ */ jsx(RegionCard, { title: "Breast exam", children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 gap-4 text-xs md:grid-cols-2", children: [
|
|
10758
|
+
/* @__PURE__ */ jsx(
|
|
10759
|
+
BreastLumpColumn,
|
|
10760
|
+
{
|
|
10761
|
+
title: "Left breast",
|
|
10762
|
+
data: safe.breast.left,
|
|
10763
|
+
onChange: (p) => update({
|
|
10764
|
+
...safe,
|
|
10765
|
+
breast: { ...safe.breast, left: { ...safe.breast.left, ...p } }
|
|
10766
|
+
}),
|
|
10767
|
+
disabled
|
|
10768
|
+
}
|
|
10769
|
+
),
|
|
10770
|
+
/* @__PURE__ */ jsx(
|
|
10771
|
+
BreastLumpColumn,
|
|
10772
|
+
{
|
|
10773
|
+
title: "Right breast",
|
|
10774
|
+
data: safe.breast.right,
|
|
10775
|
+
onChange: (p) => update({
|
|
10776
|
+
...safe,
|
|
10777
|
+
breast: { ...safe.breast, right: { ...safe.breast.right, ...p } }
|
|
10778
|
+
}),
|
|
10779
|
+
disabled
|
|
10780
|
+
}
|
|
10781
|
+
)
|
|
10782
|
+
] }) }) : null,
|
|
10783
|
+
has("thyroid") ? /* @__PURE__ */ jsx(RegionCard, { title: "Thyroid exam", children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 gap-3 text-xs md:grid-cols-4", children: [
|
|
9808
10784
|
/* @__PURE__ */ jsxs("label", { className: "block", children: [
|
|
9809
|
-
/* @__PURE__ */ jsx("span", { className: "mb-1 block font-medium", children: "
|
|
9810
|
-
/* @__PURE__ */ jsx(
|
|
9811
|
-
Input,
|
|
9812
|
-
{
|
|
9813
|
-
className: "h-8 text-xs",
|
|
9814
|
-
value: safe.breast.lumpSizeCm,
|
|
9815
|
-
onChange: (e) => update({ ...safe, breast: { ...safe.breast, lumpSizeCm: e.target.value } }),
|
|
9816
|
-
disabled
|
|
9817
|
-
}
|
|
9818
|
-
)
|
|
9819
|
-
] }),
|
|
9820
|
-
/* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2", children: [
|
|
9821
|
-
/* @__PURE__ */ jsx(
|
|
9822
|
-
Checkbox,
|
|
9823
|
-
{
|
|
9824
|
-
checked: safe.breast.mobile,
|
|
9825
|
-
onCheckedChange: (c) => update({ ...safe, breast: { ...safe.breast, mobile: c === true } }),
|
|
9826
|
-
disabled
|
|
9827
|
-
}
|
|
9828
|
-
),
|
|
9829
|
-
"Mobile"
|
|
9830
|
-
] }),
|
|
9831
|
-
/* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2", children: [
|
|
9832
|
-
/* @__PURE__ */ jsx(
|
|
9833
|
-
Checkbox,
|
|
9834
|
-
{
|
|
9835
|
-
checked: safe.breast.skinInvolvement,
|
|
9836
|
-
onCheckedChange: (c) => update({ ...safe, breast: { ...safe.breast, skinInvolvement: c === true } }),
|
|
9837
|
-
disabled
|
|
9838
|
-
}
|
|
9839
|
-
),
|
|
9840
|
-
"Skin involvement"
|
|
9841
|
-
] }),
|
|
9842
|
-
/* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2", children: [
|
|
9843
|
-
/* @__PURE__ */ jsx(
|
|
9844
|
-
Checkbox,
|
|
9845
|
-
{
|
|
9846
|
-
checked: safe.breast.axillaryNodes,
|
|
9847
|
-
onCheckedChange: (c) => update({ ...safe, breast: { ...safe.breast, axillaryNodes: c === true } }),
|
|
9848
|
-
disabled
|
|
9849
|
-
}
|
|
9850
|
-
),
|
|
9851
|
-
"Axillary nodes"
|
|
9852
|
-
] })
|
|
9853
|
-
] }) }) : null,
|
|
9854
|
-
has("thyroid") ? /* @__PURE__ */ jsx(RegionCard, { title: "Thyroid exam", children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 gap-3 text-xs md:grid-cols-4", children: [
|
|
9855
|
-
/* @__PURE__ */ jsxs("label", { className: "block", children: [
|
|
9856
|
-
/* @__PURE__ */ jsx("span", { className: "mb-1 block font-medium", children: "Size" }),
|
|
10785
|
+
/* @__PURE__ */ jsx("span", { className: "mb-1 block font-medium", children: "Size" }),
|
|
9857
10786
|
/* @__PURE__ */ jsx(
|
|
9858
10787
|
Input,
|
|
9859
10788
|
{
|
|
@@ -9984,13 +10913,43 @@ var GsExaminationWidget = ({ fieldId }) => {
|
|
|
9984
10913
|
] }) }) : null
|
|
9985
10914
|
] }),
|
|
9986
10915
|
/* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
|
|
9987
|
-
/* @__PURE__ */
|
|
10916
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2", children: [
|
|
10917
|
+
/* @__PURE__ */ jsx(Label, { className: "text-xs font-semibold text-slate-700", children: clinicalField.fieldDef?.label ?? "Clinical examination" }),
|
|
10918
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
10919
|
+
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: [
|
|
10920
|
+
"You edited this summary. Use",
|
|
10921
|
+
" ",
|
|
10922
|
+
/* @__PURE__ */ jsx("span", { className: "italic", children: "'Regenerate'" }),
|
|
10923
|
+
" ",
|
|
10924
|
+
"to update it from the form."
|
|
10925
|
+
] }) : null,
|
|
10926
|
+
clinicalNarrativeLocked ? /* @__PURE__ */ jsx(
|
|
10927
|
+
Button,
|
|
10928
|
+
{
|
|
10929
|
+
type: "button",
|
|
10930
|
+
variant: "outline",
|
|
10931
|
+
size: "sm",
|
|
10932
|
+
className: "h-7 shrink-0 px-2 text-xs",
|
|
10933
|
+
disabled: disabled || clinicalField.disabled,
|
|
10934
|
+
onClick: () => {
|
|
10935
|
+
setClinicalNarrativeLocked(false);
|
|
10936
|
+
clinicalField.setValue(
|
|
10937
|
+
formatGeneralSurgeryExaminationToNarrative(normalizeGeneralSurgeryExamination(value))
|
|
10938
|
+
);
|
|
10939
|
+
},
|
|
10940
|
+
children: "Regenerate"
|
|
10941
|
+
}
|
|
10942
|
+
) : null
|
|
10943
|
+
] })
|
|
10944
|
+
] }),
|
|
10945
|
+
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,
|
|
9988
10946
|
/* @__PURE__ */ jsx(
|
|
9989
10947
|
Textarea,
|
|
9990
10948
|
{
|
|
9991
10949
|
className: "min-h-[88px] rounded-md border border-input bg-white text-sm",
|
|
9992
10950
|
value: typeof clinicalField.value === "string" ? clinicalField.value : clinicalField.value == null ? "" : String(clinicalField.value),
|
|
9993
10951
|
onChange: (e) => {
|
|
10952
|
+
setClinicalNarrativeLocked(true);
|
|
9994
10953
|
clinicalField.setValue(e.target.value);
|
|
9995
10954
|
clinicalField.setTouched();
|
|
9996
10955
|
},
|
|
@@ -10004,7 +10963,7 @@ var GsExaminationWidget = ({ fieldId }) => {
|
|
|
10004
10963
|
};
|
|
10005
10964
|
var CHIEF_CHIPS_FIELD2 = "chief_complaints_chips";
|
|
10006
10965
|
var GS_EXAMINATION_FIELD = "gs_examination";
|
|
10007
|
-
function
|
|
10966
|
+
function chipList(state) {
|
|
10008
10967
|
const raw = state.values[CHIEF_CHIPS_FIELD2];
|
|
10009
10968
|
return Array.isArray(raw) ? raw.filter((x) => typeof x === "string") : [];
|
|
10010
10969
|
}
|
|
@@ -10018,7 +10977,7 @@ var GsGradingWidget = ({ fieldId }) => {
|
|
|
10018
10977
|
const { state } = useForm();
|
|
10019
10978
|
const showError = !!error && (touched || state.submitAttempted);
|
|
10020
10979
|
const safe = useMemo(() => normalizeGeneralSurgeryGrading(value), [value]);
|
|
10021
|
-
const chips = useMemo(() =>
|
|
10980
|
+
const chips = useMemo(() => chipList(state), [state]);
|
|
10022
10981
|
const regions = useMemo(() => regionList(state), [state]);
|
|
10023
10982
|
const visibleRows = useMemo(() => {
|
|
10024
10983
|
return ALL_GS_CONDITIONS.filter(
|
|
@@ -10173,6 +11132,813 @@ var PainScaleFlagsWidget = ({ fieldId }) => {
|
|
|
10173
11132
|
showError && /* @__PURE__ */ jsx("p", { className: "text-xs text-red-500", children: error })
|
|
10174
11133
|
] });
|
|
10175
11134
|
};
|
|
11135
|
+
var CHIEF_CHIPS_FIELD3 = "chief_complaints_chips";
|
|
11136
|
+
var ACTIVE_SYNDROME_FIELD = "uro_active_syndrome";
|
|
11137
|
+
function chipList2(state) {
|
|
11138
|
+
const raw = state.values[CHIEF_CHIPS_FIELD3];
|
|
11139
|
+
return Array.isArray(raw) ? raw.filter((x) => typeof x === "string") : [];
|
|
11140
|
+
}
|
|
11141
|
+
var IPSS_LABELS = {
|
|
11142
|
+
incomplete: "Incomplete emptying",
|
|
11143
|
+
frequency: "Frequency (<2h)",
|
|
11144
|
+
intermittency: "Intermittency",
|
|
11145
|
+
urgency: "Urgency",
|
|
11146
|
+
weakStream: "Weak stream",
|
|
11147
|
+
straining: "Straining",
|
|
11148
|
+
nocturia: "Nocturia (\xD7/night)"
|
|
11149
|
+
};
|
|
11150
|
+
var SOCRATES_KEYS3 = [
|
|
11151
|
+
"site",
|
|
11152
|
+
"onset",
|
|
11153
|
+
"character",
|
|
11154
|
+
"radiation",
|
|
11155
|
+
"associated",
|
|
11156
|
+
"timing",
|
|
11157
|
+
"exacerbating"
|
|
11158
|
+
];
|
|
11159
|
+
function Panel2({
|
|
11160
|
+
title,
|
|
11161
|
+
right,
|
|
11162
|
+
children
|
|
11163
|
+
}) {
|
|
11164
|
+
return /* @__PURE__ */ jsxs("div", { className: "overflow-hidden rounded-md border border-[#D0D0D0] bg-white", children: [
|
|
11165
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between border-b border-[#D0D0D0] bg-[#FEE8EC]/50 px-3 py-1.5", children: [
|
|
11166
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs font-semibold text-slate-700", children: title }),
|
|
11167
|
+
right
|
|
11168
|
+
] }),
|
|
11169
|
+
/* @__PURE__ */ jsx("div", { className: "p-3", children })
|
|
11170
|
+
] });
|
|
11171
|
+
}
|
|
11172
|
+
var UrologySmartHistoryWidget = ({ fieldId }) => {
|
|
11173
|
+
const { fieldDef, value, setValue, setTouched, error, touched, disabled } = useField(fieldId);
|
|
11174
|
+
const syndromeField = useField(ACTIVE_SYNDROME_FIELD);
|
|
11175
|
+
const { state } = useForm();
|
|
11176
|
+
const showError = !!error && (touched || state.submitAttempted);
|
|
11177
|
+
const safe = useMemo(() => normalizeUrologySmartHistory(value), [value]);
|
|
11178
|
+
const chips = useMemo(() => chipList2(state), [state]);
|
|
11179
|
+
const rawSyndrome = syndromeField.value ?? state.values[ACTIVE_SYNDROME_FIELD];
|
|
11180
|
+
const syndrome = typeof rawSyndrome === "string" && rawSyndrome !== "" && rawSyndrome !== "none" ? rawSyndrome : "none";
|
|
11181
|
+
const showPain = chips.includes("pain_abdomen_flank") || chips.includes("scrotal_swelling_pain") || syndrome === "stone" || syndrome === "scrotal";
|
|
11182
|
+
const showLUTS = syndrome === "luts" || syndrome === "retention" || chips.includes("frequency_urgency") || chips.includes("poor_stream") || chips.includes("acute_retention");
|
|
11183
|
+
const showHaem = syndrome === "haematuria" || chips.includes("haematuria");
|
|
11184
|
+
const showSex = syndrome === "ed_infertility" || chips.includes("erectile_dysfunction") || chips.includes("infertility_concern");
|
|
11185
|
+
const update = (next) => {
|
|
11186
|
+
setValue(next);
|
|
11187
|
+
setTouched();
|
|
11188
|
+
};
|
|
11189
|
+
const ipssTotal = urologyIpssSevenTotal(safe.ipss);
|
|
11190
|
+
const ipssBandLabel = urologyIpssBand(ipssTotal);
|
|
11191
|
+
const bandClass = ipssBandLabel === "Severe" ? "bg-red-500/15 text-red-700" : ipssBandLabel === "Moderate" ? "bg-amber-500/15 text-amber-800" : "bg-emerald-500/15 text-emerald-800";
|
|
11192
|
+
const setSocrates = (key, v) => {
|
|
11193
|
+
if (key === "severity") {
|
|
11194
|
+
const n = typeof v === "number" ? v : Number(v);
|
|
11195
|
+
const sev = Number.isFinite(n) ? Math.min(10, Math.max(0, Math.round(n))) : 0;
|
|
11196
|
+
update({ ...safe, socrates: { ...safe.socrates, severity: sev } });
|
|
11197
|
+
return;
|
|
11198
|
+
}
|
|
11199
|
+
update({ ...safe, socrates: { ...safe.socrates, [key]: String(v) } });
|
|
11200
|
+
};
|
|
11201
|
+
const setIpss = (key, v) => {
|
|
11202
|
+
update({ ...safe, ipss: { ...safe.ipss, [key]: v } });
|
|
11203
|
+
};
|
|
11204
|
+
if (!fieldDef) return null;
|
|
11205
|
+
const theme = getThemeConfig("textarea", fieldDef.theme);
|
|
11206
|
+
const wrapperClass = theme?.wrapperClassName ?? "rounded-md overflow-hidden flex flex-col border border-[#D0D0D0]";
|
|
11207
|
+
const labelClass = theme?.labelClassName;
|
|
11208
|
+
const labelContent = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
11209
|
+
fieldDef.label,
|
|
11210
|
+
fieldDef.required ? /* @__PURE__ */ jsx("span", { className: "ml-1 text-red-500", children: "*" }) : null
|
|
11211
|
+
] });
|
|
11212
|
+
const labelEl = theme ? /* @__PURE__ */ jsx(Label, { className: labelClass, children: labelContent }) : /* @__PURE__ */ jsx(Label, { className: "text-sm font-medium", children: labelContent });
|
|
11213
|
+
const bodyClass = cn(
|
|
11214
|
+
"-mt-1 flex min-w-0 flex-col gap-3 border-t border-[#D0D0D0] bg-white px-3 py-3",
|
|
11215
|
+
disabled && "pointer-events-none opacity-60"
|
|
11216
|
+
);
|
|
11217
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("w-full min-w-0", wrapperClass), children: [
|
|
11218
|
+
labelEl,
|
|
11219
|
+
/* @__PURE__ */ jsxs("div", { className: bodyClass, children: [
|
|
11220
|
+
/* @__PURE__ */ jsx("p", { className: "text-[11px] text-muted-foreground", children: "Panels follow chief complaint chips and active syndrome (Clearsight SmartHistoryUro)." }),
|
|
11221
|
+
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
|
+
SOCRATES_KEYS3.map((k) => /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
|
|
11223
|
+
/* @__PURE__ */ jsx("span", { className: "text-[10px] font-medium uppercase tracking-wide text-muted-foreground", children: k }),
|
|
11224
|
+
/* @__PURE__ */ jsx(
|
|
11225
|
+
Input,
|
|
11226
|
+
{
|
|
11227
|
+
className: "h-8 text-xs",
|
|
11228
|
+
value: safe.socrates[k],
|
|
11229
|
+
onChange: (e) => setSocrates(k, e.target.value),
|
|
11230
|
+
placeholder: k === "radiation" ? "e.g. groin \u2192 ureteric" : k === "character" ? "colicky / dull" : "",
|
|
11231
|
+
disabled
|
|
11232
|
+
}
|
|
11233
|
+
)
|
|
11234
|
+
] }, k)),
|
|
11235
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
|
|
11236
|
+
/* @__PURE__ */ jsx("span", { className: "text-[10px] font-medium uppercase tracking-wide text-muted-foreground", children: "Severity 0\u201310" }),
|
|
11237
|
+
/* @__PURE__ */ jsx(
|
|
11238
|
+
Input,
|
|
11239
|
+
{
|
|
11240
|
+
type: "number",
|
|
11241
|
+
min: 0,
|
|
11242
|
+
max: 10,
|
|
11243
|
+
className: "h-8 text-xs",
|
|
11244
|
+
value: safe.socrates.severity,
|
|
11245
|
+
onChange: (e) => setSocrates("severity", e.target.value),
|
|
11246
|
+
disabled
|
|
11247
|
+
}
|
|
11248
|
+
)
|
|
11249
|
+
] })
|
|
11250
|
+
] }) }) : null,
|
|
11251
|
+
showLUTS ? /* @__PURE__ */ jsxs(
|
|
11252
|
+
Panel2,
|
|
11253
|
+
{
|
|
11254
|
+
title: "IPSS \u2014 International Prostate Symptom Score",
|
|
11255
|
+
right: /* @__PURE__ */ jsxs("span", { className: `rounded-full px-2 py-0.5 text-[10px] font-medium ${bandClass}`, children: [
|
|
11256
|
+
ipssTotal,
|
|
11257
|
+
"/35 \u2014 ",
|
|
11258
|
+
ipssBandLabel
|
|
11259
|
+
] }),
|
|
11260
|
+
children: [
|
|
11261
|
+
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-2 md:grid-cols-4", children: [
|
|
11262
|
+
Object.keys(IPSS_LABELS).map((k) => /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
|
|
11263
|
+
/* @__PURE__ */ jsx("span", { className: "text-[10px] uppercase tracking-wide text-muted-foreground", children: IPSS_LABELS[k] }),
|
|
11264
|
+
/* @__PURE__ */ jsxs(
|
|
11265
|
+
Select,
|
|
11266
|
+
{
|
|
11267
|
+
value: String(safe.ipss[k]),
|
|
11268
|
+
onValueChange: (val) => setIpss(k, Number(val)),
|
|
11269
|
+
disabled,
|
|
11270
|
+
children: [
|
|
11271
|
+
/* @__PURE__ */ jsx(SelectTrigger, { className: "h-8 text-xs", children: /* @__PURE__ */ jsx(SelectValue, {}) }),
|
|
11272
|
+
/* @__PURE__ */ jsx(SelectContent, { children: [0, 1, 2, 3, 4, 5].map((n) => /* @__PURE__ */ jsx(SelectItem, { value: String(n), children: n }, n)) })
|
|
11273
|
+
]
|
|
11274
|
+
}
|
|
11275
|
+
)
|
|
11276
|
+
] }, k)),
|
|
11277
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
|
|
11278
|
+
/* @__PURE__ */ jsx("span", { className: "text-[10px] uppercase tracking-wide text-muted-foreground", children: "QoL (0\u20136)" }),
|
|
11279
|
+
/* @__PURE__ */ jsxs(
|
|
11280
|
+
Select,
|
|
11281
|
+
{
|
|
11282
|
+
value: String(safe.ipssQoL),
|
|
11283
|
+
onValueChange: (val) => update({ ...safe, ipssQoL: Math.min(6, Math.max(0, Number(val))) }),
|
|
11284
|
+
disabled,
|
|
11285
|
+
children: [
|
|
11286
|
+
/* @__PURE__ */ jsx(SelectTrigger, { className: "h-8 text-xs", children: /* @__PURE__ */ jsx(SelectValue, {}) }),
|
|
11287
|
+
/* @__PURE__ */ jsx(SelectContent, { children: [0, 1, 2, 3, 4, 5, 6].map((n) => /* @__PURE__ */ jsx(SelectItem, { value: String(n), children: n }, n)) })
|
|
11288
|
+
]
|
|
11289
|
+
}
|
|
11290
|
+
)
|
|
11291
|
+
] })
|
|
11292
|
+
] }),
|
|
11293
|
+
/* @__PURE__ */ jsxs("p", { className: "mt-2 text-[10px] text-muted-foreground", children: [
|
|
11294
|
+
"Bands: 0\u20137 mild \xB7 8\u201319 moderate \xB7 20\u201335 severe.",
|
|
11295
|
+
" ",
|
|
11296
|
+
/* @__PURE__ */ jsx("span", { className: "font-semibold text-foreground", children: "IPSS \u2265 20 \u2192 consider surgical intervention." })
|
|
11297
|
+
] })
|
|
11298
|
+
]
|
|
11299
|
+
}
|
|
11300
|
+
) : null,
|
|
11301
|
+
showHaem ? /* @__PURE__ */ jsxs(Panel2, { title: "Haematuria profile", children: [
|
|
11302
|
+
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-3 text-xs md:grid-cols-4", children: [
|
|
11303
|
+
/* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2", children: [
|
|
11304
|
+
/* @__PURE__ */ jsx(
|
|
11305
|
+
Checkbox,
|
|
11306
|
+
{
|
|
11307
|
+
checked: safe.haematuria.present,
|
|
11308
|
+
onCheckedChange: (c) => update({
|
|
11309
|
+
...safe,
|
|
11310
|
+
haematuria: { ...safe.haematuria, present: c === true }
|
|
11311
|
+
}),
|
|
11312
|
+
disabled
|
|
11313
|
+
}
|
|
11314
|
+
),
|
|
11315
|
+
"Present"
|
|
11316
|
+
] }),
|
|
11317
|
+
/* @__PURE__ */ jsxs("label", { className: "flex flex-col gap-1", children: [
|
|
11318
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium", children: "Timing" }),
|
|
11319
|
+
/* @__PURE__ */ jsxs(
|
|
11320
|
+
Select,
|
|
11321
|
+
{
|
|
11322
|
+
value: safe.haematuria.timing || "none",
|
|
11323
|
+
onValueChange: (val) => update({
|
|
11324
|
+
...safe,
|
|
11325
|
+
haematuria: { ...safe.haematuria, timing: val === "none" ? "" : val }
|
|
11326
|
+
}),
|
|
11327
|
+
disabled,
|
|
11328
|
+
children: [
|
|
11329
|
+
/* @__PURE__ */ jsx(SelectTrigger, { className: "h-8 text-xs", children: /* @__PURE__ */ jsx(SelectValue, { placeholder: "\u2014" }) }),
|
|
11330
|
+
/* @__PURE__ */ jsxs(SelectContent, { children: [
|
|
11331
|
+
/* @__PURE__ */ jsx(SelectItem, { value: "none", children: "\u2014" }),
|
|
11332
|
+
/* @__PURE__ */ jsx(SelectItem, { value: "Initial", children: "Initial" }),
|
|
11333
|
+
/* @__PURE__ */ jsx(SelectItem, { value: "Terminal", children: "Terminal" }),
|
|
11334
|
+
/* @__PURE__ */ jsx(SelectItem, { value: "Total", children: "Total" })
|
|
11335
|
+
] })
|
|
11336
|
+
]
|
|
11337
|
+
}
|
|
11338
|
+
)
|
|
11339
|
+
] }),
|
|
11340
|
+
/* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2", children: [
|
|
11341
|
+
/* @__PURE__ */ jsx(
|
|
11342
|
+
Checkbox,
|
|
11343
|
+
{
|
|
11344
|
+
checked: safe.haematuria.painful,
|
|
11345
|
+
onCheckedChange: (c) => update({ ...safe, haematuria: { ...safe.haematuria, painful: c === true } }),
|
|
11346
|
+
disabled
|
|
11347
|
+
}
|
|
11348
|
+
),
|
|
11349
|
+
"Painful"
|
|
11350
|
+
] }),
|
|
11351
|
+
/* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2", children: [
|
|
11352
|
+
/* @__PURE__ */ jsx(
|
|
11353
|
+
Checkbox,
|
|
11354
|
+
{
|
|
11355
|
+
checked: safe.haematuria.clots,
|
|
11356
|
+
onCheckedChange: (c) => update({ ...safe, haematuria: { ...safe.haematuria, clots: c === true } }),
|
|
11357
|
+
disabled
|
|
11358
|
+
}
|
|
11359
|
+
),
|
|
11360
|
+
"Clots"
|
|
11361
|
+
] })
|
|
11362
|
+
] }),
|
|
11363
|
+
/* @__PURE__ */ jsx("p", { className: "mt-2 text-[10px] text-red-600", children: "Painless haematuria = malignancy until proven otherwise." })
|
|
11364
|
+
] }) : null,
|
|
11365
|
+
showSex ? /* @__PURE__ */ jsx(Panel2, { title: "Sexual & reproductive history", children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-3 text-xs md:grid-cols-4", children: [
|
|
11366
|
+
/* @__PURE__ */ jsxs("label", { className: "flex flex-col gap-1", children: [
|
|
11367
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium", children: "Erectile function" }),
|
|
11368
|
+
/* @__PURE__ */ jsxs(
|
|
11369
|
+
Select,
|
|
11370
|
+
{
|
|
11371
|
+
value: safe.sexual.erectile || "none",
|
|
11372
|
+
onValueChange: (val) => update({
|
|
11373
|
+
...safe,
|
|
11374
|
+
sexual: { ...safe.sexual, erectile: val === "none" ? "" : val }
|
|
11375
|
+
}),
|
|
11376
|
+
disabled,
|
|
11377
|
+
children: [
|
|
11378
|
+
/* @__PURE__ */ jsx(SelectTrigger, { className: "h-8 text-xs", children: /* @__PURE__ */ jsx(SelectValue, { placeholder: "\u2014" }) }),
|
|
11379
|
+
/* @__PURE__ */ jsxs(SelectContent, { children: [
|
|
11380
|
+
/* @__PURE__ */ jsx(SelectItem, { value: "none", children: "\u2014" }),
|
|
11381
|
+
/* @__PURE__ */ jsx(SelectItem, { value: "Normal", children: "Normal" }),
|
|
11382
|
+
/* @__PURE__ */ jsx(SelectItem, { value: "Mild", children: "Mild" }),
|
|
11383
|
+
/* @__PURE__ */ jsx(SelectItem, { value: "Moderate", children: "Moderate" }),
|
|
11384
|
+
/* @__PURE__ */ jsx(SelectItem, { value: "Severe", children: "Severe" })
|
|
11385
|
+
] })
|
|
11386
|
+
]
|
|
11387
|
+
}
|
|
11388
|
+
)
|
|
11389
|
+
] }),
|
|
11390
|
+
/* @__PURE__ */ jsxs("label", { className: "flex flex-col gap-1", children: [
|
|
11391
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium", children: "Libido" }),
|
|
11392
|
+
/* @__PURE__ */ jsxs(
|
|
11393
|
+
Select,
|
|
11394
|
+
{
|
|
11395
|
+
value: safe.sexual.libido || "none",
|
|
11396
|
+
onValueChange: (val) => update({
|
|
11397
|
+
...safe,
|
|
11398
|
+
sexual: { ...safe.sexual, libido: val === "none" ? "" : val }
|
|
11399
|
+
}),
|
|
11400
|
+
disabled,
|
|
11401
|
+
children: [
|
|
11402
|
+
/* @__PURE__ */ jsx(SelectTrigger, { className: "h-8 text-xs", children: /* @__PURE__ */ jsx(SelectValue, { placeholder: "\u2014" }) }),
|
|
11403
|
+
/* @__PURE__ */ jsxs(SelectContent, { children: [
|
|
11404
|
+
/* @__PURE__ */ jsx(SelectItem, { value: "none", children: "\u2014" }),
|
|
11405
|
+
/* @__PURE__ */ jsx(SelectItem, { value: "Normal", children: "Normal" }),
|
|
11406
|
+
/* @__PURE__ */ jsx(SelectItem, { value: "Reduced", children: "Reduced" })
|
|
11407
|
+
] })
|
|
11408
|
+
]
|
|
11409
|
+
}
|
|
11410
|
+
)
|
|
11411
|
+
] }),
|
|
11412
|
+
/* @__PURE__ */ jsxs("label", { className: "flex flex-col gap-1", children: [
|
|
11413
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium", children: "Ejaculation" }),
|
|
11414
|
+
/* @__PURE__ */ jsxs(
|
|
11415
|
+
Select,
|
|
11416
|
+
{
|
|
11417
|
+
value: safe.sexual.ejaculation || "none",
|
|
11418
|
+
onValueChange: (val) => update({
|
|
11419
|
+
...safe,
|
|
11420
|
+
sexual: { ...safe.sexual, ejaculation: val === "none" ? "" : val }
|
|
11421
|
+
}),
|
|
11422
|
+
disabled,
|
|
11423
|
+
children: [
|
|
11424
|
+
/* @__PURE__ */ jsx(SelectTrigger, { className: "h-8 text-xs", children: /* @__PURE__ */ jsx(SelectValue, { placeholder: "\u2014" }) }),
|
|
11425
|
+
/* @__PURE__ */ jsxs(SelectContent, { children: [
|
|
11426
|
+
/* @__PURE__ */ jsx(SelectItem, { value: "none", children: "\u2014" }),
|
|
11427
|
+
/* @__PURE__ */ jsx(SelectItem, { value: "Normal", children: "Normal" }),
|
|
11428
|
+
/* @__PURE__ */ jsx(SelectItem, { value: "Premature", children: "Premature" }),
|
|
11429
|
+
/* @__PURE__ */ jsx(SelectItem, { value: "Retrograde", children: "Retrograde" }),
|
|
11430
|
+
/* @__PURE__ */ jsx(SelectItem, { value: "Anejaculation", children: "Anejaculation" })
|
|
11431
|
+
] })
|
|
11432
|
+
]
|
|
11433
|
+
}
|
|
11434
|
+
)
|
|
11435
|
+
] }),
|
|
11436
|
+
/* @__PURE__ */ jsxs("label", { className: "flex flex-col gap-1", children: [
|
|
11437
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium", children: "Infertility (months)" }),
|
|
11438
|
+
/* @__PURE__ */ jsx(
|
|
11439
|
+
Input,
|
|
11440
|
+
{
|
|
11441
|
+
type: "number",
|
|
11442
|
+
min: 0,
|
|
11443
|
+
className: "h-8 text-xs",
|
|
11444
|
+
value: safe.sexual.infertilityMonths,
|
|
11445
|
+
onChange: (e) => update({
|
|
11446
|
+
...safe,
|
|
11447
|
+
sexual: {
|
|
11448
|
+
...safe.sexual,
|
|
11449
|
+
infertilityMonths: Math.max(0, Math.round(Number(e.target.value)) || 0)
|
|
11450
|
+
}
|
|
11451
|
+
}),
|
|
11452
|
+
disabled
|
|
11453
|
+
}
|
|
11454
|
+
)
|
|
11455
|
+
] })
|
|
11456
|
+
] }) }) : null,
|
|
11457
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
|
|
11458
|
+
/* @__PURE__ */ jsx(Label, { className: "text-xs font-medium text-slate-700", children: "Past history (stones / surgeries / drugs)" }),
|
|
11459
|
+
/* @__PURE__ */ jsx(
|
|
11460
|
+
Textarea,
|
|
11461
|
+
{
|
|
11462
|
+
className: "min-h-[72px] rounded-md border border-input bg-white text-sm",
|
|
11463
|
+
placeholder: "Prior calculi, urological surgeries, anticoagulants, DM/HTN\u2026",
|
|
11464
|
+
value: safe.pastNotes,
|
|
11465
|
+
onChange: (e) => update({ ...safe, pastNotes: e.target.value }),
|
|
11466
|
+
disabled
|
|
11467
|
+
}
|
|
11468
|
+
)
|
|
11469
|
+
] })
|
|
11470
|
+
] }),
|
|
11471
|
+
showError ? /* @__PURE__ */ jsx("p", { className: "px-3 pb-2 text-xs text-red-500", children: error }) : null
|
|
11472
|
+
] });
|
|
11473
|
+
};
|
|
11474
|
+
var GENERAL_ROWS = [
|
|
11475
|
+
{ key: "pallor", label: "Pallor (chronic dz)" },
|
|
11476
|
+
{ key: "oedema", label: "Oedema (renal)" },
|
|
11477
|
+
{ key: "icterus", label: "Icterus" },
|
|
11478
|
+
{ key: "lymphadenopathy", label: "Lymphadenopathy" }
|
|
11479
|
+
];
|
|
11480
|
+
var ABD_ROWS = [
|
|
11481
|
+
{ key: "distension", label: "Distension" },
|
|
11482
|
+
{ key: "scars", label: "Surgical scars" },
|
|
11483
|
+
{ key: "mass", label: "Visible mass" },
|
|
11484
|
+
{ key: "kidneyPalpable", label: "Kidney palpable" },
|
|
11485
|
+
{ key: "bladderPalpable", label: "Bladder palpable" },
|
|
11486
|
+
{ key: "renalAngleTender", label: "Renal angle tender" },
|
|
11487
|
+
{ key: "bladderDull", label: "Bladder dullness (retention)" }
|
|
11488
|
+
];
|
|
11489
|
+
var GU_ROWS = [
|
|
11490
|
+
{ key: "meatusAbnormal", label: "Meatus abnormal (hypospadias?)" },
|
|
11491
|
+
{ key: "phimosis", label: "Phimosis / paraphimosis" },
|
|
11492
|
+
{ key: "lesions", label: "Penile lesions / ulcers" },
|
|
11493
|
+
{ key: "scrotalSwelling", label: "Scrotal swelling" },
|
|
11494
|
+
{ key: "transilluminant", label: "Transilluminant" },
|
|
11495
|
+
{ key: "tenderTestis", label: "Tender testis" },
|
|
11496
|
+
{ key: "hydrocele", label: "Hydrocele" },
|
|
11497
|
+
{ key: "varicocele", label: "Varicocele" },
|
|
11498
|
+
{ key: "suspiciousMass", label: "Suspicious mass" }
|
|
11499
|
+
];
|
|
11500
|
+
var DRE_CONSISTENCY = ["none", "Soft (benign)", "Firm", "Hard / nodular (malignancy?)"];
|
|
11501
|
+
var DRE_SULCUS = ["none", "Preserved", "Obliterated"];
|
|
11502
|
+
var UrologyExaminationWidget = ({ fieldId }) => {
|
|
11503
|
+
const { fieldDef, value, setValue, setTouched, error, touched, disabled } = useField(fieldId);
|
|
11504
|
+
const { state } = useForm();
|
|
11505
|
+
const showError = !!error && (touched || state.submitAttempted);
|
|
11506
|
+
const safe = useMemo(() => normalizeUrologyExamination(value), [value]);
|
|
11507
|
+
const update = (next) => {
|
|
11508
|
+
setValue(next);
|
|
11509
|
+
setTouched();
|
|
11510
|
+
};
|
|
11511
|
+
const toggleGeneral = (key) => {
|
|
11512
|
+
update({ ...safe, general: { ...safe.general, [key]: !safe.general[key] } });
|
|
11513
|
+
};
|
|
11514
|
+
const toggleAbdomen = (key) => {
|
|
11515
|
+
update({ ...safe, abdomen: { ...safe.abdomen, [key]: !safe.abdomen[key] } });
|
|
11516
|
+
};
|
|
11517
|
+
const toggleGu = (key) => {
|
|
11518
|
+
update({ ...safe, gu: { ...safe.gu, [key]: !safe.gu[key] } });
|
|
11519
|
+
};
|
|
11520
|
+
if (!fieldDef) return null;
|
|
11521
|
+
const theme = getThemeConfig("textarea", fieldDef.theme);
|
|
11522
|
+
const wrapperClass = theme?.wrapperClassName ?? "rounded-md overflow-hidden flex flex-col border border-[#D0D0D0]";
|
|
11523
|
+
const labelClass = theme?.labelClassName;
|
|
11524
|
+
const labelContent = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
11525
|
+
fieldDef.label,
|
|
11526
|
+
fieldDef.required ? /* @__PURE__ */ jsx("span", { className: "ml-1 text-red-500", children: "*" }) : null
|
|
11527
|
+
] });
|
|
11528
|
+
const labelEl = theme ? /* @__PURE__ */ jsx(Label, { className: labelClass, children: labelContent }) : /* @__PURE__ */ jsx(Label, { className: "text-sm font-medium", children: labelContent });
|
|
11529
|
+
const bodyClass = cn(
|
|
11530
|
+
"-mt-1 flex min-w-0 flex-col gap-3 border-t border-[#D0D0D0] bg-white px-3 py-3",
|
|
11531
|
+
disabled && "pointer-events-none opacity-60"
|
|
11532
|
+
);
|
|
11533
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("w-full min-w-0", wrapperClass), children: [
|
|
11534
|
+
labelEl,
|
|
11535
|
+
/* @__PURE__ */ jsxs("div", { className: bodyClass, children: [
|
|
11536
|
+
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 gap-3 text-xs md:grid-cols-2 xl:grid-cols-4", children: [
|
|
11537
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
11538
|
+
/* @__PURE__ */ jsx("p", { className: "font-semibold text-slate-800", children: "General" }),
|
|
11539
|
+
GENERAL_ROWS.map((r) => /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2", children: [
|
|
11540
|
+
/* @__PURE__ */ jsx(
|
|
11541
|
+
Checkbox,
|
|
11542
|
+
{
|
|
11543
|
+
checked: safe.general[r.key],
|
|
11544
|
+
onCheckedChange: () => toggleGeneral(r.key),
|
|
11545
|
+
disabled
|
|
11546
|
+
}
|
|
11547
|
+
),
|
|
11548
|
+
r.label
|
|
11549
|
+
] }, r.key))
|
|
11550
|
+
] }),
|
|
11551
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
11552
|
+
/* @__PURE__ */ jsx("p", { className: "font-semibold text-slate-800", children: "Abdomen" }),
|
|
11553
|
+
ABD_ROWS.map((r) => /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2", children: [
|
|
11554
|
+
/* @__PURE__ */ jsx(
|
|
11555
|
+
Checkbox,
|
|
11556
|
+
{
|
|
11557
|
+
checked: safe.abdomen[r.key],
|
|
11558
|
+
onCheckedChange: () => toggleAbdomen(r.key),
|
|
11559
|
+
disabled
|
|
11560
|
+
}
|
|
11561
|
+
),
|
|
11562
|
+
r.label
|
|
11563
|
+
] }, r.key))
|
|
11564
|
+
] }),
|
|
11565
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
11566
|
+
/* @__PURE__ */ jsx("p", { className: "font-semibold text-slate-800", children: "External genitalia / scrotum" }),
|
|
11567
|
+
GU_ROWS.map((r) => /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2", children: [
|
|
11568
|
+
/* @__PURE__ */ jsx(
|
|
11569
|
+
Checkbox,
|
|
11570
|
+
{
|
|
11571
|
+
checked: safe.gu[r.key],
|
|
11572
|
+
onCheckedChange: () => toggleGu(r.key),
|
|
11573
|
+
disabled
|
|
11574
|
+
}
|
|
11575
|
+
),
|
|
11576
|
+
r.key === "suspiciousMass" ? /* @__PURE__ */ jsx("span", { className: "font-medium text-red-600", children: r.label }) : r.label
|
|
11577
|
+
] }, r.key))
|
|
11578
|
+
] }),
|
|
11579
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
11580
|
+
/* @__PURE__ */ jsx("p", { className: "font-semibold text-slate-800", children: "DRE \u2014 Prostate" }),
|
|
11581
|
+
/* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2", children: [
|
|
11582
|
+
/* @__PURE__ */ jsx(
|
|
11583
|
+
Checkbox,
|
|
11584
|
+
{
|
|
11585
|
+
checked: safe.dre.done,
|
|
11586
|
+
onCheckedChange: (c) => update({ ...safe, dre: { ...safe.dre, done: c === true } }),
|
|
11587
|
+
disabled
|
|
11588
|
+
}
|
|
11589
|
+
),
|
|
11590
|
+
"DRE performed"
|
|
11591
|
+
] }),
|
|
11592
|
+
/* @__PURE__ */ jsxs("label", { className: "block", children: [
|
|
11593
|
+
/* @__PURE__ */ jsx("span", { className: "mb-1 block font-medium", children: "Estimated size (g)" }),
|
|
11594
|
+
/* @__PURE__ */ jsx(
|
|
11595
|
+
Input,
|
|
11596
|
+
{
|
|
11597
|
+
type: "number",
|
|
11598
|
+
min: 0,
|
|
11599
|
+
className: "h-8 text-xs",
|
|
11600
|
+
value: safe.dre.sizeGrams,
|
|
11601
|
+
onChange: (e) => {
|
|
11602
|
+
const n = Number(e.target.value);
|
|
11603
|
+
update({
|
|
11604
|
+
...safe,
|
|
11605
|
+
dre: {
|
|
11606
|
+
...safe.dre,
|
|
11607
|
+
sizeGrams: Number.isFinite(n) && n >= 0 ? Math.round(n) : 0
|
|
11608
|
+
}
|
|
11609
|
+
});
|
|
11610
|
+
},
|
|
11611
|
+
disabled
|
|
11612
|
+
}
|
|
11613
|
+
)
|
|
11614
|
+
] }),
|
|
11615
|
+
/* @__PURE__ */ jsxs("label", { className: "block", children: [
|
|
11616
|
+
/* @__PURE__ */ jsx("span", { className: "mb-1 block font-medium", children: "Consistency" }),
|
|
11617
|
+
/* @__PURE__ */ jsxs(
|
|
11618
|
+
Select,
|
|
11619
|
+
{
|
|
11620
|
+
value: safe.dre.consistency || "none",
|
|
11621
|
+
onValueChange: (val) => update({
|
|
11622
|
+
...safe,
|
|
11623
|
+
dre: { ...safe.dre, consistency: val === "none" ? "" : val }
|
|
11624
|
+
}),
|
|
11625
|
+
disabled,
|
|
11626
|
+
children: [
|
|
11627
|
+
/* @__PURE__ */ jsx(SelectTrigger, { className: "h-8 text-xs", children: /* @__PURE__ */ jsx(SelectValue, { placeholder: "\u2014" }) }),
|
|
11628
|
+
/* @__PURE__ */ jsx(SelectContent, { children: DRE_CONSISTENCY.map((opt) => /* @__PURE__ */ jsx(SelectItem, { value: opt, children: opt === "none" ? "\u2014" : opt }, opt)) })
|
|
11629
|
+
]
|
|
11630
|
+
}
|
|
11631
|
+
)
|
|
11632
|
+
] }),
|
|
11633
|
+
/* @__PURE__ */ jsxs("label", { className: "block", children: [
|
|
11634
|
+
/* @__PURE__ */ jsx("span", { className: "mb-1 block font-medium", children: "Median sulcus" }),
|
|
11635
|
+
/* @__PURE__ */ jsxs(
|
|
11636
|
+
Select,
|
|
11637
|
+
{
|
|
11638
|
+
value: safe.dre.medianSulcus || "none",
|
|
11639
|
+
onValueChange: (val) => update({
|
|
11640
|
+
...safe,
|
|
11641
|
+
dre: { ...safe.dre, medianSulcus: val === "none" ? "" : val }
|
|
11642
|
+
}),
|
|
11643
|
+
disabled,
|
|
11644
|
+
children: [
|
|
11645
|
+
/* @__PURE__ */ jsx(SelectTrigger, { className: "h-8 text-xs", children: /* @__PURE__ */ jsx(SelectValue, { placeholder: "\u2014" }) }),
|
|
11646
|
+
/* @__PURE__ */ jsx(SelectContent, { children: DRE_SULCUS.map((opt) => /* @__PURE__ */ jsx(SelectItem, { value: opt, children: opt === "none" ? "\u2014" : opt }, opt)) })
|
|
11647
|
+
]
|
|
11648
|
+
}
|
|
11649
|
+
)
|
|
11650
|
+
] }),
|
|
11651
|
+
/* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2", children: [
|
|
11652
|
+
/* @__PURE__ */ jsx(
|
|
11653
|
+
Checkbox,
|
|
11654
|
+
{
|
|
11655
|
+
checked: safe.dre.tenderness,
|
|
11656
|
+
onCheckedChange: (c) => update({ ...safe, dre: { ...safe.dre, tenderness: c === true } }),
|
|
11657
|
+
disabled
|
|
11658
|
+
}
|
|
11659
|
+
),
|
|
11660
|
+
"Tender (prostatitis?)"
|
|
11661
|
+
] })
|
|
11662
|
+
] })
|
|
11663
|
+
] }),
|
|
11664
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
|
|
11665
|
+
/* @__PURE__ */ jsx(Label, { className: "text-xs font-semibold text-slate-700", children: "Examination notes" }),
|
|
11666
|
+
/* @__PURE__ */ jsx(
|
|
11667
|
+
Textarea,
|
|
11668
|
+
{
|
|
11669
|
+
className: "min-h-[88px] rounded-md border border-input bg-white text-sm",
|
|
11670
|
+
placeholder: "Free-text exam findings\u2026",
|
|
11671
|
+
value: safe.examinationNotes,
|
|
11672
|
+
onChange: (e) => update({ ...safe, examinationNotes: e.target.value }),
|
|
11673
|
+
disabled
|
|
11674
|
+
}
|
|
11675
|
+
)
|
|
11676
|
+
] })
|
|
11677
|
+
] }),
|
|
11678
|
+
showError ? /* @__PURE__ */ jsx("p", { className: "px-3 pb-2 text-xs text-red-500", children: error }) : null
|
|
11679
|
+
] });
|
|
11680
|
+
};
|
|
11681
|
+
var SMART_HISTORY_FIELD = "uro_smart_history";
|
|
11682
|
+
var EXAMINATION_FIELD = "uro_examination";
|
|
11683
|
+
var DRE_HARD = "Hard / nodular (malignancy?)";
|
|
11684
|
+
function Panel3({
|
|
11685
|
+
title,
|
|
11686
|
+
className,
|
|
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
|
+
}
|
|
11694
|
+
var UrologyPathwayWidget = ({ fieldId }) => {
|
|
11695
|
+
const { fieldDef, value, setValue, setTouched, error, touched, disabled } = useField(fieldId);
|
|
11696
|
+
const { state } = useForm();
|
|
11697
|
+
const showError = !!error && (touched || state.submitAttempted);
|
|
11698
|
+
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
|
+
const update = (next) => {
|
|
11720
|
+
setValue(next);
|
|
11721
|
+
setTouched();
|
|
11722
|
+
};
|
|
11723
|
+
const setRisk = (key, next) => {
|
|
11724
|
+
update({ ...safe, risk: { ...safe.risk, [key]: next } });
|
|
11725
|
+
};
|
|
11726
|
+
if (!fieldDef) return null;
|
|
11727
|
+
const theme = getThemeConfig("textarea", fieldDef.theme);
|
|
11728
|
+
const wrapperClass = theme?.wrapperClassName ?? "rounded-md overflow-hidden flex flex-col border border-[#D0D0D0]";
|
|
11729
|
+
const labelClass = theme?.labelClassName;
|
|
11730
|
+
const labelContent = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
11731
|
+
fieldDef.label,
|
|
11732
|
+
fieldDef.required ? /* @__PURE__ */ jsx("span", { className: "ml-1 text-red-500", children: "*" }) : null
|
|
11733
|
+
] });
|
|
11734
|
+
const labelEl = theme ? /* @__PURE__ */ jsx(Label, { className: labelClass, children: labelContent }) : /* @__PURE__ */ jsx(Label, { className: "text-sm font-medium", children: labelContent });
|
|
11735
|
+
const bodyClass = cn(
|
|
11736
|
+
"-mt-1 flex min-w-0 flex-col gap-3 border-t border-[#D0D0D0] bg-white px-3 py-3",
|
|
11737
|
+
disabled && "pointer-events-none opacity-60"
|
|
11738
|
+
);
|
|
11739
|
+
const subtitle = typeof fieldDef.meta?.subtitle === "string" && fieldDef.meta.subtitle.trim().length > 0 ? fieldDef.meta.subtitle.trim() : "";
|
|
11740
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("w-full min-w-0", wrapperClass), children: [
|
|
11741
|
+
labelEl,
|
|
11742
|
+
/* @__PURE__ */ jsxs("div", { className: bodyClass, children: [
|
|
11743
|
+
subtitle ? /* @__PURE__ */ jsx("p", { className: "-mt-0.5 mb-0 text-xs font-semibold tracking-wide text-slate-700", children: subtitle }) : null,
|
|
11744
|
+
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 gap-3 text-xs md:grid-cols-2 xl:grid-cols-4", children: [
|
|
11745
|
+
/* @__PURE__ */ jsxs(Panel3, { title: "Stone disease", children: [
|
|
11746
|
+
/* @__PURE__ */ jsxs("label", { className: "block", children: [
|
|
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
|
+
] }),
|
|
11782
|
+
/* @__PURE__ */ jsx(
|
|
11783
|
+
"div",
|
|
11784
|
+
{
|
|
11785
|
+
className: cn(
|
|
11786
|
+
"mt-2 rounded p-2 text-[11px]",
|
|
11787
|
+
stone.surgical && safe.stoneSizeMm > 0 ? "bg-red-500/10 text-red-800" : safe.stoneSizeMm > 0 ? "bg-emerald-500/10 text-emerald-900" : "bg-muted/40 text-muted-foreground"
|
|
11788
|
+
),
|
|
11789
|
+
children: stone.plan
|
|
11790
|
+
}
|
|
11791
|
+
),
|
|
11792
|
+
/* @__PURE__ */ jsx("p", { className: "mt-1 text-[10px] text-muted-foreground", children: "Trigger: >10 mm OR obstruction \u2192 surgical." })
|
|
11793
|
+
] }),
|
|
11794
|
+
/* @__PURE__ */ jsxs(Panel3, { title: "Prostate / BPH", children: [
|
|
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
|
+
] }),
|
|
11874
|
+
/* @__PURE__ */ jsx(
|
|
11875
|
+
"div",
|
|
11876
|
+
{
|
|
11877
|
+
className: cn(
|
|
11878
|
+
"mt-2 rounded p-2 text-[11px]",
|
|
11879
|
+
safe.prostateVolumeCc > 30 ? "bg-amber-500/10 text-amber-900" : safe.prostateVolumeCc > 0 ? "bg-emerald-500/10 text-emerald-900" : "bg-muted/40 text-muted-foreground"
|
|
11880
|
+
),
|
|
11881
|
+
children: prostateLine
|
|
11882
|
+
}
|
|
11883
|
+
),
|
|
11884
|
+
/* @__PURE__ */ jsx("p", { className: "mt-1 text-[10px] text-muted-foreground", children: "<30 cc medical \xB7 30\u201380 cc TURP \xB7 >80 cc HoLEP/Open" })
|
|
11885
|
+
] }),
|
|
11886
|
+
/* @__PURE__ */ jsxs(Panel3, { title: "IPSS & cues", children: [
|
|
11887
|
+
/* @__PURE__ */ jsxs("div", { className: "mb-2 flex items-center justify-between", children: [
|
|
11888
|
+
/* @__PURE__ */ jsx("span", { className: "text-slate-700", children: "IPSS total" }),
|
|
11889
|
+
/* @__PURE__ */ jsxs("span", { className: `rounded-full px-2 py-0.5 text-[11px] font-semibold ${ipssBandCls}`, children: [
|
|
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",
|
|
11897
|
+
{
|
|
11898
|
+
className: cn(
|
|
11899
|
+
"h-full transition-[width]",
|
|
11900
|
+
ipssTotal >= 20 ? "bg-red-500" : ipssTotal >= 8 ? "bg-amber-500" : "bg-emerald-500"
|
|
11901
|
+
),
|
|
11902
|
+
style: { width: `${Math.min(100, ipssTotal / 35 * 100)}%` }
|
|
11903
|
+
}
|
|
11904
|
+
) }),
|
|
11905
|
+
/* @__PURE__ */ jsxs("p", { className: "mb-3 text-[10px] text-muted-foreground", children: [
|
|
11906
|
+
"From smart history (",
|
|
11907
|
+
/* @__PURE__ */ jsx("span", { className: "font-mono text-foreground", children: SMART_HISTORY_FIELD }),
|
|
11908
|
+
"). \u226520 \u2192 consider surgical intervention."
|
|
11909
|
+
] }),
|
|
11910
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-1.5 text-[11px]", children: [
|
|
11911
|
+
smart.haematuria.present && !smart.haematuria.painful ? /* @__PURE__ */ jsx("div", { className: "rounded bg-red-500/10 p-1.5 text-red-800", children: "Painless haematuria \u2014 mandatory cystoscopy" }) : null,
|
|
11912
|
+
psaHigh ? /* @__PURE__ */ jsx("div", { className: "rounded bg-amber-500/10 p-1.5 text-amber-900", children: "PSA >4 \u2014 workup for Ca prostate" }) : null,
|
|
11913
|
+
exam.dre.consistency === DRE_HARD ? /* @__PURE__ */ jsxs("div", { className: "rounded bg-red-500/10 p-1.5 text-red-800", children: [
|
|
11914
|
+
"Hard / nodular prostate (",
|
|
11915
|
+
/* @__PURE__ */ jsx("span", { className: "font-mono", children: EXAMINATION_FIELD }),
|
|
11916
|
+
") \u2014 biopsy pathway"
|
|
11917
|
+
] }) : null,
|
|
11918
|
+
exam.gu.suspiciousMass ? /* @__PURE__ */ jsx("div", { className: "rounded bg-red-500/10 p-1.5 text-red-800", children: "Suspicious scrotal mass \u2014 urgent surgical eval" }) : null
|
|
11919
|
+
] })
|
|
11920
|
+
] }),
|
|
11921
|
+
/* @__PURE__ */ jsx(Panel3, { title: "Risk stratification", children: /* @__PURE__ */ jsx("div", { className: "space-y-2", children: [
|
|
11922
|
+
["ckd", "CKD"],
|
|
11923
|
+
["diabetes", "Diabetes"],
|
|
11924
|
+
["anticoagulants", "Anticoagulants"],
|
|
11925
|
+
["activeInfection", "Active infection"]
|
|
11926
|
+
].map(([key, lab]) => /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2", children: [
|
|
11927
|
+
/* @__PURE__ */ jsx(
|
|
11928
|
+
Checkbox,
|
|
11929
|
+
{
|
|
11930
|
+
checked: safe.risk[key],
|
|
11931
|
+
disabled,
|
|
11932
|
+
onCheckedChange: (c) => setRisk(key, c === true)
|
|
11933
|
+
}
|
|
11934
|
+
),
|
|
11935
|
+
/* @__PURE__ */ jsx("span", { className: "text-slate-700", children: lab })
|
|
11936
|
+
] }, key)) }) })
|
|
11937
|
+
] })
|
|
11938
|
+
] }),
|
|
11939
|
+
showError ? /* @__PURE__ */ jsx("p", { className: "px-3 pb-2 text-xs text-red-500", children: error }) : null
|
|
11940
|
+
] });
|
|
11941
|
+
};
|
|
10176
11942
|
var FieldRenderer = ({ fieldId }) => {
|
|
10177
11943
|
const { fieldDef, visible } = useField(fieldId);
|
|
10178
11944
|
if (!visible || !fieldDef) {
|
|
@@ -10254,6 +12020,12 @@ function renderWidget(fieldId, fieldDef) {
|
|
|
10254
12020
|
return /* @__PURE__ */ jsx(GsGradingWidget, { fieldId });
|
|
10255
12021
|
case "pain_scale_flags":
|
|
10256
12022
|
return /* @__PURE__ */ jsx(PainScaleFlagsWidget, { fieldId });
|
|
12023
|
+
case "urology_smart_history":
|
|
12024
|
+
return /* @__PURE__ */ jsx(UrologySmartHistoryWidget, { fieldId });
|
|
12025
|
+
case "urology_examination":
|
|
12026
|
+
return /* @__PURE__ */ jsx(UrologyExaminationWidget, { fieldId });
|
|
12027
|
+
case "urology_pathway":
|
|
12028
|
+
return /* @__PURE__ */ jsx(UrologyPathwayWidget, { fieldId });
|
|
10257
12029
|
case "toggle": {
|
|
10258
12030
|
const { value, setValue, setTouched, disabled } = useField(fieldId);
|
|
10259
12031
|
const store = useFormStore();
|
|
@@ -11117,7 +12889,43 @@ var ReadOnlyFieldRenderer = ({
|
|
|
11117
12889
|
].join("\n");
|
|
11118
12890
|
return /* @__PURE__ */ jsx(ReadOnlyText, { fieldDef, value: lines });
|
|
11119
12891
|
}
|
|
11120
|
-
case "
|
|
12892
|
+
case "urology_smart_history":
|
|
12893
|
+
return /* @__PURE__ */ jsx(
|
|
12894
|
+
ReadOnlyText,
|
|
12895
|
+
{
|
|
12896
|
+
fieldDef,
|
|
12897
|
+
value: value && typeof value === "object" ? JSON.stringify(value, null, 2) : value == null || value === "" ? "\u2014" : String(value)
|
|
12898
|
+
}
|
|
12899
|
+
);
|
|
12900
|
+
case "urology_examination":
|
|
12901
|
+
return /* @__PURE__ */ jsx(
|
|
12902
|
+
ReadOnlyText,
|
|
12903
|
+
{
|
|
12904
|
+
fieldDef,
|
|
12905
|
+
value: value && typeof value === "object" ? JSON.stringify(value, null, 2) : value == null || value === "" ? "\u2014" : String(value)
|
|
12906
|
+
}
|
|
12907
|
+
);
|
|
12908
|
+
case "urology_pathway":
|
|
12909
|
+
return /* @__PURE__ */ jsx(
|
|
12910
|
+
ReadOnlyText,
|
|
12911
|
+
{
|
|
12912
|
+
fieldDef,
|
|
12913
|
+
value: value && typeof value === "object" ? JSON.stringify(value, null, 2) : value == null || value === "" ? "\u2014" : String(value)
|
|
12914
|
+
}
|
|
12915
|
+
);
|
|
12916
|
+
case "general_surgery_smart_history": {
|
|
12917
|
+
const structuredDisplay = value && typeof value === "object" ? JSON.stringify(normalizeGeneralSurgerySmartHistory(value), null, 2) : value == null || value === "" ? "\u2014" : String(value);
|
|
12918
|
+
const hopcDef = resolveFieldDef?.("symptoms");
|
|
12919
|
+
const hopcRaw = allValues?.["symptoms"];
|
|
12920
|
+
const hopcStr = typeof hopcRaw === "string" ? hopcRaw : hopcRaw != null && hopcRaw !== "" ? String(hopcRaw) : "";
|
|
12921
|
+
return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
|
|
12922
|
+
/* @__PURE__ */ jsx(ReadOnlyText, { fieldDef, value: structuredDisplay }),
|
|
12923
|
+
hopcDef ? /* @__PURE__ */ jsx(ReadOnlyText, { fieldDef: hopcDef, value: hopcStr }) : hopcStr ? /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
12924
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-gray-700", children: "History of presenting complaint" }),
|
|
12925
|
+
/* @__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 })
|
|
12926
|
+
] }) : null
|
|
12927
|
+
] });
|
|
12928
|
+
}
|
|
11121
12929
|
case "general_surgery_grading":
|
|
11122
12930
|
return /* @__PURE__ */ jsx(
|
|
11123
12931
|
ReadOnlyText,
|
|
@@ -11346,6 +13154,6 @@ function createUploadHandler(options) {
|
|
|
11346
13154
|
};
|
|
11347
13155
|
}
|
|
11348
13156
|
|
|
11349
|
-
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 };
|
|
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, attachUrologyClinicalPathwayMetadata, createUploadHandler, evaluateRules, fieldMetaRequestsMarMedicationOrdersButton, isUrologyTemplate, shouldFoldUrologyClinicalPathway, useField, useFieldHandlers, useForm, useFormStore, useFrequentItems, usePackages, useSmartKeywords, validateField, validateForm };
|
|
11350
13158
|
//# sourceMappingURL=index.mjs.map
|
|
11351
13159
|
//# sourceMappingURL=index.mjs.map
|