refactor: update pricing input handling to use PriceInput component

- Replaced raw input fields for pricing with PriceInput component across various forms and modals to ensure consistent formatting and accessibility.
- Updated tests to reflect changes in pricing input handling, ensuring values are displayed in toman with proper formatting.
- Enhanced accessibility by adding aria-labels and aria-invalid attributes to PriceInput components.
- Adjusted UI elements to improve layout and user experience, particularly in forms related to service items and scheduling.
- Changed labels from "نمایش در نوبت‌دهی" to "نمایش در نوبت‌دهی آنلاین" for clarity.
This commit is contained in:
hamed
2026-08-09 08:38:23 +03:30
parent e48ab9a974
commit b49abee52f
18 changed files with 299 additions and 96 deletions
@@ -35,6 +35,9 @@ const renderStep = (onCreated = vi.fn()) => {
return onCreated;
};
/** PriceInput مبلغ را با جداکنندهٔ fa-IR نشان می‌دهد، نه رقمِ خام. */
const fa = (n: number) => new Intl.NumberFormat('fa-IR').format(n);
describe('CreateStep — الزامی بودن قیمت ویزیت با فلگ require_visit_price', () => {
it('فلگ فعال + قیمت صفر → خطای inline، ستاره روی label و عدم ارسال', async () => {
mockEndpoints({ free_visit_price_rials: 0, require_visit_price: true });
@@ -78,7 +81,7 @@ describe('CreateStep — الزامی بودن قیمت ویزیت با فلگ r
mockEndpoints({ free_visit_price_rials: 300_000, require_visit_price: false });
renderStep();
await waitFor(() => expect(screen.getByLabelText('قیمت ویزیت')).toHaveValue('30000'));
await waitFor(() => expect(screen.getByLabelText('قیمت ویزیت')).toHaveValue(fa(30_000)));
});
});
@@ -171,7 +174,7 @@ describe('CreateStep — نوع خدمت بیمه', () => {
);
// ۵٬۹۵۲٬۰۰۰ ریال = ۵۹۵٬۲۰۰ تومان (ورودی قیمت ویزیت رقم خام است)
await waitFor(() => expect(screen.getByLabelText('قیمت ویزیت')).toHaveValue('595200'));
await waitFor(() => expect(screen.getByLabelText('قیمت ویزیت')).toHaveValue(fa(595_200)));
expect(screen.queryByText('نوع خدمت')).not.toBeInTheDocument();
});
@@ -215,7 +218,7 @@ describe('CreateStep — نمایش و پیش‌انتخاب بیمه', () => {
<CreateStep recordUuid="r-1" profile={null} onCreated={vi.fn()} onCancel={() => {}} />,
);
await waitFor(() => expect(screen.getByLabelText('قیمت ویزیت')).toHaveValue('30000'));
await waitFor(() => expect(screen.getByLabelText('قیمت ویزیت')).toHaveValue(fa(30_000)));
expect(screen.queryByText('بیمه پایه')).not.toBeInTheDocument();
});
@@ -7,6 +7,7 @@ import type { ApiResponse } from '../../lib/api';
import type { PatientProfile, ServiceSection, ServiceItem } from '../../types';
import { formatRial, rialToToman, tomanToRial } from '../../lib/utils';
import SearchableSelect from '../ui/SearchableSelect';
import PriceInput from '../ui/PriceInput';
import PersianDateInput from '../ui/PersianDateInput';
import { UserTick, FilesServiceAddCard, ClockP, TrashRed } from '../icons/FilesServiceIcons';
import { useAuthStore } from '../../stores/authStore';
@@ -479,11 +480,12 @@ export default function CreateStep({ recordUuid, profile, onCreated, onCancel, e
<span style={fieldLabel}>
قیمت ویزیت (تومان){requireVisit && <span style={{ color: 'var(--danger)' }}> *</span>}
</span>
<input
className="input" type="text" inputMode="numeric" dir="ltr" aria-label="قیمت ویزیت"
aria-invalid={!!visitPriceError}
value={visitPrice}
onChange={(e) => { setVisitPrice(digitsOnly(e.target.value)); setVisitPriceError(''); }}
<PriceInput
className="input"
ariaLabel="قیمت ویزیت"
ariaInvalid={!!visitPriceError}
value={visitPrice === '' ? '' : Number(visitPrice)}
onChange={(v) => { setVisitPrice(String(v)); setVisitPriceError(''); }}
/>
{visitPriceError && (
<span style={{ fontSize: 12, color: 'var(--danger)', display: 'block', marginTop: 4 }}>{visitPriceError}</span>