Polish business FA layout and wire special-group keys plus SSL sync.

RTL carousels/FABs, special key+title fields, slider gallery fixes, and dashboard SSL sync agent for super-admin.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Alireza Hassani
2026-08-03 00:06:44 +03:30
co-authored by Cursor
parent 66004a0fba
commit 672091d1f5
113 changed files with 4154 additions and 1451 deletions
+30 -21
View File
@@ -66,14 +66,14 @@ export function AddNewProductPage() {
if (err instanceof ApiError) {
setError(err.message)
} else {
setError('Unable to load form options.')
setError(t('products.form.errorOptions'))
}
}
}
void loadFormOptions()
return () => controller.abort()
}, [])
}, [t])
useEffect(() => {
if (!isEdit || !id) return
@@ -157,7 +157,7 @@ export function AddNewProductPage() {
} else if (err instanceof Error) {
setError(err.message)
} else {
setError('Unable to save product.')
setError(t('products.form.errorSave'))
}
} finally {
setIsSubmitting(false)
@@ -202,43 +202,44 @@ export function AddNewProductPage() {
<form className={styles.form} onSubmit={handleSubmit}>
<div className={styles.formGrid}>
<div className={`${styles.field} ${styles.col2} ${styles.thumbnailField}`}>
<label>Thumbnail Image</label>
<label>{t('products.form.thumbnail')}</label>
<ImageCropper value={thumbnail} onChange={setThumbnail} />
</div>
<div className={styles.col10}>
<div className={styles.topFields}>
<div className={`${styles.field} ${styles.fieldCategory}`}>
<label>Category</label>
<label>{t('products.form.category')}</label>
<SearchableSelect
options={categoryOptions}
value={categoryId}
onChange={setCategoryId}
placeholder="Search and select category..."
placeholder={t('products.form.categoryPlaceholder')}
/>
</div>
<div className={`${styles.field} ${styles.fieldBrand}`}>
<label>
Brand <span className={styles.optional}>(optional)</span>
{t('products.form.brand')}{' '}
<span className={styles.optional}>{t('products.form.optional')}</span>
</label>
<SearchableSelect
options={brandOptions}
value={brandId}
onChange={setBrandId}
placeholder="Search and select brand..."
placeholder={t('products.form.brandPlaceholder')}
/>
</div>
<div className={`${styles.field} ${styles.fieldHalf}`}>
<label htmlFor="nameFa">Name (FA)</label>
<label htmlFor="nameFa">{t('products.form.nameFa')}</label>
<input
id="nameFa"
name="nameFa"
type="text"
dir="rtl"
className="faText"
placeholder="نام محصول"
placeholder={t('products.form.nameFaPlaceholder')}
value={nameFa}
onChange={(e) => setNameFa(e.target.value)}
required
@@ -247,13 +248,13 @@ export function AddNewProductPage() {
</div>
<div className={`${styles.field} ${styles.fieldHalf}`}>
<label htmlFor="nameEn">Name (EN)</label>
<label htmlFor="nameEn">{t('products.form.nameEn')}</label>
<input
id="nameEn"
name="nameEn"
type="text"
dir="ltr"
placeholder="Product name"
placeholder={t('products.form.nameEnPlaceholder')}
value={nameEn}
onChange={(e) => setNameEn(e.target.value)}
required
@@ -262,12 +263,12 @@ export function AddNewProductPage() {
</div>
<div className={`${styles.field} ${styles.fieldFull} ${styles.summaryField}`}>
<label htmlFor="summary">Summary</label>
<label htmlFor="summary">{t('products.form.summary')}</label>
<textarea
id="summary"
name="summary"
rows={4}
placeholder="Short summary shown in product listings"
placeholder={t('products.form.summaryPlaceholder')}
value={summary}
onChange={(e) => setSummary(e.target.value)}
required
@@ -278,31 +279,39 @@ export function AddNewProductPage() {
</div>
<div className={`${styles.field} ${styles.col12}`}>
<label>Description</label>
<label>{t('products.form.description')}</label>
<RichTextEditor
value={description}
onChange={setDescription}
placeholder="Full product description with formatting..."
placeholder={t('products.form.descriptionPlaceholder')}
/>
</div>
<div className={`${styles.field} ${styles.col12}`}>
<label>Product Images</label>
<label>{t('products.form.images')}</label>
<ImageUploader images={images} onChange={setImages} />
</div>
<div className={`${styles.field} ${styles.col12}`}>
<label>Tags</label>
<TagInput tags={tags} onChange={setTags} />
<label>{t('products.form.tags')}</label>
<TagInput
tags={tags}
onChange={setTags}
placeholder={t('products.form.tagsPlaceholder')}
/>
</div>
</div>
<div className={styles.actions}>
<Link to="/products/list" className={styles.cancelBtn}>
Cancel
{t('products.form.cancel')}
</Link>
<button type="submit" className={styles.submitBtn} disabled={isSubmitting}>
{isSubmitting ? 'Saving...' : isEdit ? 'Update Product' : 'Save Product'}
{isSubmitting
? t('products.form.saving')
: isEdit
? t('products.form.update')
: t('products.form.save')}
</button>
</div>
</form>