feat: useAuth hook

This commit is contained in:
SevicheCC 2023-06-06 23:58:20 +08:00
parent 81dbaa3151
commit 86abf78493
Signed by: SevicheCC
GPG key ID: C577000000000000
7 changed files with 180 additions and 45 deletions

View file

@ -1,16 +1,28 @@
"use client"; "use client";
import { useEffect, useState } from "react";
import InputForm from "@/components/InputForm"; import InputForm from "@/components/InputForm";
import DataDisplay from "@/components/ResultTable"; import ResultTable from "@/components/ResultTable";
import TokenTable from "@/components/TokenTable";
import useCreateApp from "@/hooks/useCreateApp"; import useCreateApp from "@/hooks/useCreateApp";
import useAuth from "@/hooks/useAuth";
import { FormSchema } from "@/components/InputForm";
export type AppInfo = Pick<FormSchema, "instanceUrl" | "scopes">;
const FormContainer = () => { const FormContainer = () => {
const { appEntry, createApp } = useCreateApp(); const { appEntry, createApp } = useCreateApp();
const [appInfo, setAppInfo] = useState<AppInfo>({
instanceUrl: "",
scopes: [""],
});
const { token, getAccessToken } = useAuth(appInfo);
return ( return (
<> <>
<InputForm createApp={createApp} /> <InputForm createApp={createApp} setAppInfo={setAppInfo} />
{appEntry && <DataDisplay appEntry={appEntry} />} {appEntry && <ResultTable appEntry={appEntry} getAccessToken={getAccessToken}/>}
{/* <TokenTable appInfo={appInfo} /> */}
</> </>
); );
}; };
export default FormContainer; export default FormContainer;

View file

@ -17,9 +17,12 @@ import {
import ScopeSection from "@/components/scopes/ScopeSection"; import ScopeSection from "@/components/scopes/ScopeSection";
import { scopesInfo } from "@/lib/utils"; import { scopesInfo } from "@/lib/utils";
import { Dispatch, SetStateAction } from "react";
import { AppEntry } from "@/lib/types";
import { AppInfo } from "./FormContainer";
const formSchema = z.object({ const formSchema = z.object({
instance: z.string().trim(), instanceUrl: z.string().trim(),
clientName: z.string().trim(), clientName: z.string().trim(),
redirectUris: z.string().trim(), redirectUris: z.string().trim(),
scopes: z.string().array().nonempty().optional(), scopes: z.string().array().nonempty().optional(),
@ -28,29 +31,35 @@ const formSchema = z.object({
export type FormSchema = z.infer<typeof formSchema>; export type FormSchema = z.infer<typeof formSchema>;
interface InputFormProps { interface InputFormProps {
createApp: ({}: FormSchema) => Promise<void>; createApp: ({ }: FormSchema) => Promise<void>
setAppInfo: Dispatch<SetStateAction<AppInfo>>
} }
const InputForm: React.FC<InputFormProps> = ({ createApp }) => { const InputForm: React.FC<InputFormProps> = ({ createApp, setAppInfo }) => {
const form = useForm<FormSchema>({ const form = useForm<FormSchema>({
resolver: zodResolver(formSchema), resolver: zodResolver(formSchema),
defaultValues: { defaultValues: {
instance: "https://", instanceUrl: "https://",
clientName: "", clientName: "",
redirectUris: "", redirectUris: "",
scopes: ["read"], scopes: ["read"],
}, },
}); });
const onSubmit = async (values: FormSchema) => {
setAppInfo(values)
await createApp(values)
}
return ( return (
<Form {...form}> <Form {...form}>
<form <form
onSubmit={form.handleSubmit(createApp)} onSubmit={form.handleSubmit(onSubmit)}
className="flex flex-col space-y-6 mb-6" className="flex flex-col space-y-6 mb-6"
> >
<FormField <FormField
control={form.control} control={form.control}
name="instance" name="instanceUrl"
render={({ field }) => ( render={({ field }) => (
<FormItem> <FormItem>
<FormLabel>Instance</FormLabel> <FormLabel>Instance</FormLabel>

View file

@ -10,7 +10,13 @@ import {
TableRow, TableRow,
} from "@/components/ui/table"; } from "@/components/ui/table";
import { AppEntry } from "@/lib/types"; import { AppEntry } from "@/lib/types";
import { CopyButton } from "./ui/copybutton"; import { CopyButton } from "@/components/ui/copybutton";
import { Button } from "@/components/ui/button";
interface ResultTableProps {
appEntry: AppEntry;
getAccessToken: (appEntry: AppEntry) => Promise<void>;
}
const renderTableRow = (label: string, value: string | undefined) => ( const renderTableRow = (label: string, value: string | undefined) => (
<TableRow className="relative"> <TableRow className="relative">
@ -22,8 +28,12 @@ const renderTableRow = (label: string, value: string | undefined) => (
</TableRow> </TableRow>
); );
const DataDisplay = ({ appEntry }: { appEntry: AppEntry }) => { const ResultTable: React.FC<ResultTableProps> = ({
appEntry,
getAccessToken,
}) => {
return ( return (
<>
<Table> <Table>
<TableHeader> <TableHeader>
<TableRow> <TableRow>
@ -41,7 +51,9 @@ const DataDisplay = ({ appEntry }: { appEntry: AppEntry }) => {
{renderTableRow("Vapid Key", appEntry?.vapid_key)} {renderTableRow("Vapid Key", appEntry?.vapid_key)}
</TableBody> </TableBody>
</Table> </Table>
<Button onClick={()=>getAccessToken(appEntry)}>Generate AcessToken</Button>
</>
); );
}; };
export default DataDisplay; export default ResultTable;

View file

@ -0,0 +1,9 @@
'use client'
const TokenTable = () => {
return (
<div>5</div>
);
};
export default TokenTable;

92
hooks/useAuth.ts Normal file
View file

@ -0,0 +1,92 @@
import { useCallback, useState, useMemo } from "react";
import { AppEntry, MError } from "@/lib/types";
import { FormSchema } from "@/components/InputForm";
import { AppInfo } from "@/components/FormContainer";
const useAuth = (appInfo: AppInfo) => {
const { instanceUrl, scopes} = appInfo
const [token, setToken] = useState("");
const getCode = useCallback(
(client_id: string, redirect_uri: string) => {
const code = new URLSearchParams(window.location.search).get("code");
if (!code) {
const params = {
response_type: "code",
client_id,
redirect_uri,
};
if (scopes) {
const scope = 1
}
const queryString = new URLSearchParams(params).toString();
window.location.href = `${instanceUrl}/oauth/authorize?${queryString}`;
} else {
return code;
}
},
[instanceUrl, scopes]
);
const getAuth = useCallback(
async (
code: string,
client_id: string,
redirect_uri: string,
client_secret: string
) => {
const body = new URLSearchParams({
grant_type: "authorization_code",
client_id,
client_secret,
redirect_uri,
code,
});
try {
const response = await fetch(`${instanceUrl}/oauth/token`, {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
body: body.toString(),
});
const result = await response.json();
if (!response.ok) throw new Error((result as MError).error);
return result.access_token;
} catch (error) {
console.error(error);
}
},
[instanceUrl]
);
const getAccessToken = useCallback(
async (appEntry: AppEntry) => {
const { client_id, redirect_uri, client_secret } = appEntry;
const code = getCode(client_id, redirect_uri);
if (code) {
const accessToken = await getAuth(
code,
client_id,
redirect_uri,
client_secret
);
setToken(accessToken);
}
},
[getCode, getAuth]
);
return {
token,
getAccessToken,
};
};
export default useAuth;

View file

@ -1,17 +1,13 @@
import { FormSchema } from "@/components/InputForm"; import { FormSchema } from "@/components/InputForm";
import { useCallback, useState } from "react"; import { useCallback, useState } from "react";
import { AppEntry } from "@/lib/types"; import { AppEntry, MError } from "@/lib/types";
type MError = {
error: string;
};
const useCreateApp = () => { const useCreateApp = () => {
const [appEntry, setAppEntry] = useState<AppEntry>(); const [appEntry, setAppEntry] = useState<AppEntry>();
const createApp = useCallback( const createApp = useCallback(
async ({ async ({
instance, instanceUrl,
website, website,
clientName, clientName,
redirectUris, redirectUris,
@ -25,7 +21,7 @@ const useCreateApp = () => {
}; };
try { try {
let request = await fetch(`${instance}/api/v1/apps`, { let request = await fetch(`${instanceUrl}/api/v1/apps`, {
method: "POST", method: "POST",
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",

View file

@ -24,3 +24,8 @@ export interface ScopeInfo {
vapid_key: string; vapid_key: string;
} }
export type MError = {
error: string;
error_description: string
};