From d56594d3289002566f4653d607f0837befd65109 Mon Sep 17 00:00:00 2001 From: polwex Date: Thu, 15 May 2025 10:13:00 +0700 Subject: wtf man --- src/components/Login.tsx | 305 ++++++++++++++++++++++++++++++++++++++++++ src/components/Login2.tsx | 148 ++++++++++++++++++++ src/components/actiontest.tsx | 27 ++++ src/components/counter.tsx | 12 +- src/components/ui/button.tsx | 58 ++++++++ src/components/ui/card.tsx | 68 ++++++++++ src/components/ui/form.tsx | 165 +++++++++++++++++++++++ src/components/ui/input.tsx | 19 +++ src/components/ui/label.tsx | 24 ++++ src/components/ui/select.tsx | 179 +++++++++++++++++++++++++ src/components/ui/sonner.tsx | 23 ++++ src/components/ui/spinner.tsx | 8 ++ 12 files changed, 1033 insertions(+), 3 deletions(-) create mode 100644 src/components/Login.tsx create mode 100644 src/components/Login2.tsx create mode 100644 src/components/actiontest.tsx create mode 100644 src/components/ui/button.tsx create mode 100644 src/components/ui/card.tsx create mode 100644 src/components/ui/form.tsx create mode 100644 src/components/ui/input.tsx create mode 100644 src/components/ui/label.tsx create mode 100644 src/components/ui/select.tsx create mode 100644 src/components/ui/sonner.tsx create mode 100644 src/components/ui/spinner.tsx (limited to 'src/components') diff --git a/src/components/Login.tsx b/src/components/Login.tsx new file mode 100644 index 0000000..5747d06 --- /dev/null +++ b/src/components/Login.tsx @@ -0,0 +1,305 @@ +"use client"; + +import { postLogin, postRegister } from "@/actions/login"; +import { cn } from "@/lib/utils"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { useForm } from "react-hook-form"; +import { z } from "zod"; + +import { toast } from "sonner"; +import { Button } from "@/components/ui/button"; +import { + Card, + CardHeader, + CardDescription, + CardContent, + CardFooter, + CardTitle, +} from "@/components/ui/card"; +import { + Form, + FormControl, + FormDescription, + FormField, + FormItem, + FormLabel, + FormMessage, +} from "@/components/ui/form"; +import { Label } from "@/components/ui/label"; +import { Input } from "@/components/ui/input"; +import { useActionState } from "react"; + +const FormSchema = z.object({ + username: z.string().min(2, { + message: "Username must be at least 2 characters.", + }), + password: z.string().min(2, { + message: "Password must be at least 2 characters.", + }), +}); +export default function AuthScreen() { + return ; +} + +function OOldform() { + const [state, formAction, isPending] = useActionState< + { msg: string }, + FormData + >(postLogin, { msg: "init" }); + return ( +
+ {state.msg} + + + +
+ Don't have an account?{" "} + + Sign up + +
+
+ ); +} +function Oldform() { + const [state, formAction, isPending] = useActionState< + { msg: string }, + FormData + >(postLogin, { msg: "init" }); + return ( +
+ {state.msg} +
+ + + Welcome back + Login to Sorlang +

{state.msg}

+
+ +
+
+ + +
+ +
+ Don't have an account?{" "} + + Sign up + +
+
+
+
+
+ By clicking continue, you agree to our{" "} + Terms of Service and Privacy Policy. +
+
+
+ ); +} + +function Register({ setRegister }: { setRegister: (b: boolean) => void }) { + const form = useForm>({ + resolver: zodResolver(FormSchema), + defaultValues: { + username: "", + password: "", + }, + }); + + async function onSubmit(data: z.infer) { + const body = JSON.stringify({ + name: data.username, + creds: data.password, + }); + const opts = { + method: "POST", + headers: { "Content-type": "application/json" }, + body, + }; + const res = await fetch("/api/db/user/new", opts); + const j = await res.json(); + console.log(j); + if ("error" in j) toast(`Error: ${j.error}`); + else { + toast("Register successful"); + } + } + + return ( + + Register +
+ + + ( + + Username + + + + + This is your public display name. + + + + )} + /> + ( + + Password + + + + + + )} + /> + + + + +
+ +
+ ); +} + +function LoginForm({ + className, + ...props +}: React.ComponentPropsWithoutRef<"div">) { + const form = useForm>({ + resolver: zodResolver(FormSchema), + defaultValues: { + username: "", + password: "", + }, + }); + async function onSubmit(data: z.infer) { + console.log("oh hai"); + const body = JSON.stringify({ + name: data.username, + creds: data.password, + }); + const opts = { + method: "POST", + headers: { "Content-type": "application/json" }, + body, + }; + const res = await fetch("/api/login", opts); + const j = await res.json(); + console.log({ j }); + if ("error" in j) toast(`Error! ${j.error}`); + else { + toast("Login successful"); + } + } + return ( +
+ + + Welcome back + Login to Sorlang + + +
+ +
+
+ ( + + Username + + + + + + )} + /> + ( + + + Password + + Forgot your password? + + + + + + + + )} + /> +
+ +
+ Don't have an account?{" "} + + Sign up + +
+
+
+ +
+
+
+ By clicking continue, you agree to our Terms of Service{" "} + and Privacy Policy. +
+
+ ); +} diff --git a/src/components/Login2.tsx b/src/components/Login2.tsx new file mode 100644 index 0000000..2164b1a --- /dev/null +++ b/src/components/Login2.tsx @@ -0,0 +1,148 @@ +"use client"; + +import { FormState, postLogin, postRegister } from "@/actions/login"; + +import { useActionState, useEffect, useState } from "react"; +import { + Card, + CardHeader, + CardDescription, + CardContent, + CardFooter, + CardTitle, +} from "@/components/ui/card"; +import { + Form, + FormControl, + FormDescription, + FormField, + FormItem, + FormLabel, + FormMessage, +} from "@/components/ui/form"; +import { Label } from "@/components/ui/label"; +import { Input } from "@/components/ui/input"; +import { Button } from "@/components/ui/button"; +import { useRouter } from "waku"; + +export default function AuthScreen() { + const [isReg, setReg] = useState(false); + return setReg((b) => !b)} />; +} + +function OOldform({ isReg, toggle }: { isReg: boolean; toggle: () => void }) { + const regstrings = { + title: "Welcome to Sorlang", + desc: "Sign up", + button: "Sign up", + toggle: "Have an account?", + toggle2: "Login", + }; + const logstrings = { + title: "Welcome back", + desc: "Login to Sorlang", + button: "Login", + toggle: "Don't have an account?", + toggle2: "Sign up", + }; + const [strings, setStrings] = useState(logstrings); + + useEffect(() => { + if (isReg) setStrings(regstrings); + else setStrings(logstrings); + }, [isReg]); + + const [state, formAction, isPending] = useActionState( + isReg ? postRegister : postLogin, + {}, + "/login", + ); + // const nav = useRouter(); + // useEffect(() => { + // if (state.success) nav.replace("/"); + // }, [state]); + return ( +
+
+ + + {strings.title} + {strings.desc} + + +
+
+ + +
+ +
+ {strings.toggle} + + {strings.toggle2} + +
+
+ {state.error &&

{state.error}

} +
+
+
+ By clicking continue, you agree to our{" "} + Terms of Service and Privacy Policy. +
+
+
+ //
+ // {state.msg} + // + // + // + //
+ // Don't have an account?{" "} + // + // Sign up + // + //
+ //
+ ); +} diff --git a/src/components/actiontest.tsx b/src/components/actiontest.tsx new file mode 100644 index 0000000..863f289 --- /dev/null +++ b/src/components/actiontest.tsx @@ -0,0 +1,27 @@ +"use client"; + +import { testFn, testLogin } from "@/actions/test"; +import { useActionState, useState } from "react"; + +export default function TestForm() { + const [state, formAction, isPending] = useActionState( + testLogin, + 0, + ); + return ( +
+

State: {state}

+ + + +
+ ); +} diff --git a/src/components/counter.tsx b/src/components/counter.tsx index 0e540b8..2122b75 100644 --- a/src/components/counter.tsx +++ b/src/components/counter.tsx @@ -1,11 +1,17 @@ -'use client'; +"use client"; -import { useState } from 'react'; +import { testFn, testLogin } from "@/actions/test"; +import { useState } from "react"; export const Counter = () => { const [count, setCount] = useState(0); - const handleIncrement = () => setCount((c) => c + 1); + const handleIncrement = async () => { + setCount((c) => c + 1); + const res = await testFn("rofl"); + console.log({ res }); + const oof = testLogin({ name: "yago", creds: "xd" }); + }; return (
diff --git a/src/components/ui/button.tsx b/src/components/ui/button.tsx new file mode 100644 index 0000000..61875fc --- /dev/null +++ b/src/components/ui/button.tsx @@ -0,0 +1,58 @@ +import * as React from "react" +import { Slot } from "@radix-ui/react-slot" +import { cva, type VariantProps } from "class-variance-authority" + +import { cn } from "@/lib/utils" + +const buttonVariants = cva( + "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-[color,box-shadow] disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0 ring-ring/10 dark:ring-ring/20 dark:outline-ring/40 outline-ring/50 focus-visible:ring-4 focus-visible:outline-1 aria-invalid:focus-visible:ring-0", + { + variants: { + variant: { + default: + "bg-primary text-primary-foreground shadow-sm hover:bg-primary/90", + destructive: + "bg-destructive text-destructive-foreground shadow-xs hover:bg-destructive/90", + outline: + "border border-input bg-background shadow-xs hover:bg-accent hover:text-accent-foreground", + secondary: + "bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80", + ghost: "hover:bg-accent hover:text-accent-foreground", + link: "text-primary underline-offset-4 hover:underline", + }, + size: { + default: "h-9 px-4 py-2 has-[>svg]:px-3", + sm: "h-8 rounded-md px-3 has-[>svg]:px-2.5", + lg: "h-10 rounded-md px-6 has-[>svg]:px-4", + icon: "size-9", + }, + }, + defaultVariants: { + variant: "default", + size: "default", + }, + } +) + +function Button({ + className, + variant, + size, + asChild = false, + ...props +}: React.ComponentProps<"button"> & + VariantProps & { + asChild?: boolean + }) { + const Comp = asChild ? Slot : "button" + + return ( + + ) +} + +export { Button, buttonVariants } diff --git a/src/components/ui/card.tsx b/src/components/ui/card.tsx new file mode 100644 index 0000000..3ff199b --- /dev/null +++ b/src/components/ui/card.tsx @@ -0,0 +1,68 @@ +import * as React from "react" + +import { cn } from "@/lib/utils" + +function Card({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function CardHeader({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function CardTitle({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function CardDescription({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function CardContent({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function CardFooter({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent } diff --git a/src/components/ui/form.tsx b/src/components/ui/form.tsx new file mode 100644 index 0000000..8a83b32 --- /dev/null +++ b/src/components/ui/form.tsx @@ -0,0 +1,165 @@ +import * as React from "react" +import * as LabelPrimitive from "@radix-ui/react-label" +import { Slot } from "@radix-ui/react-slot" +import { + Controller, + ControllerProps, + FieldPath, + FieldValues, + FormProvider, + useFormContext, + useFormState, +} from "react-hook-form" + +import { cn } from "@/lib/utils" +import { Label } from "@/components/ui/label" + +const Form = FormProvider + +type FormFieldContextValue< + TFieldValues extends FieldValues = FieldValues, + TName extends FieldPath = FieldPath, +> = { + name: TName +} + +const FormFieldContext = React.createContext( + {} as FormFieldContextValue +) + +const FormField = < + TFieldValues extends FieldValues = FieldValues, + TName extends FieldPath = FieldPath, +>({ + ...props +}: ControllerProps) => { + return ( + + + + ) +} + +const useFormField = () => { + const fieldContext = React.useContext(FormFieldContext) + const itemContext = React.useContext(FormItemContext) + const { getFieldState } = useFormContext() + const formState = useFormState({ name: fieldContext.name }) + const fieldState = getFieldState(fieldContext.name, formState) + + if (!fieldContext) { + throw new Error("useFormField should be used within ") + } + + const { id } = itemContext + + return { + id, + name: fieldContext.name, + formItemId: `${id}-form-item`, + formDescriptionId: `${id}-form-item-description`, + formMessageId: `${id}-form-item-message`, + ...fieldState, + } +} + +type FormItemContextValue = { + id: string +} + +const FormItemContext = React.createContext( + {} as FormItemContextValue +) + +function FormItem({ className, ...props }: React.ComponentProps<"div">) { + const id = React.useId() + + return ( + +
+ + ) +} + +function FormLabel({ + className, + ...props +}: React.ComponentProps) { + const { error, formItemId } = useFormField() + + return ( +