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
+14 -16
View File
@@ -7,6 +7,7 @@ import { Breadcrumbs } from '../components/Breadcrumbs'
import { ConfirmDeleteModal } from '../components/ConfirmDeleteModal'
import { WebsiteSliderGallery } from '../components/WebsiteSliderGallery'
import { useToast } from '../context/ToastContext'
import { useT } from '../i18n/useT'
import { ApiError } from '../lib/api'
import { resolveDataUrlToMediaId } from '../services/mediaService'
import {
@@ -19,9 +20,8 @@ import type { WebsiteSlider, WebsiteSliderSlide } from '../types/websiteSlider'
import pageStyles from '../components/PageContent.module.css'
import styles from './StoreSpecialsPage.module.css'
const DEFAULT_SLIDER_TITLE = 'Homepage slider'
export function WebsiteSlidersPage() {
const t = useT()
const { showToast } = useToast()
const [slider, setSlider] = useState<WebsiteSlider | null>(null)
const [isLoading, setIsLoading] = useState(true)
@@ -48,7 +48,7 @@ export function WebsiteSlidersPage() {
if (err instanceof ApiError) {
setError(err.message)
} else {
setError('Unable to load slides.')
setError(t('website.sliders.errorLoad'))
}
} finally {
setIsLoading(false)
@@ -62,7 +62,7 @@ export function WebsiteSlidersPage() {
try {
const imageMediaId = await resolveDataUrlToMediaId(data.image, 'slider-slide.jpg')
if (!imageMediaId) {
throw new Error('Unable to upload slide image.')
throw new Error(t('website.sliders.errorUpload'))
}
const slideInput = {
@@ -79,21 +79,21 @@ export function WebsiteSlidersPage() {
setSlider(result.slider)
} else {
const result = await createWebsiteSlider({
title: DEFAULT_SLIDER_TITLE,
title: t('website.sliders.defaultTitle'),
slides: [slideInput],
})
setSlider(result.slider)
}
setAddSlideOpen(false)
showToast('Slide added.', 'success')
showToast(t('website.sliders.toastAdded'), 'success')
} catch (err) {
if (err instanceof ApiError) {
setError(err.message)
} else if (err instanceof Error) {
setError(err.message)
} else {
setError('Unable to add slide.')
setError(t('website.sliders.errorAdd'))
}
} finally {
setIsSaving(false)
@@ -114,12 +114,12 @@ export function WebsiteSlidersPage() {
const result = await updateWebsiteSlider(slider.id, { slides: nextSlides })
setSlider(result.slider)
setRemoveTarget(null)
showToast('Slide removed.', 'success')
showToast(t('website.sliders.toastRemoved'), 'success')
} catch (err) {
if (err instanceof ApiError) {
setError(err.message)
} else {
setError('Unable to remove slide.')
setError(t('website.sliders.errorRemove'))
}
} finally {
setIsSaving(false)
@@ -138,17 +138,15 @@ export function WebsiteSlidersPage() {
<div className={pageStyles.pageHeader}>
<div>
<h2 className={pageStyles.pageTitle}>Sliders</h2>
<p className={pageStyles.pageSubtitle}>
Manage homepage banner slides in a 9:4 gallery.
</p>
<h2 className={pageStyles.pageTitle}>{t('title.sliders')}</h2>
<p className={pageStyles.pageSubtitle}>{t('website.sliders.subtitle')}</p>
</div>
</div>
{error && <p className={styles.error}>{error}</p>}
{isLoading ? (
<p className={styles.empty}>Loading slides...</p>
<p className={styles.empty}>{t('website.sliders.loading')}</p>
) : (
<WebsiteSliderGallery
slides={slider?.slides ?? []}
@@ -166,8 +164,8 @@ export function WebsiteSlidersPage() {
<ConfirmDeleteModal
open={!!removeTarget}
title="Remove Slide"
message="Remove this slide from the homepage slider?"
title={t('website.sliders.removeTitle')}
message={t('website.sliders.removeMessage')}
onConfirm={() => void confirmRemoveSlide()}
onCancel={() => !isSaving && setRemoveTarget(null)}
/>