feat: view api service page
This commit is contained in:
@ -12,6 +12,7 @@ import PersonalInfoPage from "./pages/PersonalInfo";
|
|||||||
import ApiServicesPage from "./pages/ApiServices";
|
import ApiServicesPage from "./pages/ApiServices";
|
||||||
import AdminLayout from "./layout/AdminLayout";
|
import AdminLayout from "./layout/AdminLayout";
|
||||||
import ApiServiceCreatePage from "./pages/ApiServices/Create";
|
import ApiServiceCreatePage from "./pages/ApiServices/Create";
|
||||||
|
import ViewApiServicePage from "./pages/ApiServices/View";
|
||||||
|
|
||||||
const router = createBrowserRouter([
|
const router = createBrowserRouter([
|
||||||
{
|
{
|
||||||
@ -39,6 +40,10 @@ const router = createBrowserRouter([
|
|||||||
children: [
|
children: [
|
||||||
{ index: true, element: <ApiServicesPage /> },
|
{ index: true, element: <ApiServicesPage /> },
|
||||||
{ path: "create", element: <ApiServiceCreatePage /> },
|
{ path: "create", element: <ApiServiceCreatePage /> },
|
||||||
|
{
|
||||||
|
path: "view/:serviceId",
|
||||||
|
element: <ViewApiServicePage />,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
198
web/src/pages/ApiServices/View/index.tsx
Normal file
198
web/src/pages/ApiServices/View/index.tsx
Normal file
@ -0,0 +1,198 @@
|
|||||||
|
import Breadcrumbs from "@/components/ui/breadcrumbs";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import { Input } from "@/components/ui/input";
|
||||||
|
import { useAdmin } from "@/store/admin";
|
||||||
|
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 ViewApiServicePage: FC = () => {
|
||||||
|
const { serviceId } = useParams();
|
||||||
|
const apiService = useAdmin((state) => state.viewApiService);
|
||||||
|
// const loading = useAdmin((state) => state.fetchingApiService);
|
||||||
|
|
||||||
|
const loadService = useAdmin((state) => state.fetchApiService);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (typeof serviceId === "string") loadService(serviceId);
|
||||||
|
}, [loadService, serviceId]);
|
||||||
|
|
||||||
|
if (!apiService) {
|
||||||
|
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 API Service...
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="dark:text-gray-200 text-gray-800 p-4">
|
||||||
|
<Breadcrumbs
|
||||||
|
items={[
|
||||||
|
{ href: "/admin", label: "Admin" },
|
||||||
|
{ href: "/admin/api-services", label: "API Services" },
|
||||||
|
{ label: "View API Service" },
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div className="p-4">
|
||||||
|
{/* 📋 Main Details */}
|
||||||
|
<InfoCard title="API Service Details">
|
||||||
|
<div className="flex flex-col gap-4 text-sm text-gray-700 dark:text-gray-300">
|
||||||
|
<div>
|
||||||
|
<span className="font-medium text-gray-900 dark:text-white">
|
||||||
|
Name:
|
||||||
|
</span>{" "}
|
||||||
|
{apiService.name}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span className="font-medium text-gray-900 dark:text-white">
|
||||||
|
Description:
|
||||||
|
</span>{" "}
|
||||||
|
{apiService.description}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span className="font-medium text-gray-900 dark:text-white">
|
||||||
|
Redirect URIs:
|
||||||
|
</span>
|
||||||
|
<ul className="list-disc list-inside ml-4 mt-1">
|
||||||
|
{apiService.redirect_uris.map((uri) => (
|
||||||
|
<li key={uri}>{uri}</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span className="font-medium text-gray-900 dark:text-white">
|
||||||
|
Scopes:
|
||||||
|
</span>
|
||||||
|
<div className="flex flex-wrap gap-2 mt-1">
|
||||||
|
{apiService.scopes.map((scope) => (
|
||||||
|
<span
|
||||||
|
key={scope}
|
||||||
|
className="bg-blue-100 dark:bg-blue-800/30 text-blue-700 dark:text-blue-300 text-xs font-medium px-2 py-1 rounded"
|
||||||
|
>
|
||||||
|
{scope}
|
||||||
|
</span>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span className="font-medium text-gray-900 dark:text-white">
|
||||||
|
Grant Types:
|
||||||
|
</span>
|
||||||
|
<div className="flex flex-wrap gap-2 mt-1">
|
||||||
|
{apiService.grant_types.map((grant) => (
|
||||||
|
<span
|
||||||
|
key={grant}
|
||||||
|
className="bg-green-100 dark:bg-green-800/30 text-green-700 dark:text-green-300 text-xs font-medium px-2 py-1 rounded"
|
||||||
|
>
|
||||||
|
{grant}
|
||||||
|
</span>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span className="font-medium text-gray-900 dark:text-white">
|
||||||
|
Created At:
|
||||||
|
</span>{" "}
|
||||||
|
{new Date(apiService.created_at).toLocaleString()}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span className="font-medium text-gray-900 dark:text-white">
|
||||||
|
Updated At:
|
||||||
|
</span>{" "}
|
||||||
|
{new Date(apiService.updated_at).toLocaleString()}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span className="font-medium text-gray-900 dark:text-white">
|
||||||
|
Status:
|
||||||
|
</span>{" "}
|
||||||
|
<span
|
||||||
|
className={`font-semibold px-2 py-1 rounded ${
|
||||||
|
apiService.is_active
|
||||||
|
? "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"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{apiService.is_active ? "Active" : "Inactive"}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</InfoCard>
|
||||||
|
|
||||||
|
{/* 🔐 Credentials */}
|
||||||
|
<InfoCard title="Client Credentials">
|
||||||
|
<div className="flex flex-col gap-4">
|
||||||
|
<div>
|
||||||
|
<p className="text-sm text-gray-600 dark:text-gray-400 mb-1">
|
||||||
|
<span className="font-medium text-gray-900 dark:text-white">
|
||||||
|
Client ID:
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
<Input value={apiService.client_id} disabled />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<p className="text-sm text-gray-600 dark:text-gray-400 mb-1">
|
||||||
|
<span className="font-medium text-gray-900 dark:text-white">
|
||||||
|
Client Secret:
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
<Input value="***************" disabled />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Button variant="outlined" onClick={() => {}}>
|
||||||
|
Regenerate Credentials
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</InfoCard>
|
||||||
|
|
||||||
|
{/* 🚀 Actions */}
|
||||||
|
<div className="flex flex-wrap gap-4 mt-6 justify-between items-center">
|
||||||
|
<Link to="/admin/api-services">
|
||||||
|
<Button variant="outlined">Back</Button>
|
||||||
|
</Link>
|
||||||
|
<div className="flex flex-row items-center gap-4">
|
||||||
|
<Button
|
||||||
|
variant="text"
|
||||||
|
className={
|
||||||
|
apiService.is_active
|
||||||
|
? "text-red-400 hover:text-red-500"
|
||||||
|
: "text-green-400 hover:text-green-500"
|
||||||
|
}
|
||||||
|
onClick={() => {}}
|
||||||
|
>
|
||||||
|
{apiService.is_active ? "Disable" : "Enable"}
|
||||||
|
</Button>
|
||||||
|
<Button variant="contained" disabled>
|
||||||
|
Edit
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ViewApiServicePage;
|
Reference in New Issue
Block a user