Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
362 changes: 356 additions & 6 deletions package-lock.json

Large diffs are not rendered by default.

15 changes: 11 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,20 @@
},
"dependencies": {
"@floating-ui/dom": "^1.7.4",
"@hookform/resolvers": "^5.2.2",
"@mantine/core": "^8.3.4",
"@mantine/dates": "^8.3.5",
"@mantine/hooks": "^8.3.4",
"@neondatabase/serverless": "^1.0.2",
"@next/eslint-plugin-next": "^15.5.4",
"d3": "^7.9.0",
"@radix-ui/react-label": "^2.1.8",
"@radix-ui/react-separator": "^1.1.8",
"@radix-ui/react-slot": "^1.2.4",
"@tanstack/react-table": "^8.21.3",
"better-auth": "^1.4.1",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"d3": "^7.9.0",
"dotenv": "^17.2.3",
"drizzle-orm": "^0.44.7",
"lucide": "^0.544.0",
Expand All @@ -30,19 +35,21 @@
"react": "19.1.0",
"react-dom": "19.1.0",
"react-excel-renderer": "^1.1.0",
"react-hook-form": "^7.67.0",
"react-icons": "^5.5.0",
"tailwind-merge": "^3.4.0",
"tailwindcss-animate": "^1.0.7",
"react-icons": "^5.5.0",
"vercel": "^48.2.0",
"xlsx": "^0.18.5"
"xlsx": "^0.18.5",
"zod": "^4.1.13"
},
"devDependencies": {
"@eslint/js": "^9.37.0",
"@tailwindcss/postcss": "^4",
"@types/node": "^20",
"@types/react": "^19",
"@types/react-dom": "^19",
"drizzle-kit": "^0.31.6",
"drizzle-kit": "^0.31.7",
"eslint": "^9.37.0",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-react": "^7.37.5",
Expand Down
4 changes: 4 additions & 0 deletions src/app/api/auth/[...all]/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { auth } from "@/lib/auth";
import { toNextJsHandler } from "better-auth/next-js";

export const { POST, GET } = toNextJsHandler(auth);
7 changes: 7 additions & 0 deletions src/app/dashboard/dummyPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export default function DummyPage() {
return (
<div>
<h1>Hello World</h1>
</div>
);
}
11 changes: 11 additions & 0 deletions src/app/signup/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { SignupForm } from "@/components/signup-form";

export default function SignupPage() {
return (
<div className="bg-muted flex min-h-svh flex-col items-center justify-center p-6 md:p-10">
<div className="w-full max-w-sm md:max-w-4xl">
<SignupForm />
</div>
</div>
);
}
Empty file added src/components/signin-form.tsx
Empty file.
218 changes: 218 additions & 0 deletions src/components/signup-form.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
"use client";

import { zodResolver } from "@hookform/resolvers/zod";
import { useForm } from "react-hook-form";

import { cn } from "@/lib/utils";
import { Button } from "@/components/ui/button";
import { Card, CardContent } from "@/components/ui/card";
import {
Field,
FieldDescription,
FieldGroup,
FieldLabel,
FieldSeparator,
} from "@/components/ui/field";

import {
Form,
FormControl,
FormDescription,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "@/components/ui/form";

import { Input } from "@/components/ui/input";
import { signUp } from "@/server/users";

import { z } from "zod";

const formSchema = z.object({
em: z.email(),
pw: z.string().min(8),
});

export function SignupForm({
className,
...props
}: React.ComponentProps<"div">) {
// 1. Define your form.
const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
defaultValues: {
em: "",
pw: "",
},
});

// 2. Define a submit handler.
function onSubmit(values: z.infer<typeof formSchema>) {
signUp(values.em, values.pw);
}
return (
<div className={cn("flex flex-col gap-6", className)} {...props}>
<Card className="overflow-hidden p-0">
<CardContent className="grid p-0 md:grid-cols-2">
<Form {...form}>
<form
onSubmit={form.handleSubmit(onSubmit)}
className="space-y-8"
>
<FieldGroup>
<div className="flex flex-col items-center gap-2 text-center">
<h1 className="text-2xl font-bold">
Create your account
</h1>
<p className="text-muted-foreground text-sm text-balance">
Enter your email below to create your
account
</p>
</div>
<Field>
<FormField
control={form.control}
name="em"
render={({ field }) => (
<FormItem>
<FormLabel>Email</FormLabel>
<FormControl>
<Input
placeholder="address@gmail.com"
{...field}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FieldDescription>
We&apos;ll use this to contact you. We
will not share your email with anyone
else.
</FieldDescription>
</Field>
<Field>
<Field className="grid grid-cols-2 gap-4">
<Field>
<FormField
control={form.control}
name="pw"
render={({ field }) => (
<FormItem>
<FormLabel>
Password
</FormLabel>
<FormControl>
<Input
placeholder=""
{...field}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</Field>
<Field>
<FormField
control={form.control}
name="pw"
render={({ field }) => (
<FormItem>
<FormLabel>
Confirm Password
</FormLabel>
<FormControl>
<Input
placeholder="shadcn"
{...field}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</Field>
</Field>
<FieldDescription>
Must be at least 8 characters long.
</FieldDescription>
</Field>
<Field>
<Button type="submit">
Create Account
</Button>
</Field>
<FieldSeparator className="*:data-[slot=field-separator-content]:bg-card">
Or continue with
</FieldSeparator>
<Field className="grid grid-cols-3 gap-4">
<Button variant="outline" type="button">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
>
<path
d="M12.152 6.896c-.948 0-2.415-1.078-3.96-1.04-2.04.027-3.91 1.183-4.961 3.014-2.117 3.675-.546 9.103 1.519 12.09 1.013 1.454 2.208 3.09 3.792 3.039 1.52-.065 2.09-.987 3.935-.987 1.831 0 2.35.987 3.96.948 1.637-.026 2.676-1.48 3.676-2.948 1.156-1.688 1.636-3.325 1.662-3.415-.039-.013-3.182-1.221-3.22-4.857-.026-3.04 2.48-4.494 2.597-4.559-1.429-2.09-3.623-2.324-4.39-2.376-2-.156-3.675 1.09-4.61 1.09zM15.53 3.83c.843-1.012 1.4-2.427 1.245-3.83-1.207.052-2.662.805-3.532 1.818-.78.896-1.454 2.338-1.273 3.714 1.338.104 2.715-.688 3.559-1.701"
fill="currentColor"
/>
</svg>
<span className="sr-only">
Sign up with Apple
</span>
</Button>
<Button variant="outline" type="button">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
>
<path
d="M12.48 10.92v3.28h7.84c-.24 1.84-.853 3.187-1.787 4.133-1.147 1.147-2.933 2.4-6.053 2.4-4.827 0-8.6-3.893-8.6-8.72s3.773-8.72 8.6-8.72c2.6 0 4.507 1.027 5.907 2.347l2.307-2.307C18.747 1.44 16.133 0 12.48 0 5.867 0 .307 5.387.307 12s5.56 12 12.173 12c3.573 0 6.267-1.173 8.373-3.36 2.16-2.16 2.84-5.213 2.84-7.667 0-.76-.053-1.467-.173-2.053H12.48z"
fill="currentColor"
/>
</svg>
<span className="sr-only">
Sign up with Google
</span>
</Button>
<Button variant="outline" type="button">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
>
<path
d="M6.915 4.03c-1.968 0-3.683 1.28-4.871 3.113C.704 9.208 0 11.883 0 14.449c0 .706.07 1.369.21 1.973a6.624 6.624 0 0 0 .265.86 5.297 5.297 0 0 0 .371.761c.696 1.159 1.818 1.927 3.593 1.927 1.497 0 2.633-.671 3.965-2.444.76-1.012 1.144-1.626 2.663-4.32l.756-1.339.186-.325c.061.1.121.196.183.3l2.152 3.595c.724 1.21 1.665 2.556 2.47 3.314 1.046.987 1.992 1.22 3.06 1.22 1.075 0 1.876-.355 2.455-.843a3.743 3.743 0 0 0 .81-.973c.542-.939.861-2.127.861-3.745 0-2.72-.681-5.357-2.084-7.45-1.282-1.912-2.957-2.93-4.716-2.93-1.047 0-2.088.467-3.053 1.308-.652.57-1.257 1.29-1.82 2.05-.69-.875-1.335-1.547-1.958-2.056-1.182-.966-2.315-1.303-3.454-1.303zm10.16 2.053c1.147 0 2.188.758 2.992 1.999 1.132 1.748 1.647 4.195 1.647 6.4 0 1.548-.368 2.9-1.839 2.9-.58 0-1.027-.23-1.664-1.004-.496-.601-1.343-1.878-2.832-4.358l-.617-1.028a44.908 44.908 0 0 0-1.255-1.98c.07-.109.141-.224.211-.327 1.12-1.667 2.118-2.602 3.358-2.602zm-10.201.553c1.265 0 2.058.791 2.675 1.446.307.327.737.871 1.234 1.579l-1.02 1.566c-.757 1.163-1.882 3.017-2.837 4.338-1.191 1.649-1.81 1.817-2.486 1.817-.524 0-1.038-.237-1.383-.794-.263-.426-.464-1.13-.464-2.046 0-2.221.63-4.535 1.66-6.088.454-.687.964-1.226 1.533-1.533a2.264 2.264 0 0 1 1.088-.285z"
fill="currentColor"
/>
</svg>
<span className="sr-only">
Sign up with Meta
</span>
</Button>
</Field>
<FieldDescription className="text-center">
Already have an account?{" "}
<a href="#">Sign in</a>
</FieldDescription>
</FieldGroup>
</form>
</Form>
<div className="bg-muted relative hidden md:block">
<img
src="/placeholder.svg"
alt="Image"
className="absolute inset-0 h-full w-full object-cover dark:brightness-[0.2] dark:grayscale"
/>
</div>
</CardContent>
</Card>
<FieldDescription className="px-6 text-center">
By clicking continue, you agree to our{" "}
<a href="#">Terms of Service</a> and{" "}
<a href="#">Privacy Policy</a>.
</FieldDescription>
</div>
);
}
57 changes: 57 additions & 0 deletions src/components/ui/button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
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-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
{
variants: {
variant: {
default:
"bg-primary text-primary-foreground shadow hover:bg-primary/90",
destructive:
"bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
outline:
"border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
secondary:
"bg-secondary text-secondary-foreground shadow-sm 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",
sm: "h-8 rounded-md px-3 text-xs",
lg: "h-10 rounded-md px-8",
icon: "h-9 w-9",
},
},
defaultVariants: {
variant: "default",
size: "default",
},
},
);

export interface ButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
VariantProps<typeof buttonVariants> {
asChild?: boolean;
}

const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
({ className, variant, size, asChild = false, ...props }, ref) => {
const Comp = asChild ? Slot : "button";
return (
<Comp
className={cn(buttonVariants({ variant, size, className }))}
ref={ref}
{...props}
/>
);
},
);
Button.displayName = "Button";

export { Button, buttonVariants };
Loading