From 4b554cdb37c73c9e0d016a331c9610afabd8e8a8 Mon Sep 17 00:00:00 2001 From: ChrQR Date: Mon, 3 Jun 2024 13:38:20 +0200 Subject: [PATCH 1/4] refactored orm operations in components to server actions --- src/app/_components/AllCountries.tsx | 4 ++-- src/app/_components/AllRegions.tsx | 7 ++++--- src/server/actions/getAllCountries.ts | 6 ++++++ src/server/actions/getAllRegions.ts | 6 ++++++ 4 files changed, 18 insertions(+), 5 deletions(-) create mode 100644 src/server/actions/getAllCountries.ts create mode 100644 src/server/actions/getAllRegions.ts diff --git a/src/app/_components/AllCountries.tsx b/src/app/_components/AllCountries.tsx index 5fdbd62..e7744a0 100644 --- a/src/app/_components/AllCountries.tsx +++ b/src/app/_components/AllCountries.tsx @@ -1,9 +1,9 @@ import { Delete } from "lucide-react"; import { deleteCountry } from "~/server/actions/deleteCountry"; -import { db } from "~/server/db"; +import getAllCountries from "~/server/actions/getAllCountries"; export default async function AllCountries() { - const countries = await db.query.countries.findMany(); + const countries = await getAllCountries(); return (

All Countries:

diff --git a/src/app/_components/AllRegions.tsx b/src/app/_components/AllRegions.tsx index 4eb73b8..30015c2 100644 --- a/src/app/_components/AllRegions.tsx +++ b/src/app/_components/AllRegions.tsx @@ -1,8 +1,9 @@ -import { db } from "~/server/db"; +import getAllCountries from "~/server/actions/getAllCountries"; +import getAllRegions from "~/server/actions/getAllRegions"; export default async function AllRegions() { - const allRegions = await db.query.regions.findMany(); - const allCountries = await db.query.countries.findMany(); + const allRegions = await getAllRegions(); + const allCountries = await getAllCountries(); return (

All Regions:

diff --git a/src/server/actions/getAllCountries.ts b/src/server/actions/getAllCountries.ts new file mode 100644 index 0000000..43e7763 --- /dev/null +++ b/src/server/actions/getAllCountries.ts @@ -0,0 +1,6 @@ +import { db } from "../db"; + +export default async function getAllCountries() { + const allCountries = await db.query.countries.findMany(); + return allCountries; +} diff --git a/src/server/actions/getAllRegions.ts b/src/server/actions/getAllRegions.ts new file mode 100644 index 0000000..a478386 --- /dev/null +++ b/src/server/actions/getAllRegions.ts @@ -0,0 +1,6 @@ +import { db } from "../db"; + +export default async function getAllRegions() { + const allRegions = await db.query.regions.findMany(); + return allRegions; +} -- 2.43.4 From 7304ce10234777864d5b5eda0422cbf18b4acc50 Mon Sep 17 00:00:00 2001 From: ChrQR Date: Mon, 3 Jun 2024 15:28:22 +0200 Subject: [PATCH 2/4] CreateSubRegionForm logic unfinished --- src/app/App.tsx | 3 + src/app/_components/admin/CreateCountry.tsx | 4 +- src/app/_components/admin/CreateRegion.tsx | 7 +- src/app/_components/admin/CreateSubRegion.tsx | 18 +++++ .../_components/admin/CreateSubRegionForm.tsx | 81 +++++++++++++++++++ src/server/actions/addCountry.ts | 2 +- src/server/actions/addRegion.ts | 2 +- src/server/actions/addSubRegion.ts | 62 ++++++++++++++ 8 files changed, 172 insertions(+), 7 deletions(-) create mode 100644 src/app/_components/admin/CreateSubRegion.tsx create mode 100644 src/app/_components/admin/CreateSubRegionForm.tsx create mode 100644 src/server/actions/addSubRegion.ts diff --git a/src/app/App.tsx b/src/app/App.tsx index bf28490..628f8e2 100644 --- a/src/app/App.tsx +++ b/src/app/App.tsx @@ -4,6 +4,8 @@ import CreateCountry from "./_components/admin/CreateCountry"; import AllCountries from "./_components/AllCountries"; import CreateRegion from "./_components/admin/CreateRegion"; import AllRegions from "./_components/AllRegions"; +import CreateSubRegionForm from "./_components/admin/CreateSubRegionForm"; +import CreateSubRegion from "./_components/admin/CreateSubRegion"; export default function App() { return ( @@ -14,6 +16,7 @@ export default function App() { +
); } diff --git a/src/app/_components/admin/CreateCountry.tsx b/src/app/_components/admin/CreateCountry.tsx index 0c10572..6223e42 100644 --- a/src/app/_components/admin/CreateCountry.tsx +++ b/src/app/_components/admin/CreateCountry.tsx @@ -2,9 +2,9 @@ import CreateCountryForm from "./CreateCountryForm"; export default function CreateCountry() { return ( - <> +

Fill the form to create a new country

- +
); } diff --git a/src/app/_components/admin/CreateRegion.tsx b/src/app/_components/admin/CreateRegion.tsx index 56b6f3f..f5d1d26 100644 --- a/src/app/_components/admin/CreateRegion.tsx +++ b/src/app/_components/admin/CreateRegion.tsx @@ -1,13 +1,14 @@ "use server"; import { db } from "~/server/db"; import CreateRegionForm from "./CreateRegionForm"; +import getAllCountries from "~/server/actions/getAllCountries"; export default async function CreateRegion() { - const allCountries = await db.query.countries.findMany(); + const allCountries = await getAllCountries(); return ( - <> +

Fill the form to create a new region

- +
); } diff --git a/src/app/_components/admin/CreateSubRegion.tsx b/src/app/_components/admin/CreateSubRegion.tsx new file mode 100644 index 0000000..cf608a2 --- /dev/null +++ b/src/app/_components/admin/CreateSubRegion.tsx @@ -0,0 +1,18 @@ +"use server"; +import getAllRegions from "~/server/actions/getAllRegions"; +import CreateSubRegionForm from "./CreateSubRegionForm"; +import getAllCountries from "~/server/actions/getAllCountries"; + +const allRegions = await getAllRegions(); +const allCountries = await getAllCountries(); + +export default async function CreateSubRegion() { + return ( +
+

+ Fill the form to create a new Sub Region +

+ +
+ ); +} diff --git a/src/app/_components/admin/CreateSubRegionForm.tsx b/src/app/_components/admin/CreateSubRegionForm.tsx new file mode 100644 index 0000000..97e4546 --- /dev/null +++ b/src/app/_components/admin/CreateSubRegionForm.tsx @@ -0,0 +1,81 @@ +"use client"; +import clsx from "clsx"; +import { useState } from "react"; +import { useFormState } from "react-dom"; +import { Input } from "~/components/ui/input"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "~/components/ui/select"; +import { addRegion } from "~/server/actions/addRegion"; + +type Region = { + id: string; + name: string; + countryId: string; +}; +type Country = { + id: string; + name: string; +}; + +export default function CreateSubRegionForm(props: { + regions: Region[]; + countries: Country[]; +}) { + const { countries, regions } = props; + const [country, setCountry] = useState(undefined); + const [formState, formActions] = useFormState(addRegion, { + message: "", + errors: undefined, + fieldValues: { + name: "", + regionId: "", + }, + }); + return ( +
+ {/* country selector */} + +
+ {/* region selector */} + + +
+
+ ); +} diff --git a/src/server/actions/addCountry.ts b/src/server/actions/addCountry.ts index bbd7728..aa45cfc 100644 --- a/src/server/actions/addCountry.ts +++ b/src/server/actions/addCountry.ts @@ -20,7 +20,7 @@ export async function addCountry(prevstate: any, formData: FormData) { name: z .string() .min(1, { message: "Name is required" }) - .refine(() => !exists[0], { message: `${name} already exists` }), + .refine(() => !exists, { message: `${name} already exists` }), }); //Parse the form data using the schema for validation, and check if the name already exists try { diff --git a/src/server/actions/addRegion.ts b/src/server/actions/addRegion.ts index 5b885fe..9262940 100644 --- a/src/server/actions/addRegion.ts +++ b/src/server/actions/addRegion.ts @@ -23,7 +23,7 @@ export const addRegion = async (prevstate: any, formData: FormData) => { name: z .string() .min(1, "Name is required") - .refine(() => !exists[0], { + .refine(() => !exists, { message: `${name} already exists in selected country`, }), }); diff --git a/src/server/actions/addSubRegion.ts b/src/server/actions/addSubRegion.ts new file mode 100644 index 0000000..6f5e784 --- /dev/null +++ b/src/server/actions/addSubRegion.ts @@ -0,0 +1,62 @@ +"use server"; + +import { eq } from "drizzle-orm"; +import { db } from "../db"; +import { subRegions } from "../db/schema"; +import { ZodError, z } from "zod"; + +export const addSubRegion = async (prevstate: any, formData: FormData) => { + //assign formdaata to variables. + const name = (formData.get("name") as string).toLowerCase(); + const regionId = formData.get("region") as string; + + //check if region already exists in country + const exists = await db + .select({ name: subRegions.name }) + .from(subRegions) + .where(eq(subRegions.regionId, regionId) && eq(subRegions.name, name)); + + //Define the schema for the form data + const schema = z.object({ + regionId: z.string().min(1, "No region selected"), + name: z + .string() + .min(1, "Name is required") + .refine(() => !exists, { + message: `${name} already exists in selected region`, + }), + }); + //Parse the form data using the schema for validation, and check if the name already exists + try { + schema.parse({ + regionId, + name, + }); + //If the name doesn't exist, add the country to the database abd revalidate the page + await db.insert(subRegions).values({ regionId, name }); + //Return a success message + return { + message: "success", + errors: undefined, + fieldValues: { + name: "", + regionId: "", + }, + }; + } catch (error) { + const zodError = error as ZodError; + const errorMap = zodError.flatten().fieldErrors; + //Return an error object with the field values and errors. + return { + message: "error", + errors: { + name: errorMap["name"]?.[0] ?? "", + regionId: errorMap["regionId"]?.[0] ?? "", + }, + fieldValues: { + name, + regionId, + }, + }; + } +}; -- 2.43.4 From a609300688725874840907fa5884e44b0bc77608 Mon Sep 17 00:00:00 2001 From: christian Date: Tue, 4 Jun 2024 14:37:47 +0200 Subject: [PATCH 3/4] country selector working now. --- src/app/_components/admin/CreateSubRegion.tsx | 5 +- .../_components/admin/CreateSubRegionForm.tsx | 48 +++++++++++++------ src/server/actions/addCountry.ts | 2 +- src/server/actions/addRegion.ts | 2 +- src/server/actions/addSubRegion.ts | 4 +- 5 files changed, 41 insertions(+), 20 deletions(-) diff --git a/src/app/_components/admin/CreateSubRegion.tsx b/src/app/_components/admin/CreateSubRegion.tsx index cf608a2..75f27bb 100644 --- a/src/app/_components/admin/CreateSubRegion.tsx +++ b/src/app/_components/admin/CreateSubRegion.tsx @@ -12,7 +12,10 @@ export default async function CreateSubRegion() {

Fill the form to create a new Sub Region

- +
); } diff --git a/src/app/_components/admin/CreateSubRegionForm.tsx b/src/app/_components/admin/CreateSubRegionForm.tsx index 97e4546..beb4f16 100644 --- a/src/app/_components/admin/CreateSubRegionForm.tsx +++ b/src/app/_components/admin/CreateSubRegionForm.tsx @@ -1,6 +1,6 @@ "use client"; import clsx from "clsx"; -import { useState } from "react"; +import { ChangeEvent, useEffect, useState } from "react"; import { useFormState } from "react-dom"; import { Input } from "~/components/ui/input"; import { @@ -10,7 +10,8 @@ import { SelectTrigger, SelectValue, } from "~/components/ui/select"; -import { addRegion } from "~/server/actions/addRegion"; +import { addSubRegion } from "~/server/actions/addSubRegion"; +import SubmitButton from "../SubmitButton"; type Region = { id: string; @@ -23,12 +24,17 @@ type Country = { }; export default function CreateSubRegionForm(props: { - regions: Region[]; - countries: Country[]; + allRegions: Region[]; + allCountries: Country[]; }) { - const { countries, regions } = props; - const [country, setCountry] = useState(undefined); - const [formState, formActions] = useFormState(addRegion, { + const { allRegions, allCountries } = props; + const [selectCountryId, setSelectCountryId] = useState( + undefined, + ); + const [selectCountryRegions, setSelectCountryRegions] = useState( + [], + ); + const [formState, formActions] = useFormState(addSubRegion, { message: "", errors: undefined, fieldValues: { @@ -36,17 +42,28 @@ export default function CreateSubRegionForm(props: { regionId: "", }, }); + + useEffect(() => { + if (selectCountryId) { + const regions = allRegions.filter( + (region) => region.countryId === selectCountryId, + ); + setSelectCountryRegions(regions); + } + }, [selectCountryId]); return (
{/* country selector */} - setSelectCountryId(value)} + > + - {countries.map((country) => ( + {allCountries.map((country) => ( {country.name} @@ -55,14 +72,14 @@ export default function CreateSubRegionForm(props: {
{/* region selector */} - - {regions.map((region) => ( + {selectCountryRegions.map((region) => ( {region.name} @@ -75,6 +92,7 @@ export default function CreateSubRegionForm(props: { placeholder="Name" className={`${clsx({ "border-red-500": formState.errors?.name })}`} /> +
); diff --git a/src/server/actions/addCountry.ts b/src/server/actions/addCountry.ts index aa45cfc..bbd7728 100644 --- a/src/server/actions/addCountry.ts +++ b/src/server/actions/addCountry.ts @@ -20,7 +20,7 @@ export async function addCountry(prevstate: any, formData: FormData) { name: z .string() .min(1, { message: "Name is required" }) - .refine(() => !exists, { message: `${name} already exists` }), + .refine(() => !exists[0], { message: `${name} already exists` }), }); //Parse the form data using the schema for validation, and check if the name already exists try { diff --git a/src/server/actions/addRegion.ts b/src/server/actions/addRegion.ts index 9262940..5b885fe 100644 --- a/src/server/actions/addRegion.ts +++ b/src/server/actions/addRegion.ts @@ -23,7 +23,7 @@ export const addRegion = async (prevstate: any, formData: FormData) => { name: z .string() .min(1, "Name is required") - .refine(() => !exists, { + .refine(() => !exists[0], { message: `${name} already exists in selected country`, }), }); diff --git a/src/server/actions/addSubRegion.ts b/src/server/actions/addSubRegion.ts index 6f5e784..0cb050a 100644 --- a/src/server/actions/addSubRegion.ts +++ b/src/server/actions/addSubRegion.ts @@ -8,7 +8,7 @@ import { ZodError, z } from "zod"; export const addSubRegion = async (prevstate: any, formData: FormData) => { //assign formdaata to variables. const name = (formData.get("name") as string).toLowerCase(); - const regionId = formData.get("region") as string; + const regionId = formData.get("regionId") as string; //check if region already exists in country const exists = await db @@ -22,7 +22,7 @@ export const addSubRegion = async (prevstate: any, formData: FormData) => { name: z .string() .min(1, "Name is required") - .refine(() => !exists, { + .refine(() => !exists[0], { message: `${name} already exists in selected region`, }), }); -- 2.43.4 From 14fa130ce62dea160254f4fb474a170fc05f5f85 Mon Sep 17 00:00:00 2001 From: christian Date: Tue, 4 Jun 2024 16:02:29 +0200 Subject: [PATCH 4/4] added forms for adding producer. added delete button to all categories. --- src/app/App.tsx | 7 +- src/app/_components/AllRegions.tsx | 30 ++--- src/app/_components/AllSubRegions.tsx | 22 ++++ src/app/_components/admin/CreateProducer.tsx | 13 +++ .../_components/admin/CreateProducerForm.tsx | 108 ++++++++++++++++++ src/app/_components/admin/CreateRegion.tsx | 1 - .../_components/admin/CreateSubRegionForm.tsx | 87 ++++++++++---- src/app/_components/allProducers.tsx | 22 ++++ src/components/ui/textarea.tsx | 24 ++++ src/server/actions/addProducer.ts | 77 +++++++++++++ src/server/actions/addSubRegion.ts | 2 + src/server/actions/deleteProducer.ts | 10 ++ src/server/actions/deleteRegion.ts | 10 ++ src/server/actions/deleteSubRegion.ts | 10 ++ src/server/actions/getAllProducers.ts | 7 ++ src/server/actions/getAllSubRegions.ts | 7 ++ 16 files changed, 392 insertions(+), 45 deletions(-) create mode 100644 src/app/_components/AllSubRegions.tsx create mode 100644 src/app/_components/admin/CreateProducer.tsx create mode 100644 src/app/_components/admin/CreateProducerForm.tsx create mode 100644 src/app/_components/allProducers.tsx create mode 100644 src/components/ui/textarea.tsx create mode 100644 src/server/actions/addProducer.ts create mode 100644 src/server/actions/deleteProducer.ts create mode 100644 src/server/actions/deleteRegion.ts create mode 100644 src/server/actions/deleteSubRegion.ts create mode 100644 src/server/actions/getAllProducers.ts create mode 100644 src/server/actions/getAllSubRegions.ts diff --git a/src/app/App.tsx b/src/app/App.tsx index 628f8e2..251a9b5 100644 --- a/src/app/App.tsx +++ b/src/app/App.tsx @@ -4,8 +4,10 @@ import CreateCountry from "./_components/admin/CreateCountry"; import AllCountries from "./_components/AllCountries"; import CreateRegion from "./_components/admin/CreateRegion"; import AllRegions from "./_components/AllRegions"; -import CreateSubRegionForm from "./_components/admin/CreateSubRegionForm"; import CreateSubRegion from "./_components/admin/CreateSubRegion"; +import AllSubRegions from "./_components/AllSubRegions"; +import CreateProducer from "./_components/admin/CreateProducer"; +import AllProducers from "./_components/allProducers"; export default function App() { return ( @@ -17,6 +19,9 @@ export default function App() { + + + ); } diff --git a/src/app/_components/AllRegions.tsx b/src/app/_components/AllRegions.tsx index 30015c2..c3f2162 100644 --- a/src/app/_components/AllRegions.tsx +++ b/src/app/_components/AllRegions.tsx @@ -1,3 +1,5 @@ +import { Delete } from "lucide-react"; +import deleteRegion from "~/server/actions/deleteRegion"; import getAllCountries from "~/server/actions/getAllCountries"; import getAllRegions from "~/server/actions/getAllRegions"; @@ -7,24 +9,16 @@ export default async function AllRegions() { return (

All Regions:

- {allRegions[0] ? ( - <> -
    - {allRegions.map((region) => ( -
  • - {region.name} -{" "} - { - allCountries.find( - (country) => country.id === region.countryId, - )?.name - } -
  • - ))} -
- - ) : ( -

There are no regions in the db.

- )} + {allRegions.map((region) => ( +
+

{region.name}

+
+ +
+
+ ))}
); } diff --git a/src/app/_components/AllSubRegions.tsx b/src/app/_components/AllSubRegions.tsx new file mode 100644 index 0000000..ccdce27 --- /dev/null +++ b/src/app/_components/AllSubRegions.tsx @@ -0,0 +1,22 @@ +import { Delete } from "lucide-react"; +import deleteSubRegion from "~/server/actions/deleteSubRegion"; +import getAllSubRegions from "~/server/actions/getAllSubRegions"; + +export default async function AllSubRegions() { + const allSubRegions = await getAllSubRegions(); + return ( +
+

All Sub Regions:

+ {allSubRegions.map((subRegion) => ( +
+

{subRegion.name}

+
+ +
+
+ ))} +
+ ); +} diff --git a/src/app/_components/admin/CreateProducer.tsx b/src/app/_components/admin/CreateProducer.tsx new file mode 100644 index 0000000..067e7db --- /dev/null +++ b/src/app/_components/admin/CreateProducer.tsx @@ -0,0 +1,13 @@ +"use server"; +import getAllCountries from "~/server/actions/getAllCountries"; +import CreateProducerForm from "./CreateProducerForm"; + +export default async function CreateProducer() { + const allCountries = await getAllCountries(); + return ( +
+

Fill the form to create a new producer

+ +
+ ); +} diff --git a/src/app/_components/admin/CreateProducerForm.tsx b/src/app/_components/admin/CreateProducerForm.tsx new file mode 100644 index 0000000..abe5c4a --- /dev/null +++ b/src/app/_components/admin/CreateProducerForm.tsx @@ -0,0 +1,108 @@ +"use client"; +import clsx from "clsx"; +import { Check, CircleX } from "lucide-react"; +import { useFormState } from "react-dom"; +import { Input } from "~/components/ui/input"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "~/components/ui/select"; +import { Textarea } from "~/components/ui/textarea"; +import { addProducer } from "~/server/actions/addProducer"; +import SubmitButton from "../SubmitButton"; + +type Country = { + id: string; + name: string; +}; + +export default function CreateProducerForm(props: { allCountries: Country[] }) { + const { allCountries } = props; + const [formState, formAction] = useFormState(addProducer, { + message: "", + errors: undefined, + fieldValues: { + name: "", + description: "", + imageUrl: "", + countryId: "", + }, + }); + return ( +
+ + {formState.message !== "" && !formState.errors?.name ? ( + + ) : ( + "" + )} + {formState.errors?.name ? ( +
+ + {formState.errors?.name} +
+ ) : ( + "" + )} +