Skip to content

Commit

Permalink
Cleanup Labels in Questionnaire
Browse files Browse the repository at this point in the history
  • Loading branch information
gigincg authored and khavinshankar committed Jan 8, 2025
1 parent e0dc6af commit 78bd1f2
Show file tree
Hide file tree
Showing 6 changed files with 130 additions and 140 deletions.
29 changes: 20 additions & 9 deletions src/components/Questionnaire/QuestionLabel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,33 @@ import type { Question } from "@/types/questionnaire/question";
interface QuestionLabelProps {
question: Question;
className?: string;
groupLabel?: boolean;
}

const defaultGroupClass = "text-lg font-medium text-gray-900";
const defaultInputClass = "text-base font-medium block";

export function QuestionLabel({
question,
className = "text-base font-medium block",
className,
groupLabel,
}: QuestionLabelProps) {
const defaultClass = groupLabel ? defaultGroupClass : defaultInputClass;
return (
<Label className={className}>
<div className="flex justify-between items-center text-gray-800 font-semibold">
<div>
{question.text}
{question.required && <span className="ml-1 text-red-500">*</span>}
<Label className={className ?? defaultClass}>
<div className="flex flex-col gap-3">
{groupLabel && <div className="h-1 w-4 rounded-full bg-indigo-600" />}
<div className="flex gap-3 items-center">
<span>
{question.text}
{question.required && <span className="ml-1 text-red-500">*</span>}
</span>
{question.unit?.code && (
<span className="text-sm text-gray-500">
({question.unit.code})
</span>
)}
</div>
{question.unit?.code && (
<span className="text-sm text-gray-500">{question.unit.code}</span>
)}
</div>
</Label>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,6 @@ const CATEGORY_ICONS: Record<AllergyCategory, React.ReactNode> = {
};

export function AllergyQuestion({
question,
questionnaireResponse,
updateQuestionnaireResponseCB,
disabled,
Expand Down Expand Up @@ -119,11 +118,7 @@ export function AllergyQuestion({
};

return (
<div className="space-y-4">
<Label className="text-base font-medium">
{question.text}
{question.required && <span className="ml-1 text-red-500">*</span>}
</Label>
<>
{allergies.length > 0 && (
<div className="rounded-lg border">
<div className="overflow-x-auto">
Expand Down Expand Up @@ -170,7 +165,7 @@ export function AllergyQuestion({
onSelect={handleAddAllergy}
disabled={disabled}
/>
</div>
</>
);
}
interface AllergyItemProps {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ interface FollowUpVisitQuestionProps {
}

export function FollowUpAppointmentQuestion({
question,
questionnaireResponse,
updateQuestionnaireResponseCB,
disabled,
Expand Down Expand Up @@ -94,121 +93,113 @@ export function FollowUpAppointmentQuestion({

return (
<div className="space-y-4">
<Label className="text-base font-medium">
{question.text}
{question.required && <span className="ml-1 text-red-500">*</span>}
</Label>
<div className="space-y-4">
<div>
<Label className="mb-2">{t("reason_for_visit")}</Label>
<Textarea
placeholder={t("reason_for_visit_placeholder")}
value={value.reason_for_visit || ""}
onChange={(e) => handleUpdate({ reason_for_visit: e.target.value })}
disabled={disabled}
/>
</div>
<div>
<Label className="block mb-2">{t("select_practitioner")}</Label>
<Select
disabled={resourcesQuery.isLoading || disabled}
value={resource?.id}
onValueChange={(value) =>
setResource(
resourcesQuery.data?.users.find((r) => r.id === value),
)
}
>
<SelectTrigger>
<SelectValue placeholder={t("show_all")} />
</SelectTrigger>
<SelectContent>
{resourcesQuery.data?.users.map((user) => (
<SelectItem key={user.username} value={user.id}>
<div className="flex items-center gap-2">
<Avatar
imageUrl={user.profile_picture_url}
name={formatDisplayName(user)}
className="size-6 rounded-full"
/>
<span>{formatDisplayName(user)}</span>
</div>
</SelectItem>
))}
</SelectContent>
</Select>
</div>
<div>
<Label className="mb-2">{t("reason_for_visit")}</Label>
<Textarea
placeholder={t("reason_for_visit_placeholder")}
value={value.reason_for_visit || ""}
onChange={(e) => handleUpdate({ reason_for_visit: e.target.value })}
disabled={disabled}
/>
</div>
<div>
<Label className="block mb-2">{t("select_practitioner")}</Label>
<Select
disabled={resourcesQuery.isLoading || disabled}
value={resource?.id}
onValueChange={(value) =>
setResource(resourcesQuery.data?.users.find((r) => r.id === value))
}
>
<SelectTrigger>
<SelectValue placeholder={t("show_all")} />
</SelectTrigger>
<SelectContent>
{resourcesQuery.data?.users.map((user) => (
<SelectItem key={user.username} value={user.id}>
<div className="flex items-center gap-2">
<Avatar
imageUrl={user.profile_picture_url}
name={formatDisplayName(user)}
className="size-6 rounded-full"
/>
<span>{formatDisplayName(user)}</span>
</div>
</SelectItem>
))}
</SelectContent>
</Select>
</div>

<div className="flex gap-2">
<div className="flex-1">
<Label className="block mb-2">{t("select_date")}</Label>
<DatePicker date={selectedDate} onChange={setSelectedDate} />
</div>
<div className="flex gap-2">
<div className="flex-1">
<Label className="block mb-2">{t("select_date")}</Label>
<DatePicker date={selectedDate} onChange={setSelectedDate} />
</div>

<div className="flex-1">
<Label className="block mb-2">{t("select_time")}</Label>
{(!slotsQuery.data?.results ||
slotsQuery.data.results.length === 0) &&
selectedDate &&
resource ? (
<div className="rounded-md border border-input px-3 py-2 text-sm text-muted-foreground">
{t("no_slots_available")}
</div>
) : (
<Select
disabled={
!selectedDate || !resource || slotsQuery.isLoading || disabled
}
value={value.slot_id}
onValueChange={(slotId) => {
handleUpdate({ slot_id: slotId });
}}
>
<SelectTrigger>
<SelectValue placeholder={t("select_time_slot")} />
</SelectTrigger>
<SelectContent>
{slotsQuery.data?.results &&
groupSlotsByAvailability(slotsQuery.data.results).map(
({ availability, slots }) => (
<div key={availability.name}>
<div className="px-2 py-1.5 text-sm font-semibold">
{availability.name}
</div>
{slots.map((slot) => {
const isFullyBooked =
slot.allocated >= availability.tokens_per_slot;
return (
<SelectItem
key={slot.id}
value={slot.id}
disabled={isFullyBooked}
>
<div className="flex items-center justify-between">
<span>
{format(slot.start_datetime, "HH:mm")}
</span>
<span className="pl-1 text-xs text-gray-500">
{availability.tokens_per_slot -
slot.allocated}{" "}
{t("slots_left")}
</span>
</div>
</SelectItem>
);
})}
<div className="flex-1">
<Label className="block mb-2">{t("select_time")}</Label>
{(!slotsQuery.data?.results ||
slotsQuery.data.results.length === 0) &&
selectedDate &&
resource ? (
<div className="rounded-md border border-input px-3 py-2 text-sm text-muted-foreground">
{t("no_slots_available")}
</div>
) : (
<Select
disabled={
!selectedDate || !resource || slotsQuery.isLoading || disabled
}
value={value.slot_id}
onValueChange={(slotId) => {
handleUpdate({ slot_id: slotId });
}}
>
<SelectTrigger>
<SelectValue placeholder={t("select_time_slot")} />
</SelectTrigger>
<SelectContent>
{slotsQuery.data?.results &&
groupSlotsByAvailability(slotsQuery.data.results).map(
({ availability, slots }) => (
<div key={availability.name}>
<div className="px-2 py-1.5 text-sm font-semibold">
{availability.name}
</div>
),
)}
{slotsQuery.data?.results.length === 0 && (
<div className="px-2 py-4 text-center text-sm text-gray-500">
{t("no_slots_available")}
</div>
{slots.map((slot) => {
const isFullyBooked =
slot.allocated >= availability.tokens_per_slot;
return (
<SelectItem
key={slot.id}
value={slot.id}
disabled={isFullyBooked}
>
<div className="flex items-center justify-between">
<span>
{format(slot.start_datetime, "HH:mm")}
</span>
<span className="pl-1 text-xs text-gray-500">
{availability.tokens_per_slot -
slot.allocated}{" "}
{t("slots_left")}
</span>
</div>
</SelectItem>
);
})}
</div>
),
)}
</SelectContent>
</Select>
)}
</div>
{slotsQuery.data?.results.length === 0 && (
<div className="px-2 py-4 text-center text-sm text-gray-500">
{t("no_slots_available")}
</div>
)}
</SelectContent>
</Select>
)}
</div>
</div>
</div>
Expand Down
Empty file.
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ const MEDICATION_STATEMENT_INITIAL_VALUE: Omit<
};

export function MedicationStatementQuestion({
question,
questionnaireResponse,
updateQuestionnaireResponseCB,
disabled,
Expand Down Expand Up @@ -110,11 +109,7 @@ export function MedicationStatementQuestion({
};

return (
<div className="space-y-4">
<Label className="text-base font-medium">
{question.text}
{question.required && <span className="ml-1 text-red-500">*</span>}
</Label>
<>
{medications.length > 0 && (
<div className="rounded-lg border space-y-4">
<ul className="space-y-2 divide-y-2 divide-gray-200 divide-dashed">
Expand All @@ -141,7 +136,7 @@ export function MedicationStatementQuestion({
disabled={disabled}
searchPostFix=" clinical drug"
/>
</div>
</>
);
}

Expand Down
8 changes: 3 additions & 5 deletions src/components/Questionnaire/QuestionTypes/QuestionGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { memo } from "react";

import { cn } from "@/lib/utils";

import { Label } from "@/components/ui/label";
import { QuestionLabel } from "@/components/Questionnaire/QuestionLabel";

import { QuestionValidationError } from "@/types/questionnaire/batch";
import type { QuestionnaireResponse } from "@/types/questionnaire/form";
Expand Down Expand Up @@ -111,16 +111,14 @@ export const QuestionGroup = memo(function QuestionGroup({
<div
title="group_styling"
className={cn(
"space-y-4 rounded-lg border p-4",
"space-y-4 rounded-lg",
isActive && "ring-2 ring-primary",
question.styling_metadata?.classes && question.styling_metadata.classes,
)}
>
{question.text && (
<div className="space-y-1">
<Label className="text-lg font-semibold text-gray-900">
{question.text}
</Label>
<QuestionLabel question={question} groupLabel />
{question.description && (
<p className="text-sm text-muted-foreground">
{question.description}
Expand Down

0 comments on commit 78bd1f2

Please sign in to comment.