fix: improve code quality in soft-delete frontend (loading state, imports, confirm dialog)

This commit is contained in:
Usman Baig
2026-03-18 11:03:44 +01:00
parent ad1c8c5420
commit 311f546261
2 changed files with 33 additions and 21 deletions

View File

@@ -5,7 +5,7 @@ import Link from 'next/link'
import { motion } from 'framer-motion' import { motion } from 'framer-motion'
import { useAuth } from '@/lib/auth/context' import { useAuth } from '@/lib/auth/context'
import { initiateOAuthFlow, initiateSignupFlow } from '@/lib/api/oauth' import { initiateOAuthFlow, initiateSignupFlow } from '@/lib/api/oauth'
import { listSites, listDeletedSites, restoreSite, permanentDeleteSite, type Site } from '@/lib/api/sites' import { listSites, listDeletedSites, restoreSite, type Site } from '@/lib/api/sites'
import { getStats } from '@/lib/api/stats' import { getStats } from '@/lib/api/stats'
import type { Stats } from '@/lib/api/stats' import type { Stats } from '@/lib/api/stats'
import { getSubscription, type SubscriptionDetails } from '@/lib/api/billing' import { getSubscription, type SubscriptionDetails } from '@/lib/api/billing'
@@ -121,6 +121,7 @@ export default function HomePage() {
const [showFinishSetupBanner, setShowFinishSetupBanner] = useState(true) const [showFinishSetupBanner, setShowFinishSetupBanner] = useState(true)
const [deleteModalSite, setDeleteModalSite] = useState<Site | null>(null) const [deleteModalSite, setDeleteModalSite] = useState<Site | null>(null)
const [deletedSites, setDeletedSites] = useState<Site[]>([]) const [deletedSites, setDeletedSites] = useState<Site[]>([])
const [permanentDeleteSiteModal, setPermanentDeleteSiteModal] = useState<Site | null>(null)
useEffect(() => { useEffect(() => {
if (user?.org_id) { if (user?.org_id) {
@@ -222,15 +223,9 @@ export default function HomePage() {
} }
} }
const handlePermanentDelete = async (id: string) => { const handlePermanentDelete = (id: string) => {
if (!confirm('Permanently delete this site and all data? This cannot be undone.')) return const site = deletedSites.find((s) => s.id === id)
try { if (site) setPermanentDeleteSiteModal(site)
await permanentDeleteSite(id)
toast.success('Site permanently deleted')
loadSites()
} catch (error: unknown) {
toast.error(getAuthErrorMessage(error) || 'Failed to delete site')
}
} }
if (authLoading) { if (authLoading) {
@@ -550,6 +545,16 @@ export default function HomePage() {
siteId={deleteModalSite?.id || ''} siteId={deleteModalSite?.id || ''}
/> />
<DeleteSiteModal
open={!!permanentDeleteSiteModal}
onClose={() => setPermanentDeleteSiteModal(null)}
onDeleted={loadSites}
siteName={permanentDeleteSiteModal?.name || ''}
siteDomain={permanentDeleteSiteModal?.domain || ''}
siteId={permanentDeleteSiteModal?.id || ''}
permanentOnly
/>
{deletedSites.length > 0 && ( {deletedSites.length > 0 && (
<div className="mt-8"> <div className="mt-8">
<h3 className="text-sm font-medium text-neutral-500 dark:text-neutral-400 mb-4">Scheduled for Deletion</h3> <h3 className="text-sm font-medium text-neutral-500 dark:text-neutral-400 mb-4">Scheduled for Deletion</h3>

View File

@@ -1,11 +1,9 @@
'use client' 'use client'
import { useState } from 'react' import { useState, useEffect } from 'react'
import { createPortal } from 'react-dom' import { createPortal } from 'react-dom'
import { motion, AnimatePresence } from 'framer-motion' import { motion, AnimatePresence } from 'framer-motion'
import { toast } from '@ciphera-net/ui' import { toast, getAuthErrorMessage, AlertTriangleIcon, XIcon } from '@ciphera-net/ui'
import { getAuthErrorMessage } from '@ciphera-net/ui'
import { AlertTriangleIcon, XIcon } from '@ciphera-net/ui'
import { deleteSite, permanentDeleteSite } from '@/lib/api/sites' import { deleteSite, permanentDeleteSite } from '@/lib/api/sites'
interface DeleteSiteModalProps { interface DeleteSiteModalProps {
@@ -15,15 +13,22 @@ interface DeleteSiteModalProps {
siteName: string siteName: string
siteDomain: string siteDomain: string
siteId: string siteId: string
permanentOnly?: boolean
} }
export default function DeleteSiteModal({ open, onClose, onDeleted, siteName, siteDomain, siteId }: DeleteSiteModalProps) { export default function DeleteSiteModal({ open, onClose, onDeleted, siteName, siteDomain, siteId, permanentOnly }: DeleteSiteModalProps) {
const [deleteConfirm, setDeleteConfirm] = useState('') const [deleteConfirm, setDeleteConfirm] = useState('')
const [isDeleting, setIsDeleting] = useState(false) const [isDeleting, setIsDeleting] = useState(false)
const [showPermanent, setShowPermanent] = useState(false) const [showPermanent, setShowPermanent] = useState(!!permanentOnly)
const [permanentConfirm, setPermanentConfirm] = useState('') const [permanentConfirm, setPermanentConfirm] = useState('')
const [isPermanentDeleting, setIsPermanentDeleting] = useState(false) const [isPermanentDeleting, setIsPermanentDeleting] = useState(false)
useEffect(() => {
if (open && permanentOnly) {
setShowPermanent(true)
}
}, [open, permanentOnly])
const handleClose = () => { const handleClose = () => {
setDeleteConfirm('') setDeleteConfirm('')
setShowPermanent(false) setShowPermanent(false)
@@ -43,7 +48,6 @@ export default function DeleteSiteModal({ open, onClose, onDeleted, siteName, si
onDeleted() onDeleted()
} catch (error: unknown) { } catch (error: unknown) {
toast.error(getAuthErrorMessage(error) || 'Failed to delete site') toast.error(getAuthErrorMessage(error) || 'Failed to delete site')
} finally {
setIsDeleting(false) setIsDeleting(false)
} }
} }
@@ -58,7 +62,6 @@ export default function DeleteSiteModal({ open, onClose, onDeleted, siteName, si
onDeleted() onDeleted()
} catch (error: unknown) { } catch (error: unknown) {
toast.error(getAuthErrorMessage(error) || 'Failed to permanently delete site') toast.error(getAuthErrorMessage(error) || 'Failed to permanently delete site')
} finally {
setIsPermanentDeleting(false) setIsPermanentDeleting(false)
} }
} }
@@ -193,13 +196,17 @@ export default function DeleteSiteModal({ open, onClose, onDeleted, siteName, si
<button <button
type="button" type="button"
onClick={() => { onClick={() => {
setShowPermanent(false) if (permanentOnly) {
setPermanentConfirm('') handleClose()
} else {
setShowPermanent(false)
setPermanentConfirm('')
}
}} }}
className="flex-1 px-4 py-2 text-sm font-medium text-neutral-700 dark:text-neutral-300 hover:bg-neutral-100 dark:hover:bg-neutral-800 rounded-xl transition-colors" className="flex-1 px-4 py-2 text-sm font-medium text-neutral-700 dark:text-neutral-300 hover:bg-neutral-100 dark:hover:bg-neutral-800 rounded-xl transition-colors"
disabled={isPermanentDeleting} disabled={isPermanentDeleting}
> >
Back {permanentOnly ? 'Cancel' : 'Back'}
</button> </button>
<button <button
onClick={handlePermanentDelete} onClick={handlePermanentDelete}