"use client"; import { useState, useMemo, useEffect } from "react"; import { PlusCircle, Search, Filter, MoreHorizontal, X, ChevronDown, UserPlus, Mail, SortAsc, SortDesc, Mail as MailIcon, Phone, Clock, Calendar, ShieldAlert, ListFilter, } from "lucide-react"; import { Button } from "@/app/_components/ui/button"; import { Input } from "@/app/_components/ui/input"; import { Badge } from "@/app/_components/ui/badge"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger, DropdownMenuCheckboxItem, } from "@/app/_components/ui/dropdown-menu"; import { useQuery } from "@tanstack/react-query"; import { fetchUsers } from "@/app/(protected)/(admin)/dashboard/user-management/action"; import { User } from "@/src/models/users/users.model"; import { toast } from "sonner"; import { DataTable } from "./data-table"; import { InviteUserDialog } from "./invite-user"; import { AddUserDialog } from "./add-user-dialog"; import { UserDetailsSheet } from "./sheet"; import { Avatar } from "@radix-ui/react-avatar"; import Image from "next/image"; import { useNavigations } from "@/app/_hooks/use-navigations"; export default function UserManagement() { const [searchQuery, setSearchQuery] = useState(""); const [selectedUser, setSelectedUser] = useState(null); const [isSheetOpen, setIsSheetOpen] = useState(false); const [isAddUserOpen, setIsAddUserOpen] = useState(false); const [isInviteUserOpen, setIsInviteUserOpen] = useState(false); // Filter states const [filters, setFilters] = useState<{ email: string; phone: string; lastSignIn: string; createdAt: string; status: string[]; }>({ email: "", phone: "", lastSignIn: "", createdAt: "", status: [], }); // Use React Query to fetch users const [users, setUsers] = useState([]); const { isLoading, setIsLoading } = useNavigations(); useEffect(() => { const fetchData = async () => { try { setIsLoading(true); const fetchedUsers = await fetchUsers(); setUsers(fetchedUsers); } catch (error) { toast.error("Failed to fetch users"); } finally { setIsLoading(false); } }; fetchData(); }, []); const refetch = async () => { setIsLoading(true); try { const fetchedUsers = await fetchUsers(); setUsers(fetchedUsers); } catch (error) { toast.error("Failed to fetch users"); } finally { setIsLoading(false); } }; const handleUserClick = (user: User) => { setSelectedUser(user); setIsSheetOpen(true); }; const handleUserUpdate = () => { refetch(); setIsSheetOpen(false); }; const filteredUsers = useMemo(() => { return users.filter((user) => { // Global search if (searchQuery) { const query = searchQuery.toLowerCase(); const matchesSearch = user.email?.toLowerCase().includes(query) || user.phone?.toLowerCase().includes(query) || user.id.toLowerCase().includes(query); if (!matchesSearch) return false; } // Email filter if ( filters.email && !user.email?.toLowerCase().includes(filters.email.toLowerCase()) ) { return false; } // Phone filter if ( filters.phone && !user.phone?.toLowerCase().includes(filters.phone.toLowerCase()) ) { return false; } // Last sign in filter if (filters.lastSignIn) { if (filters.lastSignIn === "never" && user.last_sign_in_at) { return false; } else if (filters.lastSignIn === "today") { const today = new Date(); today.setHours(0, 0, 0, 0); const signInDate = user.last_sign_in_at ? new Date(user.last_sign_in_at) : null; if (!signInDate || signInDate < today) return false; } else if (filters.lastSignIn === "week") { const weekAgo = new Date(); weekAgo.setDate(weekAgo.getDate() - 7); const signInDate = user.last_sign_in_at ? new Date(user.last_sign_in_at) : null; if (!signInDate || signInDate < weekAgo) return false; } else if (filters.lastSignIn === "month") { const monthAgo = new Date(); monthAgo.setMonth(monthAgo.getMonth() - 1); const signInDate = user.last_sign_in_at ? new Date(user.last_sign_in_at) : null; if (!signInDate || signInDate < monthAgo) return false; } } // Created at filter if (filters.createdAt) { if (filters.createdAt === "today") { const today = new Date(); today.setHours(0, 0, 0, 0); const createdAt = user.created_at ? user.created_at ? new Date(user.created_at) : new Date() : new Date(); if (createdAt < today) return false; } else if (filters.createdAt === "week") { const weekAgo = new Date(); weekAgo.setDate(weekAgo.getDate() - 7); const createdAt = user.created_at ? new Date(user.created_at) : new Date(); if (createdAt < weekAgo) return false; } else if (filters.createdAt === "month") { const monthAgo = new Date(); monthAgo.setMonth(monthAgo.getMonth() - 1); const createdAt = user.created_at ? new Date(user.created_at) : new Date(); if (createdAt < monthAgo) return false; } } // Status filter if (filters.status.length > 0) { const userStatus = user.banned_until ? "banned" : !user.email_confirmed_at ? "unconfirmed" : "active"; if (!filters.status.includes(userStatus)) { return false; } } return true; }); }, [users, searchQuery, filters]); const clearFilters = () => { setFilters({ email: "", phone: "", lastSignIn: "", createdAt: "", status: [], }); }; const activeFilterCount = Object.values(filters).filter( (value) => (typeof value === "string" && value !== "") || (Array.isArray(value) && value.length > 0) ).length; const columns = [ { id: "email", header: ({ column }: any) => (
Email
setFilters({ ...filters, email: e.target.value }) } className="w-full" />
setFilters({ ...filters, email: "" })} > Clear filter
), cell: ({ row }: { row: { original: User } }) => (
{row.original.profile?.avatar ? ( Avatar ) : ( row.original.email?.[0]?.toUpperCase() || "?" )}
{row.original.email || "No email"}
{row.original.id}
), }, { id: "phone", header: ({ column }: any) => (
Phone
setFilters({ ...filters, phone: e.target.value }) } className="w-full" />
setFilters({ ...filters, phone: "" })} > Clear filter
), cell: ({ row }: { row: { original: User } }) => row.original.phone || "-", }, { id: "lastSignIn", header: ({ column }: any) => (
Last Sign In setFilters({ ...filters, lastSignIn: filters.lastSignIn === "today" ? "" : "today", }) } > Today setFilters({ ...filters, lastSignIn: filters.lastSignIn === "week" ? "" : "week", }) } > Last 7 days setFilters({ ...filters, lastSignIn: filters.lastSignIn === "month" ? "" : "month", }) } > Last 30 days setFilters({ ...filters, lastSignIn: filters.lastSignIn === "never" ? "" : "never", }) } > Never setFilters({ ...filters, lastSignIn: "" })} > Clear filter
), cell: ({ row }: { row: { original: User } }) => { return row.original.last_sign_in_at ? new Date(row.original.last_sign_in_at).toLocaleString() : "Never"; }, }, { id: "createdAt", header: ({ column }: any) => (
Created At setFilters({ ...filters, createdAt: filters.createdAt === "today" ? "" : "today", }) } > Today setFilters({ ...filters, createdAt: filters.createdAt === "week" ? "" : "week", }) } > Last 7 days setFilters({ ...filters, createdAt: filters.createdAt === "month" ? "" : "month", }) } > Last 30 days setFilters({ ...filters, createdAt: "" })} > Clear filter
), cell: ({ row }: { row: { original: User } }) => { return row.original.created_at ? new Date(row.original.created_at).toLocaleString() : "N/A"; }, }, { id: "status", header: ({ column }: any) => (
Status { const newStatus = [...filters.status]; if (newStatus.includes("active")) { newStatus.splice(newStatus.indexOf("active"), 1); } else { newStatus.push("active"); } setFilters({ ...filters, status: newStatus }); }} > Active { const newStatus = [...filters.status]; if (newStatus.includes("unconfirmed")) { newStatus.splice(newStatus.indexOf("unconfirmed"), 1); } else { newStatus.push("unconfirmed"); } setFilters({ ...filters, status: newStatus }); }} > Unconfirmed { const newStatus = [...filters.status]; if (newStatus.includes("banned")) { newStatus.splice(newStatus.indexOf("banned"), 1); } else { newStatus.push("banned"); } setFilters({ ...filters, status: newStatus }); }} > Banned setFilters({ ...filters, status: [] })} > Clear filter
), cell: ({ row }: { row: { original: User } }) => { if (row.original.banned_until) { return Banned; } if (!row.original.email_confirmed_at) { return Unconfirmed; } return Active; }, }, { id: "actions", header: "", cell: ({ row }: { row: { original: User } }) => ( ), }, ]; return (
setSearchQuery(e.target.value)} /> {searchQuery && ( )}
setIsAddUserOpen(true)}> Create new user setIsInviteUserOpen(true)}> Send invitation
handleUserClick(user)} /> {selectedUser && ( )} refetch()} /> refetch()} />
); }