improvement: rtl direction, solar calendar and persian formatting added for persian users.

This commit is contained in:
2026-07-14 01:27:11 +03:30
parent 27eae25f61
commit ec2b23f4b1
50 changed files with 1410 additions and 528 deletions

View File

@@ -247,7 +247,7 @@ export function CaseDetailPanel({
onAssignTask(task.id, e.target.value ? e.target.value : null)
}
aria-label={t('assigneeLabel')}
className={`${FORM_SELECT_CLASS} max-w-[9.5rem] rounded-md px-2 py-0.5 text-xs`}
className={`${FORM_SELECT_CLASS} max-w-[9.5rem] rounded-md py-0.5 text-xs`}
>
<option value="">{t('assigneeUnassigned')}</option>
{assignableStaff.map((staff) => (

View File

@@ -25,6 +25,7 @@ import { Button } from '@/components/ui/shared/Button';
import { MobileDetailBackButton } from '@/components/ui/shared/MobileDetailBackButton';
import { FORM_SELECT_CLASS } from '@/components/shared/formSelectStyles';
import { SearchBar } from '@/components/ui/shared/SearchBar';
import { AppDateInput } from '@/components/ui/shared/AppDateInput';
import type { TreatmentCatalogEntry } from '@/types/treatment-catalog';
import type {
AssignableTaskStaff,
@@ -267,7 +268,7 @@ export function CasesPage() {
}
}
const filterSelectClass = `${FORM_SELECT_CLASS} w-full rounded-md px-3 py-2`;
const filterSelectClass = `${FORM_SELECT_CLASS} w-full min-w-0 rounded-md py-1.5 text-xs sm:py-2 sm:text-sm`;
return (
<div className="space-y-4">
@@ -333,11 +334,10 @@ export function CasesPage() {
<label className="space-y-1">
<span className="text-xs font-medium text-text-muted">{t('filterSentFrom')}</span>
<input
type="date"
<AppDateInput
value={sentFrom}
onChange={(e) => {
setSentFrom(e.target.value);
onChange={(next) => {
setSentFrom(next);
setPage(1);
}}
className={filterSelectClass}
@@ -346,11 +346,10 @@ export function CasesPage() {
<label className="space-y-1">
<span className="text-xs font-medium text-text-muted">{t('filterSentTo')}</span>
<input
type="date"
<AppDateInput
value={sentTo}
onChange={(e) => {
setSentTo(e.target.value);
onChange={(next) => {
setSentTo(next);
setPage(1);
}}
className={filterSelectClass}

View File

@@ -5,6 +5,7 @@ import { Badge } from '@/components/ui/shared/Badge';
import { LabCaseDueDateBadge } from '@/components/lab/LabCaseDueDateBadge';
import type { CaseTaskGroup } from '@/components/lab/taskListGrouping';
import { countCaseTaskProgress } from '@/components/lab/taskListGrouping';
import { formatAppDate, APP_DATE } from '@/lib/i18n/format';
function formatPatientName(patient: { firstName: string; lastName: string }) {
return `${patient.firstName} ${patient.lastName}`.trim();
@@ -20,11 +21,7 @@ export function TaskCaseGroupHeader({ caseGroup, locale }: TaskCaseGroupHeaderPr
const progress = countCaseTaskProgress(caseGroup);
const sentLabel = caseGroup.caseSentAt
? new Intl.DateTimeFormat(locale, {
year: 'numeric',
month: 'short',
day: 'numeric',
}).format(new Date(caseGroup.caseSentAt))
? formatAppDate(caseGroup.caseSentAt, locale, APP_DATE.short)
: null;
return (

View File

@@ -12,6 +12,7 @@ import {
labTaskStatusVariant,
} from '@/components/lab/labTaskStatusDisplay';
import { LabCaseDueDateBadge } from '@/components/lab/LabCaseDueDateBadge';
import { formatAppDate, APP_DATE } from '@/lib/i18n/format';
import { notifyTabBadgesChanged } from '@/lib/tabBadgeUtils';
import {
formatToothList,
@@ -64,11 +65,7 @@ export function TaskRow({
const canEditStatus = canEditLabTaskStatus(task, currentUserId, canEdit);
const assignedToOther =
Boolean(task.assignee) && task.assignee!.id !== currentUserId;
const taskDate = new Intl.DateTimeFormat(locale, {
year: 'numeric',
month: 'short',
day: 'numeric',
}).format(new Date(task.createdAt));
const taskDate = formatAppDate(task.createdAt, locale, APP_DATE.short);
const rowClassName = [
flatMode ? undefined : 'border-b border-border/40 last:border-b-0',

View File

@@ -4,7 +4,7 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { useTranslations } from 'next-intl';
import { Button } from '@/components/ui/shared/Button';
import { Checkbox } from '@/components/ui/shared/Checkbox';
import { FORM_SELECT_CLASS } from '@/components/shared/formSelectStyles';
import { FORM_SELECT_CLASS, FORM_SELECT_COMPACT_CLASS } from '@/components/shared/formSelectStyles';
import { SearchBar } from '@/components/ui/shared/SearchBar';
import { TaskCaseGroupHeader } from '@/components/ui/lab/TaskCaseGroupHeader';
import { TaskProsthesisGroupHeader } from '@/components/ui/lab/TaskProsthesisGroupHeader';
@@ -286,7 +286,7 @@ export function TasksPage() {
[canEdit, loadTasks, setError, showError, showSuccess, statusFilter, t, tErrors],
);
const filterSelectClass = `${FORM_SELECT_CLASS} w-full min-h-[44px] rounded-md px-2 py-2 text-base sm:min-h-0 sm:py-1.5 sm:text-sm`;
const filterSelectClass = `${FORM_SELECT_CLASS} w-full min-w-0 rounded-md py-1.5 text-xs sm:py-2 sm:text-sm`;
const sortHintKey = useMemo(() => {
switch (sortBy) {
@@ -366,7 +366,8 @@ export function TasksPage() {
onChange={(v) => applyFilterChange(() => setSearch(v))}
placeholder={t('searchPlaceholder')}
/>
<div className="grid gap-2 sm:grid-cols-2 lg:grid-cols-4">
<div className="overflow-x-auto">
<div className="grid min-w-[44rem] grid-cols-4 gap-2">
<label className="space-y-1">
<span className="text-xs text-text-muted">{t('filterClinic')}</span>
<select
@@ -411,16 +412,16 @@ export function TasksPage() {
))}
</select>
</label>
<label className="space-y-1">
<label className="space-y-1 min-w-0">
<span className="text-xs text-text-muted">{t('sortBy')}</span>
<div className="flex gap-1.5">
<div className="grid grid-cols-[minmax(0,1fr)_auto] gap-1">
<select
value={sortBy}
onChange={(e) => {
setSortBy(e.target.value as TaskSortField);
clearFocus();
}}
className={`${filterSelectClass} min-w-0 flex-1`}
className={`${filterSelectClass} min-w-0`}
>
<option value="date">{t('sortDate')}</option>
<option value="dueDate">{t('sortDueDate')}</option>
@@ -432,7 +433,7 @@ export function TasksPage() {
<select
value={sortDir}
onChange={(e) => setSortDir(e.target.value as 'asc' | 'desc')}
className={`${FORM_SELECT_CLASS} w-14 shrink-0 rounded-md px-2 py-1.5 text-sm`}
className={`${FORM_SELECT_COMPACT_CLASS} w-11 shrink-0 rounded-md py-1.5 text-sm`}
aria-label={t('sortDirection')}
>
<option value="desc"></option>
@@ -440,6 +441,7 @@ export function TasksPage() {
</select>
</div>
</label>
</div>
</div>
<div className="flex flex-wrap items-center gap-x-4 gap-y-2">
<Checkbox