feat: admin view user
page
This commit is contained in:
@ -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 />,
|
||||
|
139
web/src/pages/Admin/Users/View/index.tsx
Normal file
139
web/src/pages/Admin/Users/View/index.tsx
Normal 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;
|
Reference in New Issue
Block a user