From ae0fc58569945434182abda2f985383515ca92f0 Mon Sep 17 00:00:00 2001 From: SevicheCC <91365763+Sevichecc@users.noreply.github.com> Date: Tue, 6 Jun 2023 00:31:36 +0800 Subject: [PATCH] feat: useCreateApp hook --- app/page.tsx | 37 ++++++++++-- components/DataDisplay.tsx | 43 ++++++++++++++ components/InputForm.tsx | 80 ++++--------------------- components/ScopeItem.tsx | 2 +- components/ScopeSection.tsx | 7 ++- components/ui/card.tsx | 79 +++++++++++++++++++++++++ components/ui/table.tsx | 114 ++++++++++++++++++++++++++++++++++++ hooks/useCreateApp.ts | 54 +++++++++++++++++ lib/types.ts | 27 +++++++++ lib/utils.ts | 38 ++++++++++++ 10 files changed, 402 insertions(+), 79 deletions(-) create mode 100644 components/DataDisplay.tsx create mode 100644 components/ui/card.tsx create mode 100644 components/ui/table.tsx create mode 100644 hooks/useCreateApp.ts create mode 100644 lib/types.ts diff --git a/app/page.tsx b/app/page.tsx index 7efde3b..dcb852d 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -1,15 +1,40 @@ import InputForm from "@/components/InputForm"; import ClientOnly from "@/components/ClientOnly"; +import { + Card, + CardContent, + CardDescription, + CardFooter, + CardHeader, + CardTitle, +} from "@/components/ui/card"; +import DataDisplay from "@/components/DataDisplay"; export default function Home() { return (
-

- M-OAuth -

- - - +
+ + + M-OAuth + Card Description + + + + + + + + {/* +

Card Footer

+
*/} +
+ + + + + +
); } diff --git a/components/DataDisplay.tsx b/components/DataDisplay.tsx new file mode 100644 index 0000000..c752519 --- /dev/null +++ b/components/DataDisplay.tsx @@ -0,0 +1,43 @@ +'use client' + +import useCreateApp from "@/hooks/useCreateApp"; +import { Table, TableBody, TableCaption, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"; +import { AppEntry } from "../lib/types"; + +interface DataDisplayProps { + appEntry: AppEntry; +} + +const renderTableRow = (label: string, value: string | undefined) => ( + + {label} + {value} + +); + +const DataDisplay = () => { + const { appEntry } = useCreateApp(); + + return ( + + A list of your recent invoices. + + + Data Name + Value + + + + {renderTableRow("ID", appEntry?.id)} + {renderTableRow("Name", appEntry?.name)} + {renderTableRow("Website", appEntry?.website || '')} + {renderTableRow("Redirect URI", appEntry?.redirectUri)} + {renderTableRow("Client ID", appEntry?.clientId)} + {renderTableRow("Client Secret", appEntry?.clientSecret)} + {renderTableRow("Vapid Key", appEntry?.vapidKey)} + +
+ ); +}; + +export default DataDisplay; diff --git a/components/InputForm.tsx b/components/InputForm.tsx index cd7f782..2ea5c1a 100644 --- a/components/InputForm.tsx +++ b/components/InputForm.tsx @@ -1,10 +1,10 @@ "use client"; - import * as z from "zod"; import { zodResolver } from "@hookform/resolvers/zod"; import { useForm } from "react-hook-form"; import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; import { Form, FormControl, @@ -14,66 +14,10 @@ import { FormLabel, FormMessage, } from "@/components/ui/form"; -import { Input } from "@/components/ui/input"; -import { - READ_SCOPES, - WRITE_SCOPES, - ADMIN_READ_SCOPES, - ADMIN_WRITE_SCOPES, -} from "@/lib/utils"; -import ScopeSection from "./ScopeSection"; -export type MethodType = - | "read" - | "write" - | "follow" - | "crypto" - | "follow" - | "admin" - | "push"; -export interface ScopeInfo { - method: MethodType; - label: string; - scopes?: string[] | string[][]; - description: string; -} - -const scopesInfo: ScopeInfo[] = [ - { - method: "read", - label: "Read", - scopes: READ_SCOPES, - description: "read account's data", - }, - { - method: "write", - label: "Write", - scopes: WRITE_SCOPES, - description: "modify account's data", - }, - { - method: "admin", - label: "Admin", - scopes: [ADMIN_READ_SCOPES, ADMIN_WRITE_SCOPES], - description: "read all data on the server", - }, - { - method: "follow", - label: "Follow", - description: "modify account relationships,deprecated in 3.5.0 and newer.", - }, - { - method: "push", - label: "Push", - description: "receive push notifications", - }, - - { - method: "crypto", - label: "Crypto", - description: "use end-to-end encryption", - }, -]; +import ScopeSection from "@/components/ScopeSection"; +import { scopesInfo } from "@/lib/utils"; +import useCreateApp from "@/hooks/useCreateApp"; const formSchema = z.object({ instance: z.string().trim(), @@ -83,25 +27,23 @@ const formSchema = z.object({ website: z.string().url().trim().optional(), }); +export type FormSchema = z.infer; + const InputForm = () => { - const form = useForm>({ + const { createApp } = useCreateApp(); + const form = useForm({ resolver: zodResolver(formSchema), defaultValues: { instance: "https://", clientName: "", redirectUris: "", - scopes: [], + scopes: ["read"], }, }); - function onSubmit(values: z.infer) { - const scopes = values.scopes?.join(" "); - console.log(scopes); - } - return (
- + { )} /> - + ); diff --git a/components/ScopeItem.tsx b/components/ScopeItem.tsx index 0bc7f8c..1c7ac81 100644 --- a/components/ScopeItem.tsx +++ b/components/ScopeItem.tsx @@ -1,7 +1,7 @@ "use client"; -import { MethodType } from "./InputForm"; import { Checkbox } from "@/components/ui/checkbox"; +import { MethodType } from "@/lib/types"; interface ScopeCheckboxProps { scope: string; diff --git a/components/ScopeSection.tsx b/components/ScopeSection.tsx index 70f2a14..b124ef5 100644 --- a/components/ScopeSection.tsx +++ b/components/ScopeSection.tsx @@ -1,5 +1,6 @@ "use client"; +import { ChevronsUpDown } from "lucide-react"; import { Checkbox } from "@/components/ui/checkbox"; import { Collapsible, @@ -7,10 +8,10 @@ import { CollapsibleTrigger, } from "@/components/ui/collapsible"; import { Button } from "@/components/ui/button"; -import { ChevronsUpDown } from "lucide-react"; +import ScopeItem from "@/components/ScopeItem"; + +import { ScopeInfo } from "@/lib/types"; -import { ScopeInfo } from "./InputForm"; -import ScopeItem from "./ScopeItem"; interface ScopeSectionProps { info: ScopeInfo; field: any; diff --git a/components/ui/card.tsx b/components/ui/card.tsx new file mode 100644 index 0000000..dff04b6 --- /dev/null +++ b/components/ui/card.tsx @@ -0,0 +1,79 @@ +import * as React from "react" + +import { cn } from "@/lib/utils" + +const Card = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +Card.displayName = "Card" + +const CardHeader = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +CardHeader.displayName = "CardHeader" + +const CardTitle = React.forwardRef< + HTMLParagraphElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +

+)) +CardTitle.displayName = "CardTitle" + +const CardDescription = React.forwardRef< + HTMLParagraphElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +

+)) +CardDescription.displayName = "CardDescription" + +const CardContent = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +

+)) +CardContent.displayName = "CardContent" + +const CardFooter = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +CardFooter.displayName = "CardFooter" + +export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent } diff --git a/components/ui/table.tsx b/components/ui/table.tsx new file mode 100644 index 0000000..bb3a87f --- /dev/null +++ b/components/ui/table.tsx @@ -0,0 +1,114 @@ +import * as React from "react" + +import { cn } from "@/lib/utils" + +const Table = React.forwardRef< + HTMLTableElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+ + +)) +Table.displayName = "Table" + +const TableHeader = React.forwardRef< + HTMLTableSectionElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( + +)) +TableHeader.displayName = "TableHeader" + +const TableBody = React.forwardRef< + HTMLTableSectionElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( + +)) +TableBody.displayName = "TableBody" + +const TableFooter = React.forwardRef< + HTMLTableSectionElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( + +)) +TableFooter.displayName = "TableFooter" + +const TableRow = React.forwardRef< + HTMLTableRowElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( + +)) +TableRow.displayName = "TableRow" + +const TableHead = React.forwardRef< + HTMLTableCellElement, + React.ThHTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +TableHead.displayName = "TableHead" + +const TableCell = React.forwardRef< + HTMLTableCellElement, + React.TdHTMLAttributes +>(({ className, ...props }, ref) => ( + +)) +TableCell.displayName = "TableCell" + +const TableCaption = React.forwardRef< + HTMLTableCaptionElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +TableCaption.displayName = "TableCaption" + +export { + Table, + TableHeader, + TableBody, + TableFooter, + TableHead, + TableRow, + TableCell, + TableCaption, +} diff --git a/hooks/useCreateApp.ts b/hooks/useCreateApp.ts new file mode 100644 index 0000000..9ed10d6 --- /dev/null +++ b/hooks/useCreateApp.ts @@ -0,0 +1,54 @@ +import { FormSchema } from "@/components/InputForm"; +import { useCallback, useState } from "react"; +import { AppEntry } from "@/lib/types"; + +type MError = { + error: string; +}; + +const useCreateApp = () => { + const [appEntry, setAppEntry] = useState(); + + const createApp = useCallback( + async ({ + instance, + website, + clientName, + redirectUris, + scopes, + }: FormSchema) => { + const app = { + website, + client_name: clientName, + redirect_uris: redirectUris, + scopes: scopes?.join(" "), + }; + + console.log("app,", app); + try { + let request = await fetch(`${instance}/api/v1/apps`, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(app), + }); + + if (!request.ok || request.status === 424) { + throw new Error((await request.json()).error); + } + setAppEntry(await request.json()); + } catch (error) { + throw new Error((error as MError).error); + } + }, + [] + ); + console.log(appEntry); + return { + appEntry, + createApp, + }; +}; + +export default useCreateApp; diff --git a/lib/types.ts b/lib/types.ts new file mode 100644 index 0000000..e98d67d --- /dev/null +++ b/lib/types.ts @@ -0,0 +1,27 @@ +export type MethodType = + | "read" + | "write" + | "follow" + | "crypto" + | "follow" + | "admin" + | "push"; + +export interface ScopeInfo { + method: MethodType; + label: string; + scopes?: string[] | string[][]; + description: string; +} + + export interface AppEntry { + id: string; + name: string; + website: string | null; + redirectUri: string; + clientId: string; + clientSecret: string; + vapidKey: string; + } + + \ No newline at end of file diff --git a/lib/utils.ts b/lib/utils.ts index b95e62c..cb8928c 100644 --- a/lib/utils.ts +++ b/lib/utils.ts @@ -1,5 +1,6 @@ import { clsx, type ClassValue } from "clsx"; import { twMerge } from "tailwind-merge"; +import { ScopeInfo } from "./types"; export function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs)); @@ -53,3 +54,40 @@ export const ADMIN_WRITE_SCOPES = [ "admin:write:email_domain_blocks", "admin:write:canonical_email_blocks", ]; + +export const scopesInfo: ScopeInfo[] = [ + { + method: "read", + label: "Read", + scopes: READ_SCOPES, + description: "read account's data", + }, + { + method: "write", + label: "Write", + scopes: WRITE_SCOPES, + description: "modify account's data", + }, + { + method: "admin", + label: "Admin", + scopes: [ADMIN_READ_SCOPES, ADMIN_WRITE_SCOPES], + description: "read all data on the server", + }, + { + method: "follow", + label: "Follow", + description: "modify account relationships,deprecated in 3.5.0 and newer.", + }, + { + method: "push", + label: "Push", + description: "receive push notifications", + }, + + { + method: "crypto", + label: "Crypto", + description: "use end-to-end encryption", + }, +];