MED-137: add doctor other jobs view (#55)
* add doctor jobs view * change translation * another translation change * clean up * add analaysis detail view to paths config * translation * merge fix * fix path * move components to shared * refactor * imports * clean up
This commit is contained in:
242
app/doctor/_components/analysis-view.tsx
Normal file
242
app/doctor/_components/analysis-view.tsx
Normal file
@@ -0,0 +1,242 @@
|
||||
'use client';
|
||||
|
||||
import { useState } from 'react';
|
||||
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import { useForm } from 'react-hook-form';
|
||||
|
||||
import { giveFeedbackAction } from '@kit/doctor/actions/doctor-server-actions';
|
||||
import {
|
||||
getDOBWithAgeStringFromPersonalCode,
|
||||
getResultSetName,
|
||||
} from '@kit/doctor/lib/helpers';
|
||||
import {
|
||||
AnalysisResponse,
|
||||
DoctorFeedback,
|
||||
Order,
|
||||
Patient,
|
||||
} from '@kit/doctor/schema/doctor-analysis-detail-view.schema';
|
||||
import {
|
||||
DoctorAnalysisFeedbackForm,
|
||||
doctorAnalysisFeedbackSchema,
|
||||
} from '@kit/doctor/schema/doctor-analysis.schema';
|
||||
import ConfirmationModal from '@kit/shared/components/confirmation-modal';
|
||||
import { getFullName } from '@kit/shared/utils';
|
||||
import { useUser } from '@kit/supabase/hooks/use-user';
|
||||
import { Button } from '@kit/ui/button';
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormMessage,
|
||||
} from '@kit/ui/form';
|
||||
import { toast } from '@kit/ui/sonner';
|
||||
import { Textarea } from '@kit/ui/textarea';
|
||||
import { Trans } from '@kit/ui/trans';
|
||||
|
||||
import Analysis from '~/home/(user)/(dashboard)/analysis-results/_components/analysis';
|
||||
import { bmiFromMetric } from '~/lib/utils';
|
||||
|
||||
export default function AnalysisView({
|
||||
patient,
|
||||
order,
|
||||
analyses,
|
||||
feedback,
|
||||
}: {
|
||||
patient: Patient;
|
||||
order: Order;
|
||||
analyses: AnalysisResponse[];
|
||||
feedback?: DoctorFeedback;
|
||||
}) {
|
||||
const [isConfirmOpen, setIsConfirmOpen] = useState(false);
|
||||
|
||||
const { data: user } = useUser();
|
||||
|
||||
const isInProgress =
|
||||
!!feedback?.status &&
|
||||
feedback?.doctor_user_id &&
|
||||
feedback?.status !== 'COMPLETED';
|
||||
const isReadOnly =
|
||||
!isInProgress ||
|
||||
(!!feedback?.doctor_user_id && feedback?.doctor_user_id !== user?.id);
|
||||
|
||||
const form = useForm({
|
||||
resolver: zodResolver(doctorAnalysisFeedbackSchema),
|
||||
defaultValues: {
|
||||
feedbackValue: feedback?.value ?? '',
|
||||
userId: patient.userId,
|
||||
},
|
||||
});
|
||||
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
if (!patient || !order || !analyses) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const onSubmit = async (
|
||||
data: DoctorAnalysisFeedbackForm,
|
||||
status: 'DRAFT' | 'COMPLETED',
|
||||
) => {
|
||||
try {
|
||||
const feedbackPromise = giveFeedbackAction({
|
||||
...data,
|
||||
analysisOrderId: order.analysisOrderId,
|
||||
status,
|
||||
});
|
||||
|
||||
toast.promise(() => feedbackPromise, {
|
||||
success: <Trans i18nKey={'doctor:updateFeedbackSuccess'} />,
|
||||
error: <Trans i18nKey={'doctor:updateFeedbackError'} />,
|
||||
loading: <Trans i18nKey={'doctor:updateFeedbackLoading'} />,
|
||||
});
|
||||
|
||||
queryClient.invalidateQueries({
|
||||
predicate: (query) => query.queryKey.includes('doctor-jobs'),
|
||||
});
|
||||
|
||||
return setIsConfirmOpen(false);
|
||||
} catch (error) {
|
||||
toast.error(<Trans i18nKey="common:genericServerError" />);
|
||||
}
|
||||
};
|
||||
|
||||
const handleDraftSubmit = () => {
|
||||
const formData = form.getValues();
|
||||
onSubmit(formData, 'DRAFT');
|
||||
};
|
||||
|
||||
const handleCompleteSubmit = () => {
|
||||
setIsConfirmOpen(true);
|
||||
};
|
||||
|
||||
const confirmComplete = () => {
|
||||
const formData = form.getValues();
|
||||
onSubmit(formData, 'COMPLETED');
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<h3>
|
||||
<Trans
|
||||
i18nKey={getResultSetName(
|
||||
order.title,
|
||||
order.isPackage,
|
||||
Object.keys(analyses)?.length,
|
||||
)}
|
||||
/>
|
||||
</h3>
|
||||
<div className="grid grid-cols-2">
|
||||
<div className="font-bold">
|
||||
<Trans i18nKey="doctor:name" />
|
||||
</div>
|
||||
<div>{getFullName(patient.firstName, patient.lastName)}</div>
|
||||
<div className="font-bold">
|
||||
<Trans i18nKey="doctor:personalCode" />
|
||||
</div>
|
||||
<div>{patient.personalCode ?? ''}</div>
|
||||
<div className="font-bold">
|
||||
<Trans i18nKey="doctor:dobAndAge" />
|
||||
</div>
|
||||
<div>{getDOBWithAgeStringFromPersonalCode(patient.personalCode)}</div>
|
||||
<div className="font-bold">
|
||||
<Trans i18nKey="doctor:height" />
|
||||
</div>
|
||||
<div>{patient.height}</div>
|
||||
<div className="font-bold">
|
||||
<Trans i18nKey="doctor:weight" />
|
||||
</div>
|
||||
<div>{patient.weight}</div>
|
||||
<div className="font-bold">
|
||||
<Trans i18nKey="doctor:bmi" />
|
||||
</div>
|
||||
<div>{bmiFromMetric(patient?.height ?? 0, patient?.weight ?? 0)}</div>
|
||||
<div className="font-bold">
|
||||
<Trans i18nKey="doctor:smoking" />
|
||||
</div>
|
||||
<div></div>
|
||||
<div className="font-bold">
|
||||
<Trans i18nKey="doctor:phone" />
|
||||
</div>
|
||||
<div>{patient.phone}</div>
|
||||
<div className="font-bold">
|
||||
<Trans i18nKey="doctor:email" />
|
||||
</div>
|
||||
<div>{patient.email}</div>
|
||||
</div>
|
||||
|
||||
<h3>
|
||||
<Trans i18nKey="doctor:results" />
|
||||
</h3>
|
||||
<div className="flex flex-col gap-2">
|
||||
{analyses.map((analysisData) => {
|
||||
return (
|
||||
<Analysis
|
||||
key={analysisData.id}
|
||||
analysisElement={{
|
||||
analysis_name_lab: analysisData.analysis_name,
|
||||
}}
|
||||
results={analysisData}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
<h3>
|
||||
<Trans i18nKey="doctor:feedback" />
|
||||
</h3>
|
||||
|
||||
<p>{feedback?.value ?? '-'}</p>
|
||||
|
||||
{!isReadOnly && (
|
||||
<Form {...form}>
|
||||
<form className="space-y-4 lg:w-1/2">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="feedbackValue"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Textarea {...field} disabled={isReadOnly} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<div className="flex gap-2">
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
handleDraftSubmit();
|
||||
}}
|
||||
disabled={isReadOnly}
|
||||
>
|
||||
<Trans i18nKey="common:saveAsDraft" />
|
||||
</Button>
|
||||
<Button
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
handleCompleteSubmit();
|
||||
}}
|
||||
disabled={isReadOnly}
|
||||
>
|
||||
<Trans i18nKey="common:save" />
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
)}
|
||||
<ConfirmationModal
|
||||
isOpen={isConfirmOpen}
|
||||
onClose={() => setIsConfirmOpen(false)}
|
||||
onConfirm={confirmComplete}
|
||||
titleKey="doctor:confirmFeedbackModal.title"
|
||||
descriptionKey="doctor:confirmFeedbackModal.description"
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user