feat: enhance CurrentDutyView with new functionality and improved tests

- Added a button to open the calendar in the no-duty view, triggering the onBack function.
- Implemented tests for the new button functionality and error handling in the CurrentDutyView component.
- Updated localization messages to include the new "Open calendar" label in both English and Russian.
- Refactored layout and styling for better user experience and accessibility.
This commit is contained in:
2026-03-04 11:22:45 +03:00
parent 6adec62b5f
commit d99912b080
3 changed files with 81 additions and 23 deletions

View File

@@ -166,15 +166,14 @@ export function CurrentDutyView({ onBack, openedFromPin = false }: CurrentDutyVi
aria-label={t("loading")}
>
<Card className="current-duty-card w-full max-w-[var(--max-width-app)] border-t-4 border-t-duty">
<CardHeader>
<CardContent className="flex flex-col gap-4 pt-6">
<div className="flex items-center gap-2">
<Skeleton className="size-2.5 shrink-0 rounded-full" />
<Skeleton className="h-5 w-32" />
<Skeleton className="size-2 shrink-0 rounded-full" />
<Skeleton className="h-5 w-24 rounded-full" />
</div>
</CardHeader>
<CardContent className="flex flex-col gap-4 pt-1">
<div className="flex flex-col gap-2">
<Skeleton className="h-6 w-48" />
<Skeleton className="h-7 w-48" />
<Skeleton className="h-4 w-full max-w-[200px]" />
<Skeleton className="h-4 w-full max-w-[280px]" />
</div>
<Skeleton className="h-14 w-full rounded-lg" />
@@ -246,10 +245,17 @@ export function CurrentDutyView({ onBack, openedFromPin = false }: CurrentDutyVi
{t("current_duty.no_duty")}
</p>
</CardContent>
<CardFooter>
<CardFooter className="flex flex-col gap-2 sm:flex-row sm:justify-end">
<Button onClick={handlePrimaryAction} aria-label={primaryButtonAriaLabel}>
{primaryButtonLabel}
</Button>
<Button
variant="outline"
onClick={onBack}
aria-label={t("current_duty.open_calendar")}
>
{t("current_duty.open_calendar")}
</Button>
</CardFooter>
</Card>
</div>
@@ -287,41 +293,45 @@ export function CurrentDutyView({ onBack, openedFromPin = false }: CurrentDutyVi
role="article"
aria-labelledby="current-duty-title"
>
<CardHeader>
<CardTitle
id="current-duty-title"
className="flex items-center gap-2"
>
<span
className="inline-block size-2.5 shrink-0 rounded-full bg-duty animate-pulse motion-reduce:animate-none"
aria-hidden
/>
{t("current_duty.title")}
</CardTitle>
<CardHeader className="sr-only">
<CardTitle id="current-duty-title">{t("current_duty.title")}</CardTitle>
</CardHeader>
<CardContent className="flex flex-col gap-4 pt-1">
<CardContent className="flex flex-col gap-4 pt-6">
<span
className="inline-flex w-fit items-center gap-2 rounded-full bg-duty/15 px-2.5 py-1 text-xs font-medium text-foreground"
aria-hidden
>
<span className="size-2 shrink-0 rounded-full bg-duty animate-pulse motion-reduce:animate-none" />
{t("duty.now_on_duty")}
</span>
<section className="flex flex-col gap-2" aria-label={t("current_duty.shift")}>
<p
className="text-lg font-semibold text-foreground leading-tight"
className="text-xl font-bold text-foreground leading-tight"
id="current-duty-name"
>
{duty.full_name}
</p>
<p className="text-sm text-muted-foreground break-words">
{shiftLabel} {shiftStr}
{shiftLabel}
</p>
<p className="text-sm text-muted-foreground break-words">
{shiftStr}
</p>
</section>
<div
className="rounded-lg bg-duty/10 px-3 py-2.5 flex flex-col gap-0.5"
className="rounded-lg bg-duty/10 px-3 py-2.5 flex flex-col gap-1"
aria-live="polite"
aria-atomic="true"
>
<span className="text-xs text-muted-foreground">
{t("current_duty.remaining_label")}
</span>
<span className="text-base font-semibold text-foreground tabular-nums">
<span className="text-xl font-semibold text-foreground tabular-nums">
{remainingValueStr}
</span>
<span className="text-xs text-muted-foreground">
{t("current_duty.ends_at", { time: formatHHMM(duty.end_at) })}
</span>
</div>
<section className="flex flex-col gap-2 border-t border-border/50 pt-4" aria-label={t("contact.label")}>
{hasContacts ? (