chore: replace native window.confirm with Custom ConfirmModal
This commit is contained in:
parent
c5f6b1317e
commit
fd2fa328ad
5 changed files with 101 additions and 22 deletions
|
|
@ -4,6 +4,7 @@ import { useState, useEffect } from "react";
|
|||
import { useRouter } from "next/navigation";
|
||||
import { toast } from "sonner";
|
||||
import { emailTemplatesApi, EmailTemplate } from "@/lib/api";
|
||||
import { ConfirmModal } from "@/components/confirm-modal";
|
||||
|
||||
export default function EmailTemplatesPage() {
|
||||
const router = useRouter();
|
||||
|
|
@ -11,6 +12,7 @@ export default function EmailTemplatesPage() {
|
|||
const [loading, setLoading] = useState(true);
|
||||
const [showCreate, setShowCreate] = useState(false);
|
||||
const [newTemplate, setNewTemplate] = useState({ slug: "", subject: "", body_html: "", variables: "" });
|
||||
const [deleteTemplateSlug, setDeleteTemplateSlug] = useState<string | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
fetchTemplates();
|
||||
|
|
@ -50,13 +52,19 @@ export default function EmailTemplatesPage() {
|
|||
};
|
||||
|
||||
const handleDelete = async (slug: string) => {
|
||||
if (!confirm("Delete this template?")) return;
|
||||
setDeleteTemplateSlug(slug);
|
||||
};
|
||||
|
||||
const confirmDelete = async () => {
|
||||
if (!deleteTemplateSlug) return;
|
||||
try {
|
||||
await emailTemplatesApi.delete(slug);
|
||||
await emailTemplatesApi.delete(deleteTemplateSlug);
|
||||
toast.success("Template deleted");
|
||||
fetchTemplates();
|
||||
} catch (err: any) {
|
||||
toast.error(err.message || "Failed to delete template");
|
||||
} finally {
|
||||
setDeleteTemplateSlug(null);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -178,6 +186,13 @@ export default function EmailTemplatesPage() {
|
|||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<ConfirmModal
|
||||
isOpen={!!deleteTemplateSlug}
|
||||
onClose={() => setDeleteTemplateSlug(null)}
|
||||
onConfirm={confirmDelete}
|
||||
title="Are you sure you want to delete this template?"
|
||||
description="This action cannot be undone."
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,13 +37,14 @@ import {
|
|||
} from "lucide-react"
|
||||
import { applicationsApi, notificationsApi } from "@/lib/api"
|
||||
import { toast } from "sonner"
|
||||
import { ConfirmModal } from "@/components/confirm-modal"
|
||||
|
||||
const statusConfig = {
|
||||
pending: { label: "Pendente", color: "bg-yellow-100 text-yellow-800 border-yellow-200", icon: Clock },
|
||||
reviewed: { label: "Em análise", color: "bg-blue-100 text-blue-800 border-blue-200", icon: Eye },
|
||||
pending: { label: "Pendente", color: "bg-yellow-100 text-yellow-800 border-yellow-200", icon: Clock },
|
||||
reviewed: { label: "Em análise", color: "bg-blue-100 text-blue-800 border-blue-200", icon: Eye },
|
||||
shortlisted: { label: "Selecionado", color: "bg-purple-100 text-purple-800 border-purple-200", icon: Star },
|
||||
hired: { label: "Contratado", color: "bg-green-100 text-green-800 border-green-200", icon: Check },
|
||||
rejected: { label: "Rejeitado", color: "bg-red-100 text-red-800 border-red-200", icon: X },
|
||||
hired: { label: "Contratado", color: "bg-green-100 text-green-800 border-green-200", icon: Check },
|
||||
rejected: { label: "Rejeitado", color: "bg-red-100 text-red-800 border-red-200", icon: X },
|
||||
}
|
||||
|
||||
interface Application {
|
||||
|
|
@ -64,6 +65,7 @@ export default function ApplicationsPage() {
|
|||
const [statusFilter, setStatusFilter] = useState("all")
|
||||
const [searchTerm, setSearchTerm] = useState("")
|
||||
const [selectedApp, setSelectedApp] = useState<Application | null>(null)
|
||||
const [deleteConfirmId, setDeleteConfirmId] = useState<string | null>(null)
|
||||
|
||||
useEffect(() => {
|
||||
async function fetchApplications() {
|
||||
|
|
@ -81,16 +83,22 @@ export default function ApplicationsPage() {
|
|||
|
||||
const handleDelete = async (id: string, e?: React.MouseEvent) => {
|
||||
e?.stopPropagation()
|
||||
if (!confirm("Are you sure you want to delete this application?")) return
|
||||
setDeleteConfirmId(id)
|
||||
}
|
||||
|
||||
const confirmDelete = async () => {
|
||||
if (!deleteConfirmId) return
|
||||
|
||||
try {
|
||||
await applicationsApi.delete(id)
|
||||
setApplications(applications.filter(a => a.id !== id))
|
||||
await applicationsApi.delete(deleteConfirmId)
|
||||
setApplications(applications.filter(a => a.id !== deleteConfirmId))
|
||||
toast.success("Application deleted")
|
||||
if (selectedApp?.id === id) setSelectedApp(null)
|
||||
if (selectedApp?.id === deleteConfirmId) setSelectedApp(null)
|
||||
} catch (error) {
|
||||
console.error("Delete error:", error)
|
||||
toast.error("Failed to delete application")
|
||||
} finally {
|
||||
setDeleteConfirmId(null)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -168,7 +176,7 @@ export default function ApplicationsPage() {
|
|||
<Filter className="h-4 w-4 mr-2" />
|
||||
<SelectValue placeholder="Filter by status" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectContent>
|
||||
<SelectItem value="all">All Status</SelectItem>
|
||||
<SelectItem value="pending">Pendente</SelectItem>
|
||||
<SelectItem value="reviewed">Em análise</SelectItem>
|
||||
|
|
@ -346,6 +354,13 @@ export default function ApplicationsPage() {
|
|||
</div>
|
||||
)
|
||||
}
|
||||
<ConfirmModal
|
||||
isOpen={!!deleteConfirmId}
|
||||
onClose={() => setDeleteConfirmId(null)}
|
||||
onConfirm={confirmDelete}
|
||||
title="Are you sure you want to delete this application?"
|
||||
description="This action cannot be undone."
|
||||
/>
|
||||
</div >
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ import {
|
|||
import { getCurrentUser, isAdminUser } from "@/lib/auth"
|
||||
import { toast } from "sonner"
|
||||
import { Archive, CheckCircle, Copy, ExternalLink, PauseCircle, Plus, RefreshCw, XCircle } from "lucide-react"
|
||||
import { ConfirmModal } from "@/components/confirm-modal"
|
||||
|
||||
const auditDateFormatter = new Intl.DateTimeFormat("pt-BR", {
|
||||
dateStyle: "short",
|
||||
|
|
@ -94,6 +95,7 @@ export default function BackofficePage() {
|
|||
const [isPlanDialogOpen, setIsPlanDialogOpen] = useState(false)
|
||||
const [planForm, setPlanForm] = useState<any>({ name: "", description: "", monthlyPrice: 0, yearlyPrice: 0, features: [] })
|
||||
const [editingPlanId, setEditingPlanId] = useState<string | null>(null)
|
||||
const [deletePlanId, setDeletePlanId] = useState<string | null>(null)
|
||||
|
||||
const loadBackoffice = async (silent = false) => {
|
||||
try {
|
||||
|
|
@ -223,13 +225,19 @@ export default function BackofficePage() {
|
|||
}
|
||||
|
||||
const handleDeletePlan = async (id: string) => {
|
||||
if (!confirm("Delete this plan?")) return
|
||||
setDeletePlanId(id)
|
||||
}
|
||||
|
||||
const confirmDeletePlan = async () => {
|
||||
if (!deletePlanId) return
|
||||
try {
|
||||
await plansApi.delete(id)
|
||||
await plansApi.delete(deletePlanId)
|
||||
toast.success("Plan deleted")
|
||||
loadBackoffice(true)
|
||||
} catch (error) {
|
||||
toast.error("Failed to delete plan")
|
||||
} finally {
|
||||
setDeletePlanId(null)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -534,6 +542,13 @@ export default function BackofficePage() {
|
|||
</Card>
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
<ConfirmModal
|
||||
isOpen={!!deletePlanId}
|
||||
onClose={() => setDeletePlanId(null)}
|
||||
onConfirm={confirmDeletePlan}
|
||||
title="Are you sure you want to delete this plan?"
|
||||
description="This action cannot be undone."
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -23,6 +23,7 @@ import { Switch } from "@/components/ui/switch"
|
|||
import { adminCompaniesApi, type AdminCompany } from "@/lib/api"
|
||||
import { getCurrentUser, isAdminUser } from "@/lib/auth"
|
||||
import { toast } from "sonner"
|
||||
import { ConfirmModal } from "@/components/confirm-modal"
|
||||
import { Skeleton } from "@/components/ui/skeleton"
|
||||
import { useTranslation } from "@/lib/i18n"
|
||||
|
||||
|
|
@ -89,6 +90,7 @@ export default function AdminCompaniesPage() {
|
|||
const [isDialogOpen, setIsDialogOpen] = useState(false)
|
||||
const [isViewDialogOpen, setIsViewDialogOpen] = useState(false)
|
||||
const [selectedCompany, setSelectedCompany] = useState<AdminCompany | null>(null)
|
||||
const [companyToDelete, setCompanyToDelete] = useState<AdminCompany | null>(null)
|
||||
const [creating, setCreating] = useState(false)
|
||||
const [updating, setUpdating] = useState(false)
|
||||
const [isEditDialogOpen, setIsEditDialogOpen] = useState(false)
|
||||
|
|
@ -223,16 +225,24 @@ export default function AdminCompaniesPage() {
|
|||
}
|
||||
|
||||
const handleDelete = async (company: AdminCompany) => {
|
||||
if (!window.confirm(t('admin.companies.deleteConfirm', { name: company.name }))) return
|
||||
setCompanyToDelete(company)
|
||||
}
|
||||
|
||||
const confirmDelete = async () => {
|
||||
if (!companyToDelete) return
|
||||
|
||||
try {
|
||||
await adminCompaniesApi.delete(company.id)
|
||||
await adminCompaniesApi.delete(companyToDelete.id)
|
||||
toast.success(t('admin.companies.success.deleted'))
|
||||
setIsViewDialogOpen(false)
|
||||
if (selectedCompany?.id === companyToDelete.id) {
|
||||
setIsViewDialogOpen(false)
|
||||
}
|
||||
loadCompanies()
|
||||
} catch (error) {
|
||||
console.error("Error deleting company:", error)
|
||||
toast.error("Failed to delete company")
|
||||
} finally {
|
||||
setCompanyToDelete(null)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -888,6 +898,14 @@ export default function AdminCompaniesPage() {
|
|||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</div>
|
||||
|
||||
<ConfirmModal
|
||||
isOpen={!!companyToDelete}
|
||||
onClose={() => setCompanyToDelete(null)}
|
||||
onConfirm={confirmDelete}
|
||||
title={companyToDelete ? t('admin.companies.deleteConfirm', { name: companyToDelete.name }) : ""}
|
||||
description="This action cannot be undone."
|
||||
/>
|
||||
</div >
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import { Switch } from "@/components/ui/switch"
|
|||
import { Plus, Search, Edit, Trash2, Eye, ChevronLeft, ChevronRight, Loader2 } from "lucide-react"
|
||||
import { adminJobsApi, jobsApi, type AdminJob } from "@/lib/api"
|
||||
import { useTranslation } from "@/lib/i18n"
|
||||
import { ConfirmModal } from "@/components/confirm-modal"
|
||||
|
||||
type EditForm = {
|
||||
title: string
|
||||
|
|
@ -70,6 +71,7 @@ export default function AdminJobsPage() {
|
|||
const [isLoading, setIsLoading] = useState(true)
|
||||
const [isSaving, setIsSaving] = useState(false)
|
||||
const [errorMessage, setErrorMessage] = useState<string | null>(null)
|
||||
const [deleteConfirmDialog, setDeleteConfirmDialog] = useState<{ isOpen: boolean, jobId: string | null }>({ isOpen: false, jobId: null })
|
||||
|
||||
const [page, setPage] = useState(1)
|
||||
const [limit] = useState(10)
|
||||
|
|
@ -144,12 +146,18 @@ export default function AdminJobsPage() {
|
|||
}
|
||||
|
||||
const handleDeleteJob = async (id: string) => {
|
||||
if (!confirm(t('admin.jobs.deleteConfirm'))) return
|
||||
setDeleteConfirmDialog({ isOpen: true, jobId: id })
|
||||
}
|
||||
|
||||
const confirmDeleteJob = async () => {
|
||||
if (!deleteConfirmDialog.jobId) return
|
||||
try {
|
||||
await jobsApi.delete(id)
|
||||
setJobs((prev) => prev.filter((job) => job.id !== id))
|
||||
await jobsApi.delete(deleteConfirmDialog.jobId)
|
||||
setJobs((prev) => prev.filter((job) => job.id !== deleteConfirmDialog.jobId))
|
||||
} catch {
|
||||
alert(t('admin.jobs.deleteError'))
|
||||
} finally {
|
||||
setDeleteConfirmDialog({ isOpen: false, jobId: null })
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -208,6 +216,14 @@ export default function AdminJobsPage() {
|
|||
</Link>
|
||||
</div>
|
||||
|
||||
<ConfirmModal
|
||||
isOpen={deleteConfirmDialog.isOpen}
|
||||
onClose={() => setDeleteConfirmDialog({ isOpen: false, jobId: null })}
|
||||
onConfirm={confirmDeleteJob}
|
||||
title={t('admin.jobs.deleteConfirm')}
|
||||
description="Esta ação não pode ser desfeita e irá excluir a vaga permanentemente."
|
||||
/>
|
||||
|
||||
{/* View Job Dialog */}
|
||||
<Dialog open={isViewDialogOpen} onOpenChange={setIsViewDialogOpen}>
|
||||
<DialogContent className="max-w-2xl max-h-[85vh] overflow-y-auto">
|
||||
|
|
@ -363,7 +379,7 @@ export default function AdminJobsPage() {
|
|||
<Select value={editForm.currency} onValueChange={(v) => setEditForm({ ...editForm, currency: v })}>
|
||||
<SelectTrigger><SelectValue /></SelectTrigger>
|
||||
<SelectContent>
|
||||
{["BRL","USD","EUR","GBP","JPY","CNY","AED","CAD","AUD","CHF"].map(c => (
|
||||
{["BRL", "USD", "EUR", "GBP", "JPY", "CNY", "AED", "CAD", "AUD", "CHF"].map(c => (
|
||||
<SelectItem key={c} value={c}>{c}</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
|
|
|
|||
Loading…
Reference in a new issue