feat: credentials modal

This commit is contained in:
2025-05-31 17:31:22 +02:00
parent cef9dae4d3
commit 63437d6dc7
2 changed files with 90 additions and 5 deletions

View File

@ -0,0 +1,65 @@
import { createPortal } from "react-dom";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { X } from "lucide-react";
import { useAdmin } from "@/store/admin";
import type { ApiServiceCredentials } from "@/types";
const download = (credentials: ApiServiceCredentials) => {
const jsonStr = JSON.stringify(credentials, null, 2);
const blob = new Blob([jsonStr], { type: "application/json" });
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = `credentials.json`;
a.click();
URL.revokeObjectURL(url);
};
const ApiServiceCredentialsModal = () => {
const credentials = useAdmin((state) => state.createdCredentials);
const resetCredentials = useAdmin((state) => state.resetCredentials);
const portalRoot = document.getElementById("portal-root");
if (!portalRoot || !credentials) return null;
return createPortal(
<div className="fixed z-50 inset-0 flex items-center justify-center bg-black/30 dark:bg-white/30 px-5">
<div className="rounded-2xl flex flex-col items-stretch bg-white dark:bg-black min-w-[300px] max-w-md w-full">
<div className="flex flex-row items-center justify-between p-4 border-b dark:border-gray-800 border-gray-300">
<p className="text-gray-800 dark:text-gray-200">New Credentials</p>
<Button variant="icon" onClick={resetCredentials}>
<X />
</Button>
</div>
<div className="p-4">
<div className="flex flex-col gap-2 mb-4">
<p className="text-gray-600 dark:text-gray-400 text-sm">
Client ID
</p>
<Input value={credentials.client_id} disabled />
</div>
<div className="flex flex-col gap-2 mb-4">
<p className="text-gray-600 dark:text-gray-400 text-sm">
Client Secret
</p>
<Input value={credentials.client_secret} disabled />
</div>
<div className="mt-4 flex flex-row items-center justify-between">
<Button variant="contained" onClick={resetCredentials}>
Close
</Button>
<Button variant="outlined" onClick={() => download(credentials)}>
Download
</Button>
</div>
</div>
</div>
</div>,
portalRoot,
);
};
export default ApiServiceCredentialsModal;

View File

@ -1,7 +1,9 @@
import Breadcrumbs from "@/components/ui/breadcrumbs";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import type { FC } from "react";
import ApiServiceCredentialsModal from "@/feature/ApiServiceCredentialsModal";
import { useAdmin } from "@/store/admin";
import { useCallback, type FC } from "react";
import { useForm } from "react-hook-form";
import { Link } from "react-router";
@ -26,13 +28,31 @@ const ApiServiceCreatePage: FC = () => {
},
});
const onSubmit = (data: FormData) => {
console.log("Form submitted:", data);
// handle create logic here (e.g. API call)
};
const createApiService = useAdmin((state) => state.createApiService);
const credentials = useAdmin((state) => state.createdCredentials);
const onSubmit = useCallback(
(data: FormData) => {
console.log("Form submitted:", data);
createApiService({
name: data.name,
description: data.description ?? "",
redirect_uris: data.redirectUris.trim().split("\n"),
scopes: data.scopes.trim().split(" "),
grant_types: data.grantTypes
? data.grantTypes.trim().split(" ")
: ["authorization_code"],
is_active: data.enabled,
});
},
[createApiService],
);
return (
<div className="p-4">
{credentials !== null && <ApiServiceCredentialsModal />}
<Breadcrumbs
items={[
{ href: "/admin", label: "Admin" },