import { useEffect, useState, type ChangeEvent } from "react"; import { BadgeCheck, Briefcase, CalendarDays, Mail, Phone, Shield, User } from "lucide-react"; import { Badge } from "../components/ui/badge"; import { Button } from "../components/ui/button"; import { Card, CardContent } from "../components/ui/card"; import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle, } from "../components/ui/dialog"; import { Input } from "../components/ui/input"; import { Textarea } from "../components/ui/textarea"; import { FileUpload } from "../components/ui/file-upload"; import { getMyProfile } from "../api/users.api"; import { updateTeamMember } from "../api/team.api"; import { uploadImageFile } from "../api/files.api"; import { SpinnerIcon } from "../components/ui/spinner-icon"; import type { UpdateTeamMemberRequest } from "../types/team.types"; import { toast } from "sonner"; function formatDate(dateStr: string | null | undefined): string { if (!dateStr) return "—"; return new Date(dateStr).toLocaleDateString("en-US", { year: "numeric", month: "long", day: "numeric", }); } function formatDateTime(dateStr: string | null | undefined): string { if (!dateStr) return "—"; return new Date(dateStr).toLocaleString("en-US", { year: "numeric", month: "long", day: "numeric", hour: "2-digit", minute: "2-digit", }); } interface TeamMeProfile { id: number first_name: string last_name: string email: string phone_number: string team_role: string department: string job_title: string employment_type: string hire_date: string bio: string status: string email_verified: boolean permissions: string[] last_login: string | null created_at: string emergency_contact?: string work_phone?: string profile_picture_url?: string } function LoadingSkeleton() { return (
{[1, 2, 3].map((i) => (
{[1, 2, 3, 4].map((j) => (
))}
))}
); } export function ProfilePage() { const [profile, setProfile] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [editing, setEditing] = useState(false); const [saving, setSaving] = useState(false); const [profilePictureFile, setProfilePictureFile] = useState(null); const [editForm, setEditForm] = useState({ first_name: "", last_name: "", phone_number: "", profile_picture_url: "", bio: "", }); useEffect(() => { const fetchProfile = async () => { try { const res = await getMyProfile(); setProfile((res.data?.data ?? null) as unknown as TeamMeProfile | null); } catch (err) { console.error("Failed to fetch profile", err); setError("Failed to load profile. Please try again later."); } finally { setLoading(false); } }; fetchProfile(); }, []); const startEditing = () => { if (!profile) return; const nextForm: UpdateTeamMemberRequest = { first_name: profile.first_name ?? "", last_name: profile.last_name ?? "", phone_number: profile.phone_number ?? "", profile_picture_url: profile.profile_picture_url ?? "", bio: profile.bio ?? "", }; setEditForm(nextForm); setProfilePictureFile(null); setEditing(true); }; const cancelEditing = () => { setProfilePictureFile(null); setEditing(false); }; const updateField = (field: keyof UpdateTeamMemberRequest, value: string) => { setEditForm((prev) => ({ ...prev, [field]: value })); }; const handleSave = async () => { if (!profile) return; let nextProfilePictureUrl = editForm.profile_picture_url ?? ""; if (profilePictureFile) { try { const uploadRes = await uploadImageFile(profilePictureFile); const uploadedUrl = uploadRes.data?.data?.url?.trim(); if (!uploadedUrl) throw new Error("Missing uploaded image url"); nextProfilePictureUrl = uploadedUrl; } catch (err) { console.error("Failed to upload profile picture:", err); toast.error("Failed to upload profile picture"); return; } } const payload: UpdateTeamMemberRequest = { bio: editForm.bio ?? "", first_name: editForm.first_name ?? "", last_name: editForm.last_name ?? "", phone_number: editForm.phone_number ?? "", profile_picture_url: nextProfilePictureUrl, }; setSaving(true); try { await updateTeamMember(profile.id, payload); const refreshed = await getMyProfile(); setProfile((refreshed.data?.data ?? null) as unknown as TeamMeProfile | null); setEditing(false); setProfilePictureFile(null); toast.success("Profile updated successfully"); } catch (err) { console.error("Failed to update team member profile", err); toast.error("Failed to update profile"); } finally { setSaving(false); } }; if (loading) return ; if (error || !profile) { return (

{error || "Profile not available"}

Please check your connection and try again.

); } const fullName = `${profile.first_name} ${profile.last_name}`; const initials = `${profile.first_name?.[0] ?? ""}${profile.last_name?.[0] ?? ""}`.toUpperCase(); return (

Summary

{profile.job_title || "Role-focused work item"}
{profile.team_role || "Team responsibility"}
{profile.email}
{profile.phone_number || "No phone number"}

Employment

{profile.department || "Department not set"}

Employment type: {profile.employment_type || "—"}

More about me

Status {profile.status} Email {profile.email_verified ? "verified" : "not verified"} Joined {formatDate(profile.created_at)} Last login {formatDateTime(profile.last_login)}

First Name

{profile.first_name}

Last Name

{profile.last_name}

Department

{profile.department || "—"}

Team Role

{profile.team_role || "—"}

Job Title

{profile.job_title || "—"}

Hire Date

{formatDate(profile.hire_date) || "—"}

Phone Number

{profile.phone_number || "—"}

!saving && setEditing(open)}> Edit profile

First Name

updateField("first_name", e.target.value)} />

Last Name

updateField("last_name", e.target.value)} />

Phone Number

updateField("phone_number", e.target.value)} />

Profile Picture

updateField("profile_picture_url", e.target.value)} placeholder="Or paste image URL (https://...)" />

Bio