-
Notifications
You must be signed in to change notification settings - Fork 514
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add base for fhir forms #9262
Add base for fhir forms #9262
Changes from 20 commits
c464e63
c47a541
d2a6e12
6c8cd61
6fa3520
9da93aa
cfa055d
20cc9b2
f775e6f
e82126c
2c57ce9
c9726a9
9624078
0a7a133
fcd9ac2
d4b94c2
1b60519
1a82817
754a479
40dc5b0
062dd94
e5a2a28
44405be
1e0eb39
dd12b34
86e58a7
402aa2c
2401e2f
19e035e
d5bfef9
abfbc61
4f2cbf4
9f3637b
9833569
547edd4
bcf1970
47ee165
5dea3a9
e23cff7
04cb300
770f991
04d3ea7
ee3b941
912ee9a
ed2d5e3
f9d7fbd
cdb3558
5d3c719
ba16ea2
6691441
1a21311
b0ecc62
f12a27e
6a859c8
6a41e31
2a2c09b
3e926ab
16f1331
b50cbcf
b79daaf
7f6fe60
d29b13c
bf6330a
1b118f7
457da44
ef30f7a
25b3aec
2582637
e2d02b6
5b83a6e
e3c8571
595450d
dbba8da
698befa
26dc260
e0c8889
47b21d1
46bf5ed
f5411d8
22eee90
67b6d03
9bbaed4
2203a25
35e0725
d2c94a0
b6103b1
572cdae
a370cfe
7bf3bca
421bfa2
cc737e4
52956f5
2acd106
6a56d9b
fb5407e
b196362
8ca7a57
157e523
664b217
9a28652
1f5cd90
9d1fc9a
03a5ca0
bf64f6f
9295643
2594908
4517cf0
9b7f390
3b746f4
46e9ef3
57f7c0e
4dcd431
e042651
79afe4e
c297b92
e4a9060
317e792
b075970
96cd29e
85a80bc
eb249fd
92202c5
27a064c
55636a6
37757af
3e89df5
38e0dfa
95a5107
c01598d
bb745c2
896d6b5
ffa11d4
988570c
4e53924
45483b6
8236465
531abb2
efbbe48
894bfb6
11e9d0a
b744ce4
dd98155
3c869f4
adbab3c
bb0d545
25426fe
5980ee1
5dd612c
7cd29ca
3b19fde
0dedb10
bd2a3bc
e923e43
a6c11e1
7d01e4e
fcc808f
cfcdfc8
8a8ba38
ca75575
213777b
27f663f
3cdbfad
b40a676
bb81159
147fb3e
cc7b3f7
8ad3e86
9b8e634
b21c5ed
44e1a97
a7b76e9
91eb525
27b1a4b
1f11a16
d903755
67635f7
4fd5c2b
1d014dd
1552609
e9385c1
23eb6e9
51957a7
f23241e
216730e
65ea0c5
f6e58ef
fc5599b
5cfd511
7fb179c
00b1e8a
f636e93
d66c8db
5bf7d38
6da2d4f
9c1e72c
7ad89a4
322953d
0f1c906
82c434a
1602e79
c7a2167
266507a
aae2eca
f5445bd
5e30050
7592bcd
3eceb3a
d9e7d79
5187082
ea06ea4
2567f4d
c1a17ae
4b9d333
3d59158
59728cc
3f2d28f
a38cda0
090cff9
0dd1b2d
0356c13
b8bdfa5
aa5de89
62b60b4
0a48b25
3fa6e45
402f965
40b7faf
e324cf6
e840ff2
a237805
ac52bfe
65574a7
035d294
d672cad
d5856fd
e11b6a6
f5d654b
f2916b3
872d667
293e715
534df8c
ad84046
8abffc9
8ac481f
4f1b74b
f012942
587e5ca
e23edce
b20e167
ea19afa
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -60,11 +60,13 @@ | |
"@pnotify/mobile": "^5.2.0", | ||
"@radix-ui/react-dialog": "^1.1.2", | ||
"@radix-ui/react-dropdown-menu": "^2.1.2", | ||
"@radix-ui/react-icons": "^1.3.2", | ||
"@radix-ui/react-label": "^2.1.0", | ||
"@radix-ui/react-popover": "^1.1.2", | ||
"@radix-ui/react-scroll-area": "^1.2.0", | ||
"@radix-ui/react-icons": "^1.3.2", | ||
"@radix-ui/react-select": "^2.1.2", | ||
"@radix-ui/react-slot": "^1.1.0", | ||
"@radix-ui/react-tabs": "^1.1.1", | ||
"@radix-ui/react-toast": "^1.2.2", | ||
"@radix-ui/react-tooltip": "^1.1.4", | ||
"@sentry/browser": "^8.42.0", | ||
|
@@ -180,4 +182,4 @@ | |
"node": ">=22.11.0" | ||
}, | ||
"packageManager": "[email protected]" | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -90,6 +90,12 @@ import { | |
} from "@/components/Users/models"; | ||
|
||
import { PaginatedResponse } from "@/Utils/request/types"; | ||
import { | ||
BatchRequestBody, | ||
BatchSubmissionResult, | ||
} from "@/types/questionnaire/batch"; | ||
import { Code } from "@/types/questionnaire/code"; | ||
import type { QuestionnaireDetail } from "@/types/questionnaire/questionnaire"; | ||
|
||
/** | ||
* A fake function that returns an empty object casted to type T | ||
|
@@ -1399,6 +1405,88 @@ const routes = { | |
}, | ||
}, | ||
}, | ||
|
||
valueset: { | ||
// list: { | ||
// path: "/api/v1/valueset/", | ||
// method: "GET", | ||
// TRes: Type<PaginatedResponse<ValueSet>>(), | ||
// }, | ||
expand: { | ||
path: "/api/v1/valueset/{system}/expand/", | ||
method: "POST", | ||
TBody: Type<{ search: string; count: number }>(), | ||
TRes: Type<{ results: Code[] }>(), | ||
}, | ||
}, | ||
|
||
// Questionnaire Routes | ||
questionnaire: { | ||
list: { | ||
path: "/api/v1/questionnaire/", | ||
method: "GET", | ||
TRes: Type<PaginatedResponse<QuestionnaireDetail>>(), | ||
}, | ||
|
||
detail: { | ||
path: "/api/v1/questionnaire/{id}/", | ||
method: "GET", | ||
TRes: Type<QuestionnaireDetail>(), | ||
}, | ||
|
||
create: { | ||
path: "/api/v1/questionnaire/", | ||
method: "POST", | ||
TRes: Type<QuestionnaireDetail>(), | ||
TBody: Type<Partial<QuestionnaireDetail>>(), | ||
}, | ||
|
||
update: { | ||
path: "/api/v1/questionnaire/{id}/", | ||
method: "PUT", | ||
TRes: Type<QuestionnaireDetail>(), | ||
TBody: Type<QuestionnaireDetail>(), | ||
}, | ||
|
||
partialUpdate: { | ||
path: "/api/v1/questionnaire/{id}/", | ||
method: "PATCH", | ||
TRes: Type<QuestionnaireDetail>(), | ||
TBody: Type<Partial<QuestionnaireDetail>>(), | ||
}, | ||
|
||
delete: { | ||
path: "/api/v1/questionnaire/{id}/", | ||
method: "DELETE", | ||
TRes: Type<Record<string, never>>(), | ||
}, | ||
|
||
submit: { | ||
path: "/api/v1/questionnaire/{id}/submit/", | ||
method: "POST", | ||
TRes: Type<Record<string, never>>(), | ||
TBody: Type<{ | ||
resource_id: string; | ||
encounter: string; | ||
responses: Array<{ | ||
question_id: string; | ||
value: string | number | boolean; | ||
note?: string; | ||
bodysite?: string; | ||
method?: string; | ||
}>; | ||
}>(), | ||
}, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Add validation for questionnaire response values The
Would you like assistance in implementing validation using a library like As a follow-up, you can verify the presence of validation by searching the codebase: #!/bin/bash
# Description: Search for validation in the questionnaire submission process.
# Check for validation schemas or functions related to questionnaire submission.
rg -g '*.{ts,tsx}' -A 5 'questionnaire.*validate|questionnaire.*schema|questionnaire.*validation' |
||
}, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Codebase verification Based on the searches performed, I can now generate the final response since we've thoroughly checked for:
The lack of results from these searches indicates there's no existing validation for questionnaire responses, confirming the review comment's concern. Add validation for questionnaire response values The questionnaire submit endpoint accepts complex response data without any validation. Add runtime validation to ensure:
Example locations that need validation:
🔗 Analysis chainConsider adding validation for questionnaire responses The submit endpoint accepts complex response data but doesn't specify validation requirements in the type definition. Consider adding:
🏁 Scripts executedThe following scripts were executed for the analysis: Script: #!/bin/bash
# Check if validation types/schemas exist for questionnaire responses
rg -g '*.{ts,tsx}' -A 5 'questionnaire.*validation|questionnaire.*schema|questionnaire.*validate'
Length of output: 99 Script: #!/bin/bash
# Let's check for any validation related code in the codebase, particularly around questionnaires
rg -g '*.{ts,tsx}' -B 2 -A 5 'interface.*Questionnaire|type.*Questionnaire'
# Also search for any validation utilities or schemas in the codebase
rg -g '*.{ts,tsx}' -B 2 -A 5 'zod|yup|validate|schema'
# Let's also check how questionnaire responses are handled
ast-grep --pattern 'function $FUNC($$$) {
$$$
questionnaire$$$submit($$$)
$$$
}'
Length of output: 66387 Script: #!/bin/bash
# Let's check for any validation related code specifically for questionnaire responses
rg -g '*.{ts,tsx}' -B 2 -A 5 'QuestionnaireResponse.*validate|QuestionnaireResponse.*schema'
# Let's also check the types/questionnaire directory for any validation related code
rg -g '*.{ts,tsx}' -B 2 -A 5 'validate|schema' src/types/questionnaire/
# Let's look at how questionnaire responses are handled in the form component
ast-grep --pattern 'function $FUNC($$$) {
$$$
responses: QuestionnaireResponse$$$
$$$
}'
Length of output: 265 |
||
|
||
batchRequest: { | ||
path: "/api/v1/batch_requests/", | ||
method: "POST", | ||
TRes: Type<{ | ||
results: BatchSubmissionResult[]; | ||
}>(), | ||
TBody: Type<BatchRequestBody>(), | ||
}, | ||
} as const; | ||
|
||
export default routes; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -61,7 +61,7 @@ export default async function request<TData, TBody>( | |
result = { | ||
res, | ||
data: res.ok ? data : undefined, | ||
error: res.ok ? undefined : (data as Record<string, unknown>), | ||
error: res.ok ? undefined : (data as Record<any, unknown>), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Avoid using 'any' type for error records The change from - error: res.ok ? undefined : (data as Record<any, unknown>),
+ error: res.ok ? undefined : (data as Record<string, unknown>), If specific non-string keys are needed, consider creating a union type of allowed key types: type ErrorKey = string | number;
// Then use: Record<ErrorKey, unknown> |
||
}; | ||
|
||
onResponse?.(result); | ||
|
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,82 @@ | ||||||||||||||||||||||||||||||||||||
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; | ||||||||||||||||||||||||||||||||||||
import { Card, CardContent } from "@/components/ui/card"; | ||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||
import Loading from "@/components/Common/Loading"; | ||||||||||||||||||||||||||||||||||||
import Page from "@/components/Common/Page"; | ||||||||||||||||||||||||||||||||||||
import { QuestionnaireForm } from "@/components/Questionnaire/QuestionnaireForm"; | ||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||
import routes from "@/Utils/request/api"; | ||||||||||||||||||||||||||||||||||||
import useQuery from "@/Utils/request/useQuery"; | ||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||
interface Props { | ||||||||||||||||||||||||||||||||||||
facilityId: string; | ||||||||||||||||||||||||||||||||||||
patientId: string; | ||||||||||||||||||||||||||||||||||||
consultationId: string; | ||||||||||||||||||||||||||||||||||||
questionnaireSlug?: string; | ||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||
export default function EncounterQuestionnaire({ | ||||||||||||||||||||||||||||||||||||
facilityId, | ||||||||||||||||||||||||||||||||||||
patientId, | ||||||||||||||||||||||||||||||||||||
consultationId, | ||||||||||||||||||||||||||||||||||||
questionnaireSlug, | ||||||||||||||||||||||||||||||||||||
}: Props) { | ||||||||||||||||||||||||||||||||||||
const { | ||||||||||||||||||||||||||||||||||||
data: consultation, | ||||||||||||||||||||||||||||||||||||
loading, | ||||||||||||||||||||||||||||||||||||
error, | ||||||||||||||||||||||||||||||||||||
} = useQuery(routes.getConsultation, { | ||||||||||||||||||||||||||||||||||||
pathParams: { id: consultationId }, | ||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||
const { data: patient } = useQuery(routes.getPatient, { | ||||||||||||||||||||||||||||||||||||
pathParams: { id: patientId }, | ||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add error handling for patient data fetch While the consultation fetch has error handling, the patient fetch doesn't handle errors which could lead to runtime errors when accessing - const { data: patient } = useQuery(routes.getPatient, {
+ const { data: patient, error: patientError } = useQuery(routes.getPatient, {
pathParams: { id: patientId },
});
+ if (patientError) {
+ return (
+ <Alert variant="destructive">
+ <AlertTitle>Error</AlertTitle>
+ <AlertDescription>
+ Failed to load patient details. Please try again later.
+ </AlertDescription>
+ </Alert>
+ );
+ } 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||
if (loading) { | ||||||||||||||||||||||||||||||||||||
return <Loading />; | ||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||
if (error) { | ||||||||||||||||||||||||||||||||||||
return ( | ||||||||||||||||||||||||||||||||||||
<Alert variant="destructive"> | ||||||||||||||||||||||||||||||||||||
<AlertTitle>Error</AlertTitle> | ||||||||||||||||||||||||||||||||||||
<AlertDescription> | ||||||||||||||||||||||||||||||||||||
Failed to load consultation details. Please try again later. | ||||||||||||||||||||||||||||||||||||
</AlertDescription> | ||||||||||||||||||||||||||||||||||||
</Alert> | ||||||||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||
return ( | ||||||||||||||||||||||||||||||||||||
<Page | ||||||||||||||||||||||||||||||||||||
title="Questionnaire" | ||||||||||||||||||||||||||||||||||||
crumbsReplacements={{ | ||||||||||||||||||||||||||||||||||||
[facilityId]: { name: patient?.facility_object?.name }, | ||||||||||||||||||||||||||||||||||||
[patientId]: { name: patient?.name }, | ||||||||||||||||||||||||||||||||||||
consultation: { | ||||||||||||||||||||||||||||||||||||
name: "Consultation", | ||||||||||||||||||||||||||||||||||||
uri: `/facility/${facilityId}/patient/${patientId}/consultation/${consultationId}`, | ||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||
[consultationId]: { | ||||||||||||||||||||||||||||||||||||
name: consultation?.encounter_date | ||||||||||||||||||||||||||||||||||||
? `Admitted on ${consultation.encounter_date}` | ||||||||||||||||||||||||||||||||||||
: consultation?.suggestion_text, | ||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||
}} | ||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Add fallback text for missing facility/patient names The crumbs replacement logic should handle cases where facility or patient names are undefined. crumbsReplacements={{
[facilityId]: { name: patient?.facility_object?.name },
[patientId]: { name: patient?.name },
consultation: {
name: "Consultation",
uri: `/facility/${facilityId}/patient/${patientId}/consultation/${consultationId}`,
},
[consultationId]: {
- name: consultation?.encounter_date
- ? `Admitted on ${consultation.encounter_date}`
- : consultation?.suggestion_text,
+ name: consultation?.encounter_date
+ ? `Admitted on ${consultation.encounter_date}`
+ : consultation?.suggestion_text ?? 'Consultation Details',
},
}}
|
||||||||||||||||||||||||||||||||||||
backUrl={`/facility/${facilityId}/patient/${patientId}/consultation/${consultationId}`} | ||||||||||||||||||||||||||||||||||||
> | ||||||||||||||||||||||||||||||||||||
<div className="container mx-auto p-4"> | ||||||||||||||||||||||||||||||||||||
<Card> | ||||||||||||||||||||||||||||||||||||
<CardContent className="pt-6"> | ||||||||||||||||||||||||||||||||||||
<QuestionnaireForm | ||||||||||||||||||||||||||||||||||||
resourceId={patientId} | ||||||||||||||||||||||||||||||||||||
encounterId={consultationId} | ||||||||||||||||||||||||||||||||||||
questionnaireSlug={questionnaireSlug} | ||||||||||||||||||||||||||||||||||||
/> | ||||||||||||||||||||||||||||||||||||
</CardContent> | ||||||||||||||||||||||||||||||||||||
</Card> | ||||||||||||||||||||||||||||||||||||
</div> | ||||||||||||||||||||||||||||||||||||
</Page> | ||||||||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||||||||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Codebase verification
Warning: Cannot remove @radix-ui/react-icons as it's actively used
The package is currently imported in multiple UI components:
Removing this package will break these components. Either keep the dependency or replace these icon imports with alternatives before removal.
🔗 Analysis chain
Verify icon usage after removing @radix-ui/react-icons
The removal of
@radix-ui/react-icons
might impact existing icon usage in the codebase. Let's verify there are no remaining dependencies on this package.Also applies to: 67-67, 69-69
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
Length of output: 75
Script:
Length of output: 73
Script:
Length of output: 1567