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";
|
"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;
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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;
|
||||||
|
|
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 { 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",
|
||||||
|
|
|
@ -24,3 +24,8 @@ export interface ScopeInfo {
|
||||||
vapid_key: string;
|
vapid_key: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type MError = {
|
||||||
|
error: string;
|
||||||
|
error_description: string
|
||||||
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue