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