feature: localization's first implmentation done. all frontend hardcoded text is now localized.

This commit is contained in:
2026-06-20 14:51:43 +03:30
parent 284fbd08aa
commit b2f4dfa4ca
52 changed files with 3306 additions and 1041 deletions

View File

@@ -1,8 +1,17 @@
'use client';
import { useTranslations } from 'next-intl';
import { Button } from '@/components/ui/shared/Button';
import type { PastTreatment } from '@/types/treatment';
const TREATMENT_TYPE_KEYS = {
consultation: 'typeConsultation',
filling: 'typeFilling',
endo: 'typeEndo',
visit: 'typeVisit',
hygiene: 'typeHygiene',
} as const;
interface TreatmentPreviewCardProps {
draft: PastTreatment | null;
disabled?: boolean;
@@ -10,16 +19,22 @@ interface TreatmentPreviewCardProps {
}
export function TreatmentPreviewCard({ draft, disabled, onPreview }: TreatmentPreviewCardProps) {
const t = useTranslations('treatment');
const attachmentCount = draft
? draft.cases.reduce((n, c) => n + (c.attachmentMetas?.length ?? 0), 0)
: 0;
return (
<div className="surface-card p-4 space-y-3">
<div className="flex items-center justify-between gap-2">
<h3 className="text-sm font-semibold text-text-primary">Treatment preview</h3>
<h3 className="text-sm font-semibold text-text-primary">{t('previewTitle')}</h3>
<Button type="button" variant="primary" disabled={disabled || !draft} onClick={onPreview}>
Preview current draft
{t('previewDraft')}
</Button>
</div>
{!draft ? (
<p className="text-sm text-text-muted">Select an appointment to preview its draft.</p>
<p className="text-sm text-text-muted">{t('selectAppointment')}</p>
) : (
<div className="border border-border/70 rounded-[var(--radius-md)] p-3 bg-background-secondary/40 space-y-2">
<div className="flex items-start justify-between gap-2">
@@ -27,26 +42,31 @@ export function TreatmentPreviewCard({ draft, disabled, onPreview }: TreatmentPr
<span className="text-xs text-text-muted tabular-nums shrink-0 capitalize">{draft.status}</span>
</div>
<p className="text-xs text-text-secondary">
{draft.cases.length} case{draft.cases.length === 1 ? '' : 's'} ·{' '}
{draft.cases.reduce((n, c) => n + (c.attachmentMetas?.length ?? 0), 0)} attachment
{draft.cases.reduce((n, c) => n + (c.attachmentMetas?.length ?? 0), 0) === 1 ? '' : 's'}
{t('caseCount', { n: draft.cases.length })} ·{' '}
{t('attachmentCount', { n: attachmentCount })}
</p>
<div className="space-y-2">
{draft.cases.slice(0, 2).map((c, idx) => (
{draft.cases.slice(0, 2).map((c, idx) => {
const typeKey = TREATMENT_TYPE_KEYS[c.treatmentType as keyof typeof TREATMENT_TYPE_KEYS];
const typeLabel = typeKey ? t(typeKey) : c.treatmentType;
return (
<div
key={c.id}
className="rounded-[var(--radius-sm)] border border-border/60 px-2.5 py-2 text-xs text-text-secondary"
>
<span className="text-text-primary font-medium capitalize">
Case {idx + 1}: {c.treatmentType}
{t('caseSummary', { n: idx + 1, type: typeLabel })}
</span>
{c.teeth.length > 0 && (
<span className="ml-1 tabular-nums">· Teeth {[...c.teeth].sort().join(', ')}</span>
<span className="ml-1 tabular-nums">
{t('teethPrefix')} {[...c.teeth].sort().join(', ')}
</span>
)}
</div>
))}
);
})}
{draft.cases.length > 2 && (
<p className="text-xs text-text-muted">+ {draft.cases.length - 2} more case(s)</p>
<p className="text-xs text-text-muted">{t('moreCases', { n: draft.cases.length - 2 })}</p>
)}
</div>
</div>