migrants-nt-web/src/components/ui/ProfileSettings.tsx

510 lines
23 KiB
TypeScript

"use client"
import type React from "react"
import { useState, useEffect } from "react"
import { useNavigate } from "react-router-dom"
import { motion } from "framer-motion"
import { Camera, Save, User, Mail, MapPin, Lock, Bell, Home } from "lucide-react"
import { Link } from "react-router-dom"
interface UserProfile {
firstName: string
lastName: string
email: string
jobTitle: string
department: string
bio: string
avatar: string
}
export default function ProfileSettings() {
const [isFirstLoad, setIsFirstLoad] = useState(true)
const [isLoading, setIsLoading] = useState(false)
const [activeTab, setActiveTab] = useState("profile")
const [profile, setProfile] = useState<UserProfile>({
firstName: "Admin",
lastName: "User",
email: "admin@example.com",
jobTitle: "Database Administrator",
department: "IT",
bio: "Experienced database administrator with a focus on migration data management.",
avatar: "",
})
const navigate = useNavigate()
// Add a handleLogout function that clears the adminNavigation flag
const handleLogout = () => {
localStorage.removeItem("adminToken")
localStorage.removeItem("adminNavigation") // Clear navigation flag on logout
navigate("/admin/login")
}
useEffect(() => {
// Check if user is authenticated
const token = localStorage.getItem("adminToken")
if (!token) {
navigate("/admin/login")
return
}
// Check if we're navigating from another admin page
const hasVisitedAdmin = localStorage.getItem("adminNavigation")
// Skip loading if we're navigating from another admin page
if (hasVisitedAdmin) {
setIsFirstLoad(false)
} else {
// Set flag to indicate we've visited an admin page
localStorage.setItem("adminNavigation", "true")
// Only show loading state on first load
if (isFirstLoad) {
// Simulate loading profile data
const timer = setTimeout(() => {
setIsFirstLoad(false)
}, 500) // Reduced loading time for better UX
return () => clearTimeout(timer)
}
}
}, [isFirstLoad, navigate])
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
const { name, value } = e.target
setProfile((prev) => ({ ...prev, [name]: value }))
}
const handleSave = () => {
setIsLoading(true)
// Simulate API call
setTimeout(() => {
setIsLoading(false)
}, 500) // Reduced loading time for better UX
}
const handleAvatarChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0]
if (file) {
const reader = new FileReader()
reader.onload = (event) => {
if (event.target?.result) {
}
}
reader.readAsDataURL(file)
}
}
// If it's the first load, show a loading state
if (isFirstLoad) {
return (
<div className="min-h-screen flex items-center justify-center bg-[#E8DCCA]/10">
<div className="text-center">
<div className="w-16 h-16 border-4 border-[#9B2335] border-t-transparent rounded-full animate-spin mx-auto"></div>
<p className="mt-4 text-gray-600">Loading profile...</p>
</div>
</div>
)
}
return (
<div className="min-h-screen flex">
{/* Sidebar */}
<div className="w-64 bg-[#1A2A57] text-white">
<div className="p-4 border-b border-[#1A2A57]/30">
<h2 className="text-xl font-serif font-bold">Italian Migrants</h2>
<p className="text-sm text-white/70">Northern Territory DB</p>
</div>
<nav className="mt-6 px-4">
<div className="space-y-1">
<Link
to="/admin"
className="flex items-center px-4 py-3 text-white/80 hover:bg-[#1A2A57]/40 rounded-md"
>
<Home className="h-5 w-5 mr-3" />
Dashboard
</Link>
<Link
to="/admin/migrants"
className="flex items-center px-4 py-3 text-white/80 hover:bg-[#1A2A57]/40 rounded-md"
>
<User className="h-5 w-5 mr-3" />
Migrants
</Link>
<Link to="#" className="flex items-center px-4 py-3 text-white/80 hover:bg-[#1A2A57]/40 rounded-md">
<Mail className="h-5 w-5 mr-3" />
Reports
</Link>
<Link to="#" className="flex items-center px-4 py-3 text-white/80 hover:bg-[#1A2A57]/40 rounded-md">
<MapPin className="h-5 w-5 mr-3" />
Database
</Link>
<Link
to="/admin/settings/profile"
className="flex items-center px-4 py-3 text-white bg-[#1A2A57]/40 rounded-md"
>
<Lock className="h-5 w-5 mr-3" />
Settings
</Link>
</div>
</nav>
{/* Update the bottom user section in the sidebar */}
<div className="absolute bottom-0 w-64 p-4 border-t border-[#1A2A57]/30">
<button
onClick={handleLogout}
className="flex items-center w-full px-4 py-2 text-white/80 hover:bg-[#1A2A57]/40 rounded-md"
>
<div className="h-8 w-8 rounded-full bg-white text-[#1A2A57] flex items-center justify-center mr-2">
<User className="h-5 w-5" />
</div>
<span className="text-sm">Admin User</span>
</button>
</div>
</div>
{/* Main content */}
<div className="flex-1 overflow-auto">
{/* Header */}
<div className="bg-white shadow-sm border-b border-gray-200">
<div className="flex justify-between items-center px-6 py-4">
<h1 className="text-xl font-medium text-[#1A2A57]">Admin Portal</h1>
<div className="text-sm text-gray-600">Northern Territory</div>
</div>
</div>
{/* Settings content */}
<div className="p-6">
<motion.div initial={{ opacity: 0, y: 10 }} animate={{ opacity: 1, y: 0 }} transition={{ duration: 0.3 }}>
<div className="flex justify-between items-center mb-6">
<div>
<h2 className="text-2xl font-bold text-gray-800">Settings</h2>
<p className="text-gray-600">Manage your account preferences</p>
</div>
<button
onClick={handleSave}
disabled={isLoading}
className="px-4 py-2 bg-[#01796F] text-white rounded-md hover:bg-[#01796F]/90 flex items-center disabled:opacity-70"
>
{isLoading ? (
<>
<div className="w-4 h-4 border-2 border-white border-t-transparent rounded-full animate-spin mr-2"></div>
Saving...
</>
) : (
<>
<Save className="h-4 w-4 mr-2" />
Save Changes
</>
)}
</button>
</div>
{/* Tabs */}
<div className="flex mb-6 border-b border-gray-200">
<button
className={`px-6 py-3 font-medium flex items-center ${
activeTab === "profile"
? "text-[#1A2A57] border-b-2 border-[#1A2A57]"
: "text-gray-500 hover:text-gray-700"
}`}
onClick={() => setActiveTab("profile")}
>
<User className="h-4 w-4 mr-2" />
Profile
</button>
<button
className={`px-6 py-3 font-medium flex items-center ${
activeTab === "security"
? "text-[#1A2A57] border-b-2 border-[#1A2A57]"
: "text-gray-500 hover:text-gray-700"
}`}
onClick={() => setActiveTab("security")}
>
<Lock className="h-4 w-4 mr-2" />
Security
</button>
<button
className={`px-6 py-3 font-medium flex items-center ${
activeTab === "notifications"
? "text-[#1A2A57] border-b-2 border-[#1A2A57]"
: "text-gray-500 hover:text-gray-700"
}`}
onClick={() => setActiveTab("notifications")}
>
<Bell className="h-4 w-4 mr-2" />
Notifications
</button>
</div>
{/* Profile Tab Content */}
{activeTab === "profile" && (
<div className="bg-white rounded-lg shadow-sm border border-gray-200 p-6">
<h3 className="text-lg font-medium text-gray-800 mb-4">Profile Information</h3>
<p className="text-gray-600 mb-6">
Update your personal information and how it appears on your profile.
</p>
<div className="flex items-start mb-8">
<div className="mr-6">
<div className="relative">
<div className="h-24 w-24 rounded-full bg-gray-200 overflow-hidden">
{profile.avatar ? (
<img
src={profile.avatar || `${import.meta.env.BASE_URL}assets/placeholder.png`}
alt="Profile"
className="h-full w-full object-cover"
/>
) : (
<div className="h-full w-full flex items-center justify-center bg-gray-300">
<User className="h-12 w-12 text-gray-400" />
</div>
)}
</div>
<label
htmlFor="avatar-upload"
className="absolute bottom-0 right-0 p-1 bg-[#9B2335] text-white rounded-full cursor-pointer"
>
<Camera className="h-4 w-4" />
<input
id="avatar-upload"
type="file"
accept="image/*"
className="hidden"
onChange={handleAvatarChange}
/>
</label>
</div>
<button className="mt-2 text-sm text-[#1A2A57] hover:underline">Change</button>
</div>
<div className="flex-1 grid grid-cols-2 gap-6">
<div>
<label htmlFor="firstName" className="block text-sm font-medium text-gray-700 mb-1">
First Name
</label>
<input
type="text"
id="firstName"
name="firstName"
value={profile.firstName}
onChange={handleInputChange}
className="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-[#01796F] focus:border-[#01796F]"
/>
</div>
<div>
<label htmlFor="lastName" className="block text-sm font-medium text-gray-700 mb-1">
Last Name
</label>
<input
type="text"
id="lastName"
name="lastName"
value={profile.lastName}
onChange={handleInputChange}
className="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-[#01796F] focus:border-[#01796F]"
/>
</div>
<div className="col-span-2">
<label htmlFor="email" className="block text-sm font-medium text-gray-700 mb-1">
Email
</label>
<input
type="email"
id="email"
name="email"
value={profile.email}
onChange={handleInputChange}
className="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-[#01796F] focus:border-[#01796F]"
/>
</div>
<div>
<label htmlFor="jobTitle" className="block text-sm font-medium text-gray-700 mb-1">
Job Title
</label>
<input
type="text"
id="jobTitle"
name="jobTitle"
value={profile.jobTitle}
onChange={handleInputChange}
className="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-[#01796F] focus:border-[#01796F]"
/>
</div>
<div>
<label htmlFor="department" className="block text-sm font-medium text-gray-700 mb-1">
Department
</label>
<input
type="text"
id="department"
name="department"
value={profile.department}
onChange={handleInputChange}
className="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-[#01796F] focus:border-[#01796F]"
/>
</div>
</div>
</div>
<div>
<label htmlFor="bio" className="block text-sm font-medium text-gray-700 mb-1">
Bio
</label>
<textarea
id="bio"
name="bio"
rows={4}
value={profile.bio}
onChange={handleInputChange}
className="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-[#01796F] focus:border-[#01796F]"
/>
</div>
</div>
)}
{/* Security Tab Content */}
{activeTab === "security" && (
<div className="bg-white rounded-lg shadow-sm border border-gray-200 p-6">
<h3 className="text-lg font-medium text-gray-800 mb-4">Security Settings</h3>
<p className="text-gray-600 mb-6">Manage your password and account security preferences.</p>
<div className="space-y-6">
<div>
<h4 className="text-md font-medium mb-2">Change Password</h4>
<div className="grid grid-cols-1 gap-4">
<div>
<label htmlFor="currentPassword" className="block text-sm font-medium text-gray-700 mb-1">
Current Password
</label>
<input
type="password"
id="currentPassword"
className="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-[#01796F] focus:border-[#01796F]"
/>
</div>
<div>
<label htmlFor="newPassword" className="block text-sm font-medium text-gray-700 mb-1">
New Password
</label>
<input
type="password"
id="newPassword"
className="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-[#01796F] focus:border-[#01796F]"
/>
</div>
<div>
<label htmlFor="confirmPassword" className="block text-sm font-medium text-gray-700 mb-1">
Confirm New Password
</label>
<input
type="password"
id="confirmPassword"
className="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-[#01796F] focus:border-[#01796F]"
/>
</div>
</div>
<button className="mt-4 px-4 py-2 bg-[#1A2A57] text-white rounded-md hover:bg-[#1A2A57]/90">
Update Password
</button>
</div>
<div className="pt-6 border-t border-gray-200">
<h4 className="text-md font-medium mb-2">Two-Factor Authentication</h4>
<p className="text-sm text-gray-600 mb-4">
Add an extra layer of security to your account by enabling two-factor authentication.
</p>
<button className="px-4 py-2 bg-[#9B2335] text-white rounded-md hover:bg-[#9B2335]/90">
Enable 2FA
</button>
</div>
</div>
</div>
)}
{/* Notifications Tab Content */}
{activeTab === "notifications" && (
<div className="bg-white rounded-lg shadow-sm border border-gray-200 p-6">
<h3 className="text-lg font-medium text-gray-800 mb-4">Notification Preferences</h3>
<p className="text-gray-600 mb-6">Manage how and when you receive notifications.</p>
<div className="space-y-6">
<div>
<h4 className="text-md font-medium mb-4">Email Notifications</h4>
<div className="space-y-3">
<div className="flex items-center justify-between">
<div>
<p className="font-medium">System Updates</p>
<p className="text-sm text-gray-600">Receive emails about system updates and maintenance</p>
</div>
<label className="relative inline-flex items-center cursor-pointer">
<input type="checkbox" className="sr-only peer" defaultChecked />
<div className="w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-[#01796F]/20 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-[#01796F]"></div>
</label>
</div>
<div className="flex items-center justify-between">
<div>
<p className="font-medium">New Records</p>
<p className="text-sm text-gray-600">Receive emails when new migrant records are added</p>
</div>
<label className="relative inline-flex items-center cursor-pointer">
<input type="checkbox" className="sr-only peer" defaultChecked />
<div className="w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-[#01796F]/20 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-[#01796F]"></div>
</label>
</div>
<div className="flex items-center justify-between">
<div>
<p className="font-medium">Security Alerts</p>
<p className="text-sm text-gray-600">Receive emails about security-related events</p>
</div>
<label className="relative inline-flex items-center cursor-pointer">
<input type="checkbox" className="sr-only peer" defaultChecked />
<div className="w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-[#01796F]/20 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-[#01796F]"></div>
</label>
</div>
</div>
</div>
<div className="pt-6 border-t border-gray-200">
<h4 className="text-md font-medium mb-4">In-App Notifications</h4>
<div className="space-y-3">
<div className="flex items-center justify-between">
<div>
<p className="font-medium">Record Updates</p>
<p className="text-sm text-gray-600">Receive notifications when records are updated</p>
</div>
<label className="relative inline-flex items-center cursor-pointer">
<input type="checkbox" className="sr-only peer" defaultChecked />
<div className="w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-[#01796F]/20 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-[#01796F]"></div>
</label>
</div>
<div className="flex items-center justify-between">
<div>
<p className="font-medium">User Activity</p>
<p className="text-sm text-gray-600">Receive notifications about other users' activity</p>
</div>
<label className="relative inline-flex items-center cursor-pointer">
<input type="checkbox" className="sr-only peer" />
<div className="w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-[#01796F]/20 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-[#01796F]"></div>
</label>
</div>
</div>
</div>
</div>
</div>
)}
</motion.div>
</div>
</div>
</div>
)
}