diff --git a/.gitignore b/.gitignore index fd3dbb5..677e7b0 100644 --- a/.gitignore +++ b/.gitignore @@ -34,3 +34,5 @@ yarn-error.log* # typescript *.tsbuildinfo next-env.d.ts + +data diff --git a/app/action.ts b/app/action.ts new file mode 100644 index 0000000..adca127 --- /dev/null +++ b/app/action.ts @@ -0,0 +1,59 @@ +"use server"; + +import { z } from "zod"; +import { nanoid } from "nanoid"; +import { GenerateJson } from "@/lib/server/utils"; + +type FormState = { + id?: string; + errors?: string; +}; + +export async function submit(prevState: FormState, next: FormData) { + const formSchema = z.object({ + name: z.string().min(1, { + message: "Name is required", + }), + email: z.string().email().min(1, { + message: "Email is required", + }), + zipcode: z.string().length(5, { + message: "Zip code must be 5 characters", + }), + type: z + .string({ + required_error: "Medical Staffing Type is required", + }) + .min(1, { + message: "Medical Staffing Type is required", + }), + }); + + try { + const { name, email, zipcode, type } = Object.fromEntries(next); + + const formData = formSchema.parse({ name, email, zipcode, type }); + + const id = nanoid(8); + await GenerateJson(id, formData); + + // Send data to webhook + // comment out since webhook is not permanent + // await fetch("", { + // method: "POST", + // headers: { + // "Content-Type": "application/json", + // }, + // body: JSON.stringify(formData), + // }); + + return { + id, + }; + } catch (e: any) { + console.error(e); + return { + errors: e.errors[0].message, + }; + } +} diff --git a/app/form.tsx b/app/form.tsx new file mode 100644 index 0000000..cf1bb25 --- /dev/null +++ b/app/form.tsx @@ -0,0 +1,67 @@ +"use client"; + +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { useFormState, useFormStatus } from "react-dom"; +import { FaSpinner } from "react-icons/fa6"; +import { submit } from "./action"; +import { useEffect, useState } from "react"; +import Select from 'react-select' + + +function SubmitButton() { + const status = useFormStatus(); + return ( + + ) +} + +const options = [ + { value: 'Assisted Living', label: 'Assisted Living' }, + { value: 'Home Care', label: 'Home Care' }, + { value: 'Home Health', label: 'Home Health' }, + { value: 'Independent Living/Retirement Community', label: 'Independent Living/Retirement Community' }, + +] + +export default function InquiryForm() { + const [state, dispatch] = useFormState(submit, {} as any); + const status = useFormStatus(); + const [selected, setSelected] = useState([]); + + useEffect(() => { + if (!status.pending) { + if (state.id) { + window.location.href = `/result/${state.id}`; + } + } + }, [status, state]) + + return ( +
+
+
+ + + +
+ + {state?.errors && ( +

{state.errors}

+ )} +
+ +
+ +
+ ) +} diff --git a/app/globals.css b/app/globals.css index 875c01e..b8dd906 100644 --- a/app/globals.css +++ b/app/globals.css @@ -2,32 +2,50 @@ @tailwind components; @tailwind utilities; -:root { - --foreground-rgb: 0, 0, 0; - --background-start-rgb: 214, 219, 220; - --background-end-rgb: 255, 255, 255; -} - -@media (prefers-color-scheme: dark) { +@layer base { :root { - --foreground-rgb: 255, 255, 255; - --background-start-rgb: 0, 0, 0; - --background-end-rgb: 0, 0, 0; + --background: 0 0% 100%; + --foreground: 240 10% 3.9%; + --card: 0 0% 100%; + --card-foreground: 240 10% 3.9%; + --popover: 0 0% 100%; + --popover-foreground: 240 10% 3.9%; + --primary: 181.9 96.9% 25.5%; + --primary-foreground: 355.7 100% 97.3%; + --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%; + --destructive: 0 84.2% 60.2%; + --destructive-foreground: 0 0% 98%; + --border: 240 5.9% 90%; + --input: 240 5.9% 90%; + --ring: 142.1 76.2% 36.3%; + --radius: 0.5rem; } -} -body { - color: rgb(var(--foreground-rgb)); - background: linear-gradient( - to bottom, - transparent, - rgb(var(--background-end-rgb)) - ) - rgb(var(--background-start-rgb)); -} - -@layer utilities { - .text-balance { - text-wrap: balance; + .dark { + --background: 20 14.3% 4.1%; + --foreground: 0 0% 95%; + --card: 24 9.8% 10%; + --card-foreground: 0 0% 95%; + --popover: 0 0% 9%; + --popover-foreground: 0 0% 95%; + --primary: 142.1 70.6% 45.3%; + --primary-foreground: 144.9 80.4% 10%; + --secondary: 240 3.7% 15.9%; + --secondary-foreground: 0 0% 98%; + --muted: 0 0% 15%; + --muted-foreground: 240 5% 64.9%; + --accent: 12 6.5% 15.1%; + --accent-foreground: 0 0% 98%; + --destructive: 0 62.8% 30.6%; + --destructive-foreground: 0 85.7% 97.3%; + --border: 240 3.7% 15.9%; + --input: 240 3.7% 15.9%; + --ring: 142.4 71.8% 29.2%; } } + diff --git a/app/layout.tsx b/app/layout.tsx index 3314e47..534fb12 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -5,8 +5,8 @@ import "./globals.css"; const inter = Inter({ subsets: ["latin"] }); export const metadata: Metadata = { - title: "Create Next App", - description: "Generated by create next app", + title: "Inquiry Page | Care Indeed", + description: "Get the care you or your loved one needs, tailored to your specific requirements.", }; export default function RootLayout({ diff --git a/app/page.tsx b/app/page.tsx index 5705d4e..b9ceb6a 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -1,113 +1,39 @@ -import Image from "next/image"; +import Image from "next/image" +import HeroImage from '@/public/hero.jpg'; +import InquiryForm from "./form"; -export default function Home() { +export default function Page() { return ( -
-
- ); + +
+ ) } diff --git a/app/result/[id]/page.tsx b/app/result/[id]/page.tsx new file mode 100644 index 0000000..c403e9a --- /dev/null +++ b/app/result/[id]/page.tsx @@ -0,0 +1,86 @@ +import { findNearestLocation, getDistance, locations } from "@/lib/locations"; +import { Button } from "@/components/ui/button"; +import Link from "next/link"; +import { ReadJson } from "@/lib/server/utils"; + +export const metadata = { + title: "Good News! Get Started! | Care Indeed", + description: "Get the care you or your loved one needs, tailored to your specific requirements.", +} + +export default async function Page({ + params, +}: { + params: { + id: string + }, +}) { + const readJson = await ReadJson(params.id); + const jsonData = JSON.parse(readJson); + + const name = jsonData?.name || "John Doe"; + const location = findNearestLocation(jsonData?.zipcode) + const distance = getDistance(location?.zipcode, jsonData?.zipcode) + const types = jsonData?.type.split(",").map((type: string) => type.trim()) + + return ( +
+
+
+
+
+ + Back to Home + +
+

+ Hey,  + + {name}! + +

+

+ We have { + types.map((type: string, index: number) => ( + <> + + {type} + + {index < types.length - 1 ? ", " : ""} + {index === types.length - 2 ? " and " : ""} + + )) + } available for you in our 
+

+
+ + {location?.name} Branch  + +

+ It's only {distance} miles away! +

+
+ + {location?.address} + + +
+
+
+