feature: localization's first implmentation done. all frontend hardcoded text is now localized.
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
'use client';
|
||||
|
||||
import { useRef, useState } from 'react';
|
||||
import { useTranslations } from 'next-intl';
|
||||
import { Loader2, Paperclip, Send } from 'lucide-react';
|
||||
import { DialogCloseButton } from '@/components/ui/shared/DialogCloseButton';
|
||||
import { Button } from '@/components/ui/shared/Button';
|
||||
@@ -32,6 +33,14 @@ function caseKey(c: PastTreatmentCase): string {
|
||||
const caseActionIconClass =
|
||||
'inline-flex items-center justify-center rounded-[var(--radius-sm)] p-1.5 text-text-secondary transition-colors hover:bg-background-card/80 hover:text-text-primary disabled:cursor-not-allowed disabled:opacity-40';
|
||||
|
||||
const TREATMENT_TYPE_KEYS = {
|
||||
consultation: 'typeConsultation',
|
||||
filling: 'typeFilling',
|
||||
endo: 'typeEndo',
|
||||
visit: 'typeVisit',
|
||||
hygiene: 'typeHygiene',
|
||||
} as const;
|
||||
|
||||
export function TreatmentPreviewDialog({
|
||||
open,
|
||||
onClose,
|
||||
@@ -45,6 +54,7 @@ export function TreatmentPreviewDialog({
|
||||
getCaseOrgIds,
|
||||
onToggleCaseOrg,
|
||||
}: TreatmentPreviewDialogProps) {
|
||||
const t = useTranslations('treatment');
|
||||
const [expandedSendCaseId, setExpandedSendCaseId] = useState<string | null>(null);
|
||||
const fileInputsRef = useRef<Record<string, HTMLInputElement | null>>({});
|
||||
|
||||
@@ -64,10 +74,10 @@ export function TreatmentPreviewDialog({
|
||||
<div className="flex items-start justify-between gap-3">
|
||||
<div className="min-w-0">
|
||||
<h2 id="treatment-preview-title" className="text-lg font-semibold text-text-primary pr-2">
|
||||
Treatment preview
|
||||
{t('previewDialogTitle')}
|
||||
</h2>
|
||||
<p className="text-xs text-text-muted mt-0.5">
|
||||
Review cases, attachments, and send destinations.
|
||||
{t('previewDialogSubtitle')}
|
||||
</p>
|
||||
</div>
|
||||
<DialogCloseButton onClick={onClose} />
|
||||
@@ -80,10 +90,12 @@ export function TreatmentPreviewDialog({
|
||||
{new Date(treatment.treatmentAt).toLocaleDateString()}
|
||||
</span>
|
||||
</div>
|
||||
<p className="text-xs text-text-secondary capitalize">Status: {treatment.status}</p>
|
||||
<p className="text-xs text-text-secondary capitalize">
|
||||
{t('statusLabel')} {treatment.status}
|
||||
</p>
|
||||
|
||||
{treatment.cases.length === 0 ? (
|
||||
<p className="text-sm text-text-muted">No cases in this treatment.</p>
|
||||
<p className="text-sm text-text-muted">{t('noCases')}</p>
|
||||
) : (
|
||||
<div className="space-y-2">
|
||||
{treatment.cases.map((c, idx) => {
|
||||
@@ -98,6 +110,8 @@ export function TreatmentPreviewDialog({
|
||||
const comment = c.notes?.trim() ?? '';
|
||||
const attachBusy = uploadBusyCaseId === key;
|
||||
const sendBusy = sendBusyCaseId === key;
|
||||
const typeKey = TREATMENT_TYPE_KEYS[c.treatmentType as keyof typeof TREATMENT_TYPE_KEYS];
|
||||
const typeLabel = typeKey ? t(typeKey) : c.treatmentType;
|
||||
|
||||
return (
|
||||
<div
|
||||
@@ -107,7 +121,9 @@ export function TreatmentPreviewDialog({
|
||||
<div className="grid grid-cols-[minmax(0,1fr)_auto] gap-x-4 gap-y-1">
|
||||
<div className="min-w-0 space-y-0.5">
|
||||
<div className="flex items-center gap-2">
|
||||
<p className="text-xs font-medium text-text-primary">Case {idx + 1}</p>
|
||||
<p className="text-xs font-medium text-text-primary">
|
||||
{t('caseLabel', { n: idx + 1 })}
|
||||
</p>
|
||||
{actionsEnabled && (
|
||||
<div className="flex items-center gap-0.5">
|
||||
<input
|
||||
@@ -129,8 +145,8 @@ export function TreatmentPreviewDialog({
|
||||
type="button"
|
||||
className={caseActionIconClass}
|
||||
disabled={attachBusy}
|
||||
aria-label="Attach files"
|
||||
title="Attach files"
|
||||
aria-label={t('attachFilesShort')}
|
||||
title={t('attachFilesShort')}
|
||||
onClick={() => fileInputsRef.current[key]?.click()}
|
||||
>
|
||||
{attachBusy ? (
|
||||
@@ -145,8 +161,8 @@ export function TreatmentPreviewDialog({
|
||||
sendExpanded ? 'bg-primary-soft text-primary' : ''
|
||||
}`}
|
||||
disabled={sendBusy}
|
||||
aria-label="Send this case"
|
||||
title="Send this case"
|
||||
aria-label={t('sendCase')}
|
||||
title={t('sendCase')}
|
||||
aria-expanded={sendExpanded}
|
||||
onClick={() =>
|
||||
setExpandedSendCaseId((prev) => (prev === key ? null : key))
|
||||
@@ -162,18 +178,18 @@ export function TreatmentPreviewDialog({
|
||||
)}
|
||||
</div>
|
||||
<p className="text-[11px] text-text-secondary capitalize">
|
||||
Type: {c.treatmentType}
|
||||
{t('typeLabel')} {typeLabel}
|
||||
</p>
|
||||
<p className="text-[11px] text-text-secondary">
|
||||
Teeth:{' '}
|
||||
{c.teeth.length ? [...c.teeth].sort().join(', ') : 'None selected'}
|
||||
{t('teethLabel')}{' '}
|
||||
{c.teeth.length ? [...c.teeth].sort().join(', ') : t('teethNone')}
|
||||
</p>
|
||||
{comment ? (
|
||||
<p className="text-[11px] text-text-muted line-clamp-2" title={comment}>
|
||||
Comments: {comment}
|
||||
{t('commentsLabel')} {comment}
|
||||
</p>
|
||||
) : (
|
||||
<p className="text-[11px] text-text-muted">Comments: —</p>
|
||||
<p className="text-[11px] text-text-muted">{t('commentsEmpty')}</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -186,7 +202,7 @@ export function TreatmentPreviewDialog({
|
||||
/>
|
||||
)}
|
||||
<p className="text-[10px] uppercase tracking-wide text-text-muted">
|
||||
Attachments
|
||||
{t('attachments')}
|
||||
</p>
|
||||
<TreatmentLatestAttachmentPreview attachment={latestAttachment} />
|
||||
</div>
|
||||
@@ -195,10 +211,10 @@ export function TreatmentPreviewDialog({
|
||||
{sendExpanded && editable && !sent && (
|
||||
<div className="mt-2 space-y-2 border-t border-border/40 pt-2">
|
||||
<p className="text-xs font-medium text-text-secondary">
|
||||
Send to linked organizations
|
||||
{t('sendToLinkedOrgs')}
|
||||
</p>
|
||||
{activeOrgs.length === 0 ? (
|
||||
<p className="text-xs text-text-muted">No active linked organizations.</p>
|
||||
<p className="text-xs text-text-muted">{t('noActiveOrgs')}</p>
|
||||
) : (
|
||||
<div className="flex flex-col gap-1.5">
|
||||
{activeOrgs.map((o) => (
|
||||
@@ -219,7 +235,7 @@ export function TreatmentPreviewDialog({
|
||||
isLoading={sendBusy}
|
||||
onClick={() => void onSend?.(key, selectedOrgIds)}
|
||||
>
|
||||
Confirm send
|
||||
{t('confirmSend')}
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user