Yvonne Priscilla
update theme login etc
bb909a5
'use client';
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { authFetch } from '@/lib/api';
import { Candidate } from '@/types/candidate-table';
import { Profile } from '@/types/profile';
import { useQuery } from '@tanstack/react-query';
import { Download } from 'lucide-react';
import { Badge } from '../ui/badge';
interface DetailDialogProps {
open?: boolean;
onOpenChange?: (open: boolean) => void;
candidate?: Candidate | null;
}
// Helper: check if value is meaningful
const isValidValue = (value: any) => {
if (value === null || value === undefined) return false
if (typeof value === "string" && value.trim() === "") return false
if (typeof value === "number" && value === 0) return false
return true
}
const InfoItem = ({ label, value }: { label: string; value: React.ReactNode }) => {
if (!isValidValue(value)) return null
return (
<div>
<h3 className="text-sm text-gray-500">{label}</h3>
<div className="text-base">{value}</div>
</div>
)
}
export function DetailDialog({ open, onOpenChange, candidate }: DetailDialogProps) {
const fetchProfile = async (profileId: string): Promise<Profile> => {
const res = await authFetch(`/api/cv-profile/profile-detail?profile_id=${profileId}`)
if (!res.ok) throw new Error("Failed to fetch profile")
return res.json()
}
const { data, isLoading } = useQuery({
queryKey: ["profile-detail", candidate?.profile_id],
queryFn: () => fetchProfile(candidate!.profile_id),
enabled: open && !!candidate?.profile_id,
staleTime: 0,
refetchOnWindowFocus: false,
})
const handleDownload = () => {
if (!data?.url) return
window.open(data.url, '_blank')
}
return (
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent className="sm:max-w-2xl">
<DialogHeader>
<DialogTitle>Profile Candidate</DialogTitle>
</DialogHeader>
{/* ===================== */}
{/* 🔹 LOADING SKELETON */}
{/* ===================== */}
{isLoading && (
<div className="grid grid-cols-2 gap-4 animate-pulse">
{Array.from({ length: 10 }).map((_, i) => (
<div key={i}>
<div className="h-3 bg-gray-200 rounded w-24 mb-2" />
<div className="h-4 bg-gray-200 rounded w-full" />
</div>
))}
</div>
)}
{/* ===================== */}
{/* 🔹 CONTENT */}
{/* ===================== */}
{!isLoading && data && (
<div className="grid grid-cols-2 gap-4">
<InfoItem label="Full Name" value={data.fullname} />
<InfoItem label="Domicile" value={data.domicile} />
<InfoItem
label="Year of Experience"
value={
isValidValue(data.yoe)
? `${data.yoe} year${data.yoe !== 1 ? "s" : ""}`
: null
}
/>
<InfoItem label="Filename" value={data.filename} />
{/* Education 1 */}
<InfoItem label="University 1" value={data.univ_edu_1} />
<InfoItem label="Major 1" value={data.major_edu_1} />
<InfoItem label="GPA 1" value={data.gpa_edu_1} />
{/* Education 2 */}
<InfoItem label="University 2" value={data.univ_edu_2} />
<InfoItem label="Major 2" value={data.major_edu_2} />
<InfoItem label="GPA 2" value={data.gpa_edu_2} />
{/* Education 3 */}
<InfoItem label="University 3" value={data.univ_edu_3} />
<InfoItem label="Major 3" value={data.major_edu_3} />
<InfoItem label="GPA 3" value={data.gpa_edu_3} />
{/* Arrays */}
{data.hardskills?.length > 0 && (
<div className="col-span-2">
<h3 className="text-sm text-gray-500 mb-1">Hardskills</h3>
<div className="flex flex-wrap gap-2">
{data.hardskills.map((s) => (
<Badge variant="outline" key={s}>{s}</Badge>
))}
</div>
</div>
)}
{data.softskills?.length > 0 && (
<div className="col-span-2">
<h3 className="text-sm text-gray-500 mb-1">Softskills</h3>
<div className="flex flex-wrap gap-2">
{data.softskills.map((s) => (
<Badge variant="outline" key={s}>{s}</Badge>
))}
</div>
</div>
)}
{data.certifications?.length > 0 && (
<div className="col-span-2">
<h3 className="text-sm text-gray-500 mb-1">Certifications</h3>
<div className="flex flex-wrap gap-2">
{data.certifications.map((s) => (
<Badge variant="outline" key={s}>{s}</Badge>
))}
</div>
</div>
)}
{data.business_domain?.length > 0 && (
<div className="col-span-2">
<h3 className="text-sm text-gray-500 mb-1">Business Domain</h3>
<div className="flex flex-wrap gap-2">
{data.business_domain.map((s) => (
<Badge variant="outline" key={s}>{s}</Badge>
))}
</div>
</div>
)}
{/* Download */}
{isValidValue(data.url) && (
<div>
<h3 className="text-sm text-gray-500">CV</h3>
<button
className="mt-1 flex items-center gap-1 text-sm text-blue-600 hover:underline"
onClick={handleDownload}
>
<Download className="size-4" />
{data.filename}
</button>
</div>
)}
</div>
)}
</DialogContent>
</Dialog>
);
}