diff --git a/app/globals.css b/app/globals.css
index cdc9ba3..54a53d1 100644
--- a/app/globals.css
+++ b/app/globals.css
@@ -25,51 +25,52 @@
@layer base {
:root {
--background: 0 0% 100%;
- --foreground: 240 10% 3.9%;
+ --foreground: 20 14.3% 4.1%;
--card: 0 0% 100%;
- --card-foreground: 240 10% 3.9%;
+ --card-foreground: 20 14.3% 4.1%;
--popover: 0 0% 100%;
- --popover-foreground: 240 10% 3.9%;
- --primary: 240 5.9% 10%;
- --primary-foreground: 0 0% 98%;
- --secondary: 240 4.8% 95.9%;
- --secondary-foreground: 240 5.9% 10%;
- --muted: 240 4.8% 95.9%;
- --muted-foreground: 240 3.8% 46.1%;
- --accent: 240 4.8% 95.9%;
- --accent-foreground: 240 5.9% 10%;
+ --popover-foreground: 20 14.3% 4.1%;
+ --primary: 24.6 95% 53.1%;
+ --primary-foreground: 60 9.1% 97.8%;
+ --secondary: 60 4.8% 95.9%;
+ --secondary-foreground: 24 9.8% 10%;
+ --muted: 60 4.8% 95.9%;
+ --muted-foreground: 25 5.3% 44.7%;
+ --accent: 60 4.8% 95.9%;
+ --accent-foreground: 24 9.8% 10%;
--destructive: 0 84.2% 60.2%;
- --destructive-foreground: 0 0% 98%;
- --border: 240 5.9% 90%;
- --input: 240 5.9% 90%;
- --ring: 240 10% 3.9%;
+ --destructive-foreground: 60 9.1% 97.8%;
+ --border: 20 5.9% 90%;
+ --input: 20 5.9% 90%;
+ --ring: 24.6 95% 53.1%;
+ --radius: 1rem;
--chart-1: 12 76% 61%;
--chart-2: 173 58% 39%;
--chart-3: 197 37% 24%;
--chart-4: 43 74% 66%;
--chart-5: 27 87% 67%;
- --radius: 0.5rem;
}
+
.dark {
- --background: 240 10% 3.9%;
- --foreground: 0 0% 98%;
- --card: 240 10% 3.9%;
- --card-foreground: 0 0% 98%;
- --popover: 240 10% 3.9%;
- --popover-foreground: 0 0% 98%;
- --primary: 0 0% 98%;
- --primary-foreground: 240 5.9% 10%;
- --secondary: 240 3.7% 15.9%;
- --secondary-foreground: 0 0% 98%;
- --muted: 240 3.7% 15.9%;
- --muted-foreground: 240 5% 64.9%;
- --accent: 240 3.7% 15.9%;
- --accent-foreground: 0 0% 98%;
- --destructive: 0 62.8% 30.6%;
- --destructive-foreground: 0 0% 98%;
- --border: 240 3.7% 15.9%;
- --input: 240 3.7% 15.9%;
- --ring: 240 4.9% 83.9%;
+ --background: 20 14.3% 4.1%;
+ --foreground: 60 9.1% 97.8%;
+ --card: 20 14.3% 4.1%;
+ --card-foreground: 60 9.1% 97.8%;
+ --popover: 20 14.3% 4.1%;
+ --popover-foreground: 60 9.1% 97.8%;
+ --primary: 20.5 90.2% 48.2%;
+ --primary-foreground: 60 9.1% 97.8%;
+ --secondary: 12 6.5% 15.1%;
+ --secondary-foreground: 60 9.1% 97.8%;
+ --muted: 12 6.5% 15.1%;
+ --muted-foreground: 24 5.4% 63.9%;
+ --accent: 12 6.5% 15.1%;
+ --accent-foreground: 60 9.1% 97.8%;
+ --destructive: 0 72.2% 50.6%;
+ --destructive-foreground: 60 9.1% 97.8%;
+ --border: 12 6.5% 15.1%;
+ --input: 12 6.5% 15.1%;
+ --ring: 20.5 90.2% 48.2%;
--chart-1: 220 70% 50%;
--chart-2: 160 60% 45%;
--chart-3: 30 80% 55%;
diff --git a/app/layout.tsx b/app/layout.tsx
index c32c8d6..da66ad2 100644
--- a/app/layout.tsx
+++ b/app/layout.tsx
@@ -20,7 +20,7 @@ export default function RootLayout({
children: React.ReactNode;
}>) {
return (
-
+
-
-
- );
+ return "helloworld";
}
diff --git a/app/sign-up/page.tsx b/app/sign-up/page.tsx
new file mode 100644
index 0000000..d4cb99c
--- /dev/null
+++ b/app/sign-up/page.tsx
@@ -0,0 +1,17 @@
+import Image from "next/image";
+import SignUp from "./sign-up-form";
+
+export default function Page() {
+ return (
+
+
+
+
+ );
+}
diff --git a/app/sign-up/sign-up-form.tsx b/app/sign-up/sign-up-form.tsx
new file mode 100644
index 0000000..9932f37
--- /dev/null
+++ b/app/sign-up/sign-up-form.tsx
@@ -0,0 +1,124 @@
+"use client";
+
+import { zodResolver } from "@hookform/resolvers/zod";
+import { useForm } from "react-hook-form";
+import { z } from "zod";
+
+import { Button } from "@/components/ui/button";
+import {
+ Form,
+ FormControl,
+ FormDescription,
+ FormField,
+ FormItem,
+ FormLabel,
+ FormMessage,
+} from "@/components/ui/form";
+import { format } from "date-fns";
+import { CalendarIcon } from "lucide-react";
+import { Input } from "@/components/ui/input";
+import { Calendar } from "@/components/ui/calendar";
+import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
+import { cn } from "@/lib/utils";
+import { signupFormSubmit } from "@/lib/actions";
+
+export const signupFormSchema = z.object({
+ name: z.string().min(2, { message: "Name is required" }).max(50, { message: "Name is too long" }),
+ email: z.string().email({ message: "Email is invalid" }),
+ dob: z.date({ required_error: "Birthday is required" }),
+});
+
+export const youngestDate = new Date(new Date().setFullYear(new Date().getFullYear() - 21));
+export const oldestDate = new Date(new Date().setFullYear(new Date().getFullYear() - 100));
+
+export default function SignUp() {
+ const form = useForm>({
+ resolver: zodResolver(signupFormSchema),
+ defaultValues: {
+ name: "",
+ email: "",
+ dob: youngestDate,
+ },
+ });
+ function onSubmit(values: z.infer) {
+ signupFormSubmit(values);
+ }
+ return (
+
+
+ );
+}
diff --git a/components/ui/calendar.tsx b/components/ui/calendar.tsx
new file mode 100644
index 0000000..b473cc2
--- /dev/null
+++ b/components/ui/calendar.tsx
@@ -0,0 +1,95 @@
+"use client";
+
+import * as React from "react";
+import { ChevronLeft, ChevronRight } from "lucide-react";
+import { DayPicker } from "react-day-picker";
+
+import { cn } from "@/lib/utils";
+import { buttonVariants } from "@/components/ui/button";
+import {
+ Select,
+ SelectContent,
+ SelectItem,
+ SelectTrigger,
+ SelectValue,
+} from "@/components/ui/select";
+
+export type CalendarProps = React.ComponentProps;
+
+function Calendar({ className, classNames, showOutsideDays = true, ...props }: CalendarProps) {
+ return (
+ ,
+ IconRight: ({ ...props }) => ,
+ Dropdown: ({ children, value, onChange, ...props }) => {
+ const options = React.Children.toArray(children) as React.ReactElement<
+ React.HTMLProps
+ >[];
+ const selected = options.find((child) => child.props.value === value);
+ const handleChange = (value: string) => {
+ const changeEvent = {
+ target: { value },
+ } as React.ChangeEvent;
+ onChange?.(changeEvent);
+ };
+ return (
+
+ );
+ },
+ }}
+ {...props}
+ />
+ );
+}
+Calendar.displayName = "Calendar";
+
+export { Calendar };
diff --git a/components/ui/input.tsx b/components/ui/input.tsx
new file mode 100644
index 0000000..a921025
--- /dev/null
+++ b/components/ui/input.tsx
@@ -0,0 +1,25 @@
+import * as React from "react"
+
+import { cn } from "@/lib/utils"
+
+export interface InputProps
+ extends React.InputHTMLAttributes {}
+
+const Input = React.forwardRef(
+ ({ className, type, ...props }, ref) => {
+ return (
+
+ )
+ }
+)
+Input.displayName = "Input"
+
+export { Input }
diff --git a/components/ui/popover.tsx b/components/ui/popover.tsx
new file mode 100644
index 0000000..a0ec48b
--- /dev/null
+++ b/components/ui/popover.tsx
@@ -0,0 +1,31 @@
+"use client"
+
+import * as React from "react"
+import * as PopoverPrimitive from "@radix-ui/react-popover"
+
+import { cn } from "@/lib/utils"
+
+const Popover = PopoverPrimitive.Root
+
+const PopoverTrigger = PopoverPrimitive.Trigger
+
+const PopoverContent = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, align = "center", sideOffset = 4, ...props }, ref) => (
+
+
+
+))
+PopoverContent.displayName = PopoverPrimitive.Content.displayName
+
+export { Popover, PopoverTrigger, PopoverContent }
diff --git a/components/ui/select.tsx b/components/ui/select.tsx
new file mode 100644
index 0000000..cbe5a36
--- /dev/null
+++ b/components/ui/select.tsx
@@ -0,0 +1,160 @@
+"use client"
+
+import * as React from "react"
+import * as SelectPrimitive from "@radix-ui/react-select"
+import { Check, ChevronDown, ChevronUp } from "lucide-react"
+
+import { cn } from "@/lib/utils"
+
+const Select = SelectPrimitive.Root
+
+const SelectGroup = SelectPrimitive.Group
+
+const SelectValue = SelectPrimitive.Value
+
+const SelectTrigger = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, children, ...props }, ref) => (
+ span]:line-clamp-1",
+ className
+ )}
+ {...props}
+ >
+ {children}
+
+
+
+
+))
+SelectTrigger.displayName = SelectPrimitive.Trigger.displayName
+
+const SelectScrollUpButton = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+
+
+))
+SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName
+
+const SelectScrollDownButton = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+
+
+))
+SelectScrollDownButton.displayName =
+ SelectPrimitive.ScrollDownButton.displayName
+
+const SelectContent = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, children, position = "popper", ...props }, ref) => (
+
+
+
+
+ {children}
+
+
+
+
+))
+SelectContent.displayName = SelectPrimitive.Content.displayName
+
+const SelectLabel = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+))
+SelectLabel.displayName = SelectPrimitive.Label.displayName
+
+const SelectItem = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, children, ...props }, ref) => (
+
+
+
+
+
+
+
+ {children}
+
+))
+SelectItem.displayName = SelectPrimitive.Item.displayName
+
+const SelectSeparator = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+))
+SelectSeparator.displayName = SelectPrimitive.Separator.displayName
+
+export {
+ Select,
+ SelectGroup,
+ SelectValue,
+ SelectTrigger,
+ SelectContent,
+ SelectLabel,
+ SelectItem,
+ SelectSeparator,
+ SelectScrollUpButton,
+ SelectScrollDownButton,
+}
diff --git a/lib/actions.ts b/lib/actions.ts
new file mode 100644
index 0000000..41c989f
--- /dev/null
+++ b/lib/actions.ts
@@ -0,0 +1,19 @@
+"use server";
+
+import { z } from "zod";
+import { oldestDate, signupFormSchema, youngestDate } from "@/app/sign-up/sign-up-form";
+import listmonk from "./listmonk";
+
+export async function signupFormSubmit(data: z.infer) {
+ if (data.dob > youngestDate || data.dob < oldestDate) {
+ return { error: "Invalid date of birth" };
+ }
+ const listmonkData = {
+ email: data.email,
+ name: data.name,
+ attribs: {
+ dob: data.dob.toISOString(),
+ },
+ };
+ console.log(listmonkData);
+}
diff --git a/lib/listmonk.ts b/lib/listmonk.ts
new file mode 100644
index 0000000..434d52b
--- /dev/null
+++ b/lib/listmonk.ts
@@ -0,0 +1,21 @@
+import "server-only";
+
+async function makeApiCall(url: string, options?: RequestInit) {
+ try {
+ const response = await fetch(url, options);
+ if (!response.ok) {
+ throw new Error(`HTTP error! Status: ${response.status}`);
+ }
+ return await response.json();
+ } catch (error) {
+ console.error("Error making API call:", error);
+ throw error;
+ }
+}
+
+async function listmonk() {
+ const listmonkUrl = process.env.LISTMONK_URL ?? "";
+ makeApiCall(listmonkUrl);
+}
+
+export default listmonk;