mirror of
https://git.meshkee.com/Meshkee/dashboards.git
synced 2026-08-12 06:40:57 +04:30
Make public invoices RTL for Farsi businesses and fix invoice back-arrow direction.
Also add optional English name fields on the add-customer modal to match the API. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
co-authored by
Cursor
parent
a50685ec69
commit
f21041b950
@@ -1,3 +1,7 @@
|
||||
.wideModal {
|
||||
max-width: min(800px, calc(100vw - 32px));
|
||||
}
|
||||
|
||||
.formGrid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
@@ -8,15 +12,29 @@
|
||||
grid-column: 1 / -1;
|
||||
}
|
||||
|
||||
.hint {
|
||||
margin-bottom: 12px;
|
||||
font-size: 12px;
|
||||
line-height: 1.45;
|
||||
.keyPoints {
|
||||
margin: 0 0 14px;
|
||||
padding-inline-start: 1.15em;
|
||||
list-style: disc;
|
||||
font-size: 12.5px;
|
||||
line-height: 1.5;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
@media (max-width: 520px) {
|
||||
.keyPoints li {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.keyPoints li + li {
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.formGrid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.keyPoints li {
|
||||
white-space: normal;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,8 @@ export function AddCustomerModal({ open, onClose, onCreated }: AddCustomerModalP
|
||||
const [closing, setClosing] = useState(false)
|
||||
const [firstName, setFirstName] = useState('')
|
||||
const [lastName, setLastName] = useState('')
|
||||
const [firstNameEn, setFirstNameEn] = useState('')
|
||||
const [lastNameEn, setLastNameEn] = useState('')
|
||||
const [cellNumber, setCellNumber] = useState('')
|
||||
const [password, setPassword] = useState('')
|
||||
const [passwordConfirm, setPasswordConfirm] = useState('')
|
||||
@@ -40,6 +42,8 @@ export function AddCustomerModal({ open, onClose, onCreated }: AddCustomerModalP
|
||||
setClosing(false)
|
||||
setFirstName('')
|
||||
setLastName('')
|
||||
setFirstNameEn('')
|
||||
setLastNameEn('')
|
||||
setCellNumber('')
|
||||
setPassword('')
|
||||
setPasswordConfirm('')
|
||||
@@ -86,6 +90,16 @@ export function AddCustomerModal({ open, onClose, onCreated }: AddCustomerModalP
|
||||
}
|
||||
}
|
||||
|
||||
const trimmedFirstEn = firstNameEn.trim()
|
||||
const trimmedLastEn = lastNameEn.trim()
|
||||
if (
|
||||
(trimmedFirstEn && trimmedFirstEn.length < 2) ||
|
||||
(trimmedLastEn && trimmedLastEn.length < 2)
|
||||
) {
|
||||
setError(t('customers.addModal.errorNameEnLength'))
|
||||
return
|
||||
}
|
||||
|
||||
setIsSubmitting(true)
|
||||
setError('')
|
||||
try {
|
||||
@@ -93,6 +107,8 @@ export function AddCustomerModal({ open, onClose, onCreated }: AddCustomerModalP
|
||||
cellNumber: normalizedCell,
|
||||
firstName: firstName.trim(),
|
||||
lastName: lastName.trim(),
|
||||
...(trimmedFirstEn ? { firstNameEn: trimmedFirstEn } : {}),
|
||||
...(trimmedLastEn ? { lastNameEn: trimmedLastEn } : {}),
|
||||
...(trimmedPassword ? { password: trimmedPassword } : {}),
|
||||
})
|
||||
onCreated({
|
||||
@@ -119,7 +135,7 @@ export function AddCustomerModal({ open, onClose, onCreated }: AddCustomerModalP
|
||||
onClick={onClose}
|
||||
>
|
||||
<div
|
||||
className={`${modalStyles.modal} ${closing ? modalStyles.modalOut : modalStyles.modalIn}`}
|
||||
className={`${modalStyles.modal} ${formStyles.wideModal} ${closing ? modalStyles.modalOut : modalStyles.modalIn}`}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
@@ -132,7 +148,6 @@ export function AddCustomerModal({ open, onClose, onCreated }: AddCustomerModalP
|
||||
<h3 id="add-customer-title" className={modalStyles.title}>
|
||||
{t('customers.addModal.title')}
|
||||
</h3>
|
||||
<p className={modalStyles.subtitle}>{t('customers.addModal.subtitle')}</p>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
@@ -145,29 +160,58 @@ export function AddCustomerModal({ open, onClose, onCreated }: AddCustomerModalP
|
||||
</div>
|
||||
|
||||
<div className={modalStyles.body}>
|
||||
<p className={formStyles.hint}>{t('customers.addModal.hint')}</p>
|
||||
<ul className={formStyles.keyPoints}>
|
||||
<li>{t('customers.addModal.pointCreate')}</li>
|
||||
<li>{t('customers.addModal.pointPassword')}</li>
|
||||
</ul>
|
||||
|
||||
{error && <p className={modalStyles.errorText}>{error}</p>}
|
||||
|
||||
<div className={formStyles.formGrid}>
|
||||
<div className={modalStyles.field}>
|
||||
<label htmlFor="add-customer-first-name">{t('customers.addModal.firstName')}</label>
|
||||
<label htmlFor="add-customer-first-name">{t('customers.addModal.firstNameFa')}</label>
|
||||
<input
|
||||
id="add-customer-first-name"
|
||||
value={firstName}
|
||||
onChange={(e) => setFirstName(e.target.value)}
|
||||
disabled={isSubmitting}
|
||||
dir={isFa ? 'rtl' : 'ltr'}
|
||||
dir="rtl"
|
||||
lang="fa"
|
||||
className="faText"
|
||||
/>
|
||||
</div>
|
||||
<div className={modalStyles.field}>
|
||||
<label htmlFor="add-customer-last-name">{t('customers.addModal.lastName')}</label>
|
||||
<label htmlFor="add-customer-last-name">{t('customers.addModal.lastNameFa')}</label>
|
||||
<input
|
||||
id="add-customer-last-name"
|
||||
value={lastName}
|
||||
onChange={(e) => setLastName(e.target.value)}
|
||||
disabled={isSubmitting}
|
||||
dir={isFa ? 'rtl' : 'ltr'}
|
||||
dir="rtl"
|
||||
lang="fa"
|
||||
className="faText"
|
||||
/>
|
||||
</div>
|
||||
<div className={modalStyles.field}>
|
||||
<label htmlFor="add-customer-first-name-en">{t('customers.addModal.firstNameEn')}</label>
|
||||
<input
|
||||
id="add-customer-first-name-en"
|
||||
value={firstNameEn}
|
||||
onChange={(e) => setFirstNameEn(e.target.value)}
|
||||
disabled={isSubmitting}
|
||||
dir="ltr"
|
||||
lang="en"
|
||||
/>
|
||||
</div>
|
||||
<div className={modalStyles.field}>
|
||||
<label htmlFor="add-customer-last-name-en">{t('customers.addModal.lastNameEn')}</label>
|
||||
<input
|
||||
id="add-customer-last-name-en"
|
||||
value={lastNameEn}
|
||||
onChange={(e) => setLastNameEn(e.target.value)}
|
||||
disabled={isSubmitting}
|
||||
dir="ltr"
|
||||
lang="en"
|
||||
/>
|
||||
</div>
|
||||
<div className={`${modalStyles.field} ${formStyles.formFull}`}>
|
||||
@@ -233,8 +277,7 @@ export function AddCustomerModal({ open, onClose, onCreated }: AddCustomerModalP
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
,
|
||||
document.body,
|
||||
</div>,
|
||||
document.body,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -192,6 +192,10 @@
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
:global([dir='rtl']) .backLink svg {
|
||||
transform: scaleX(-1);
|
||||
}
|
||||
|
||||
.section {
|
||||
padding: 16px;
|
||||
background: var(--glass-bg);
|
||||
|
||||
@@ -833,8 +833,16 @@ const en = {
|
||||
'Creates a verified customer account or links an existing user to your business.',
|
||||
'customers.addModal.hint':
|
||||
'Password is required only for new accounts. Existing users are added as verified customers.',
|
||||
'customers.addModal.pointCreate':
|
||||
'Creates a verified customer account or links an existing user to your business.',
|
||||
'customers.addModal.pointPassword':
|
||||
'Password is required only for new accounts. Existing users are added as verified customers.',
|
||||
'customers.addModal.firstName': 'First name',
|
||||
'customers.addModal.lastName': 'Last name',
|
||||
'customers.addModal.firstNameFa': 'First name (FA)',
|
||||
'customers.addModal.lastNameFa': 'Last name (FA)',
|
||||
'customers.addModal.firstNameEn': 'First name (EN)',
|
||||
'customers.addModal.lastNameEn': 'Last name (EN)',
|
||||
'customers.addModal.cell': 'Cell number',
|
||||
'customers.addModal.cellPlaceholder': '0912...',
|
||||
'customers.addModal.password': 'Password (new users)',
|
||||
@@ -846,6 +854,7 @@ const en = {
|
||||
'customers.addModal.error': 'Unable to add customer.',
|
||||
'customers.addModal.errorPasswordMatch': 'Passwords do not match.',
|
||||
'customers.addModal.errorPasswordLength': 'Password must be at least 8 characters.',
|
||||
'customers.addModal.errorNameEnLength': 'English names must be at least 2 characters.',
|
||||
'customers.access.title': 'Change access',
|
||||
'customers.access.subtitle': 'Choose customer or manager access for {name}.',
|
||||
'customers.access.customer': 'Customer',
|
||||
@@ -2434,8 +2443,16 @@ const fa: Record<MessageKey, string> = {
|
||||
'یک حساب تأییدشده مشتری میسازد یا کاربر موجود را به کسبوکار شما وصل میکند.',
|
||||
'customers.addModal.hint':
|
||||
'رمز عبور فقط برای حسابهای جدید لازم است. کاربران موجود بهعنوان مشتری تأییدشده اضافه میشوند.',
|
||||
'customers.addModal.pointCreate':
|
||||
'یک حساب تأییدشده مشتری میسازد یا کاربر موجود را به کسبوکار شما وصل میکند.',
|
||||
'customers.addModal.pointPassword':
|
||||
'رمز عبور فقط برای حسابهای جدید لازم است. کاربران موجود بهعنوان مشتری تأییدشده اضافه میشوند.',
|
||||
'customers.addModal.firstName': 'نام',
|
||||
'customers.addModal.lastName': 'نام خانوادگی',
|
||||
'customers.addModal.firstNameFa': 'نام (فارسی)',
|
||||
'customers.addModal.lastNameFa': 'نام خانوادگی (فارسی)',
|
||||
'customers.addModal.firstNameEn': 'نام (انگلیسی)',
|
||||
'customers.addModal.lastNameEn': 'نام خانوادگی (انگلیسی)',
|
||||
'customers.addModal.cell': 'شماره موبایل',
|
||||
'customers.addModal.cellPlaceholder': '۰۹۱۲...',
|
||||
'customers.addModal.password': 'رمز عبور (کاربران جدید)',
|
||||
@@ -2447,6 +2464,7 @@ const fa: Record<MessageKey, string> = {
|
||||
'customers.addModal.error': 'افزودن مشتری ممکن نشد.',
|
||||
'customers.addModal.errorPasswordMatch': 'رمزهای عبور یکسان نیستند.',
|
||||
'customers.addModal.errorPasswordLength': 'رمز عبور باید حداقل ۸ کاراکتر باشد.',
|
||||
'customers.addModal.errorNameEnLength': 'نام انگلیسی باید حداقل ۲ کاراکتر باشد.',
|
||||
'customers.access.title': 'تغییر دسترسی',
|
||||
'customers.access.subtitle': 'دسترسی مشتری یا مدیر را برای {name} انتخاب کنید.',
|
||||
'customers.access.customer': 'مشتری',
|
||||
|
||||
@@ -76,6 +76,8 @@ export interface CreateCustomerPayload {
|
||||
cellNumber: string
|
||||
firstName: string
|
||||
lastName: string
|
||||
firstNameEn?: string
|
||||
lastNameEn?: string
|
||||
password?: string
|
||||
email?: string
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user