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
@@ -5,6 +5,7 @@ import {
Loader2,
Lock,
Pencil,
RefreshCw,
Rocket,
RotateCcw,
Search,
@@ -23,6 +24,7 @@ import {
removeDomain,
setDomainActive,
setDomainSsl,
syncSsl,
updateDomain,
} from '../services/domainService'
import { useToast } from '../context/ToastContext'
@@ -102,6 +104,7 @@ export function WebsitesPage() {
const [togglingActiveId, setTogglingActiveId] = useState<number | null>(null)
const [togglingSslId, setTogglingSslId] = useState<number | null>(null)
const [deployingId, setDeployingId] = useState<DomainListItem['id'] | null>(null)
const [syncingSsl, setSyncingSsl] = useState(false)
useEffect(() => {
const controller = new AbortController()
@@ -260,6 +263,27 @@ export function WebsitesPage() {
}
}
async function handleSyncSsl() {
if (syncingSsl) return
flushSync(() => {
setSyncingSsl(true)
})
setError('')
showToast('Starting SSL sync…', 'info')
try {
const result = await syncSsl()
showToast(result.message || 'SSL sync started.', 'success')
} catch (err) {
const message = err instanceof ApiError ? err.message : 'Unable to start SSL sync.'
setError(message)
showToast(message, 'error')
} finally {
setSyncingSsl(false)
}
}
async function handleDeploy(domain: DomainListItem) {
if (!domain.deploySlug) return
if (deployingId != null) return
@@ -342,6 +366,22 @@ export function WebsitesPage() {
Monitor and manage all domains across the platform.
</p>
</div>
<button
type="button"
className={`${tableStyles.btn} ${tableStyles.btnPrimary} ${
syncingSsl ? styles.deployBusy : ''
}`}
onClick={() => void handleSyncSsl()}
disabled={syncingSsl}
aria-busy={syncingSsl}
>
{syncingSsl ? (
<Loader2 size={16} className={styles.spin} aria-hidden />
) : (
<RefreshCw size={16} aria-hidden />
)}
{syncingSsl ? 'Syncing SSL…' : 'Sync SSL now'}
</button>
</div>
<div className={tableStyles.filtersPanel}>
@@ -1,5 +1,5 @@
import { apiRequest } from '../lib/api'
import type { DeployDomainResponse, DomainsListResponse } from '../types/domain'
import type { DeployDomainResponse, DomainsListResponse, SyncSslResponse } from '../types/domain'
export interface ListDomainsParams {
page?: number
@@ -60,3 +60,10 @@ export async function deployDomain(domainId: number | string) {
auth: true,
})
}
export async function syncSsl() {
return apiRequest<SyncSslResponse>('/domains/ssl-sync', {
method: 'POST',
auth: true,
})
}
+5
View File
@@ -30,3 +30,8 @@ export interface DeployDomainResponse {
lastDeployedAt: string | null
lastDeployStatus: DomainDeployStatus | null
}
export interface SyncSslResponse {
status: 'accepted'
message: string
}