mirror of
https://github.com/Sevichecc/m-oauth.git
synced 2025-04-30 06:59:29 +08:00
feat: useAuth hook
This commit is contained in:
parent
81dbaa3151
commit
86abf78493
7 changed files with 180 additions and 45 deletions
|
@ -1,16 +1,28 @@
|
|||
"use client";
|
||||
import { useEffect, useState } from "react";
|
||||
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 useAuth from "@/hooks/useAuth";
|
||||
import { FormSchema } from "@/components/InputForm";
|
||||
|
||||
export type AppInfo = Pick<FormSchema, "instanceUrl" | "scopes">;
|
||||
const FormContainer = () => {
|
||||
const { appEntry, createApp } = useCreateApp();
|
||||
const [appInfo, setAppInfo] = useState<AppInfo>({
|
||||
instanceUrl: "",
|
||||
scopes: [""],
|
||||
});
|
||||
const { token, getAccessToken } = useAuth(appInfo);
|
||||
|
||||
return (
|
||||
<>
|
||||
<InputForm createApp={createApp} />
|
||||
{appEntry && <DataDisplay appEntry={appEntry} />}
|
||||
<InputForm createApp={createApp} setAppInfo={setAppInfo} />
|
||||
{appEntry && <ResultTable appEntry={appEntry} getAccessToken={getAccessToken}/>}
|
||||
{/* <TokenTable appInfo={appInfo} /> */}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default FormContainer;
|
||||
|
|
|
@ -17,9 +17,12 @@ import {
|
|||
|
||||
import ScopeSection from "@/components/scopes/ScopeSection";
|
||||
import { scopesInfo } from "@/lib/utils";
|
||||
import { Dispatch, SetStateAction } from "react";
|
||||
import { AppEntry } from "@/lib/types";
|
||||
import { AppInfo } from "./FormContainer";
|
||||
|
||||
const formSchema = z.object({
|
||||
instance: z.string().trim(),
|
||||
instanceUrl: z.string().trim(),
|
||||
clientName: z.string().trim(),
|
||||
redirectUris: z.string().trim(),
|
||||
scopes: z.string().array().nonempty().optional(),
|
||||
|
@ -28,29 +31,35 @@ const formSchema = z.object({
|
|||
|
||||
export type FormSchema = z.infer<typeof formSchema>;
|
||||
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>({
|
||||
resolver: zodResolver(formSchema),
|
||||
defaultValues: {
|
||||
instance: "https://",
|
||||
instanceUrl: "https://",
|
||||
clientName: "",
|
||||
redirectUris: "",
|
||||
scopes: ["read"],
|
||||
},
|
||||
});
|
||||
|
||||
const onSubmit = async (values: FormSchema) => {
|
||||
setAppInfo(values)
|
||||
await createApp(values)
|
||||
}
|
||||
|
||||
return (
|
||||
<Form {...form}>
|
||||
<form
|
||||
onSubmit={form.handleSubmit(createApp)}
|
||||
onSubmit={form.handleSubmit(onSubmit)}
|
||||
className="flex flex-col space-y-6 mb-6"
|
||||
>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="instance"
|
||||
name="instanceUrl"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Instance</FormLabel>
|
||||
|
|
|
@ -10,7 +10,13 @@ import {
|
|||
TableRow,
|
||||
} from "@/components/ui/table";
|
||||
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) => (
|
||||
<TableRow className="relative">
|
||||
|
@ -22,8 +28,12 @@ const renderTableRow = (label: string, value: string | undefined) => (
|
|||
</TableRow>
|
||||
);
|
||||
|
||||
const DataDisplay = ({ appEntry }: { appEntry: AppEntry }) => {
|
||||
const ResultTable: React.FC<ResultTableProps> = ({
|
||||
appEntry,
|
||||
getAccessToken,
|
||||
}) => {
|
||||
return (
|
||||
<>
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
|
@ -41,7 +51,9 @@ const DataDisplay = ({ appEntry }: { appEntry: AppEntry }) => {
|
|||
{renderTableRow("Vapid Key", appEntry?.vapid_key)}
|
||||
</TableBody>
|
||||
</Table>
|
||||
<Button onClick={()=>getAccessToken(appEntry)}>Generate AcessToken</Button>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default DataDisplay;
|
||||
export default ResultTable;
|
||||
|
|
9
components/TokenTable.tsx
Normal file
9
components/TokenTable.tsx
Normal file
|
@ -0,0 +1,9 @@
|
|||
'use client'
|
||||
|
||||
const TokenTable = () => {
|
||||
|
||||
return (
|
||||
<div>5</div>
|
||||
);
|
||||
};
|
||||
export default TokenTable;
|
92
hooks/useAuth.ts
Normal file
92
hooks/useAuth.ts
Normal 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;
|
|
@ -1,17 +1,13 @@
|
|||
import { FormSchema } from "@/components/InputForm";
|
||||
import { useCallback, useState } from "react";
|
||||
import { AppEntry } from "@/lib/types";
|
||||
|
||||
type MError = {
|
||||
error: string;
|
||||
};
|
||||
import { AppEntry, MError } from "@/lib/types";
|
||||
|
||||
const useCreateApp = () => {
|
||||
const [appEntry, setAppEntry] = useState<AppEntry>();
|
||||
|
||||
const createApp = useCallback(
|
||||
async ({
|
||||
instance,
|
||||
instanceUrl,
|
||||
website,
|
||||
clientName,
|
||||
redirectUris,
|
||||
|
@ -25,7 +21,7 @@ const useCreateApp = () => {
|
|||
};
|
||||
|
||||
try {
|
||||
let request = await fetch(`${instance}/api/v1/apps`, {
|
||||
let request = await fetch(`${instanceUrl}/api/v1/apps`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
|
|
|
@ -14,7 +14,7 @@ export interface ScopeInfo {
|
|||
description: string;
|
||||
}
|
||||
|
||||
export interface AppEntry {
|
||||
export interface AppEntry {
|
||||
id: string;
|
||||
name: string;
|
||||
website: string | null;
|
||||
|
@ -22,5 +22,10 @@ export interface ScopeInfo {
|
|||
client_id: string;
|
||||
client_secret: string;
|
||||
vapid_key: string;
|
||||
}
|
||||
}
|
||||
|
||||
export type MError = {
|
||||
error: string;
|
||||
error_description: string
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue