feat: admin view user page

This commit is contained in:
2025-06-04 19:33:41 +02:00
parent 6164b77bee
commit e85b23b3e8
2 changed files with 144 additions and 4 deletions

View File

@ -17,6 +17,7 @@ import NotAllowedPage from "./pages/NotAllowed";
import NotFoundPage from "./pages/NotFound";
import ApiServiceEditPage from "./pages/Admin/ApiServices/Update";
import AdminUsersPage from "./pages/Admin/Users";
import AdminViewUserPage from "./pages/Admin/Users/View";
const router = createBrowserRouter([
{
@ -59,10 +60,10 @@ const router = createBrowserRouter([
children: [
{ index: true, element: <AdminUsersPage /> },
// { path: "create", element: <ApiServiceCreatePage /> },
// {
// path: "view/:serviceId",
// element: <ViewApiServicePage />,
// },
{
path: "view/:userId",
element: <AdminViewUserPage />,
},
// {
// path: "edit/:serviceId",
// element: <ApiServiceEditPage />,

View File

@ -0,0 +1,139 @@
import Breadcrumbs from "@/components/ui/breadcrumbs";
import { Button } from "@/components/ui/button";
import Avatar from "@/feature/Avatar";
import { useUsers } from "@/store/admin/users";
import { useEffect, type FC } from "react";
import { Link, useParams } from "react-router";
const InfoCard = ({
title,
children,
}: {
title: string;
children: React.ReactNode;
}) => (
<div className="border dark:border-gray-800 border-gray-300 rounded mb-4">
<div className="p-4 border-b dark:border-gray-800 border-gray-300">
<h2 className="text-gray-800 dark:text-gray-200 font-semibold text-lg">
{title}
</h2>
</div>
<div className="p-4">{children}</div>
</div>
);
const AdminViewUserPage: FC = () => {
const { userId } = useParams();
const user = useUsers((state) => state.current);
// const loading = useApiServices((state) => state.fetchingApiService);
const loadUser = useUsers((state) => state.fetchUser);
useEffect(() => {
if (typeof userId === "string") loadUser(userId);
}, [loadUser, userId]);
if (!user) {
return (
<div className="p-4 flex items-center justify-center h-[60vh]">
<div className="text-center">
<div className="animate-spin rounded-full h-8 w-8 border-2 border-blue-500 border-t-transparent mx-auto mb-3" />
<p className="text-gray-600 dark:text-gray-400">Loading User...</p>
</div>
</div>
);
}
return (
<div className="dark:text-gray-200 text-gray-800 p-4">
<Breadcrumbs
items={[
{ href: "/admin", label: "Admin" },
{ href: "/admin/users", label: "Users" },
{ label: "View User" },
]}
/>
<div className="sm:p-4 pt-4">
{/* 📋 Main Details */}
<InfoCard title="Personal Info">
<div className="flex flex-col gap-4 text-sm">
<div className="flex flex-col gap-4">
<span className="font-medium text-gray-900 dark:text-white">
Avatar:
</span>
<Avatar
avatarId={user.profile_picture ?? undefined}
className="w-16 h-16"
iconSize={28}
/>
</div>
<div>
<span className="font-medium text-gray-900 dark:text-white">
Full Name:
</span>{" "}
{user.full_name}
</div>
<div>
<span className="font-medium text-gray-900 dark:text-white">
Email:
</span>{" "}
{user.email}
</div>
<div>
<span className="font-medium text-gray-900 dark:text-white">
Phone Number:
</span>{" "}
{user.phone_number || "-"}{" "}
</div>
<div>
<span className="font-medium text-gray-900 dark:text-white">
Is Admin:
</span>{" "}
<span
className={`font-semibold px-2 py-1 rounded ${
user.is_admin
? "bg-green-200 text-green-800 dark:bg-green-700/20 dark:text-green-300"
: "bg-red-200 text-red-800 dark:bg-red-700/20 dark:text-red-300"
}`}
>
{user.is_admin ? "Yes" : "No"}
</span>
</div>
<div>
<span className="font-medium text-gray-900 dark:text-white">
Created At:
</span>{" "}
{new Date(user.created_at).toLocaleString()}
</div>
<div>
<span className="font-medium text-gray-900 dark:text-white">
Last Login At:
</span>{" "}
{user.last_login
? new Date(user.last_login).toLocaleString()
: "never"}
</div>
</div>
</InfoCard>
{/* 🚀 Actions */}
<div className="flex flex-wrap gap-4 mt-6 justify-between items-center">
<Link to="/admin/users">
<Button variant="outlined">Back</Button>
</Link>
<div className="flex flex-row items-center gap-4">
<Link
to={`/admin/users/edit/${userId}`}
className="hover:underline hover:text-gray-600 dark:hover:text-gray-300 transition-colors"
>
<Button variant="contained">Edit</Button>
</Link>
</div>
</div>
</div>
</div>
);
};
export default AdminViewUserPage;