Merge pull request 'admin-forms' (#12) from admin-forms into main
	
		
			
	
		
	
	
		
	
		
			All checks were successful
		
		
	
	
		
			
				
	
				Vercel Production Deployment / Deploy-Production (push) Successful in 1m20s
				
			
		
		
	
	
				
					
				
			
		
			All checks were successful
		
		
	
	Vercel Production Deployment / Deploy-Production (push) Successful in 1m20s
				
			Reviewed-on: #12
This commit is contained in:
		
						commit
						93c0348564
					
				@ -4,6 +4,10 @@ import CreateCountry from "./_components/admin/CreateCountry";
 | 
				
			|||||||
import AllCountries from "./_components/AllCountries";
 | 
					import AllCountries from "./_components/AllCountries";
 | 
				
			||||||
import CreateRegion from "./_components/admin/CreateRegion";
 | 
					import CreateRegion from "./_components/admin/CreateRegion";
 | 
				
			||||||
import AllRegions from "./_components/AllRegions";
 | 
					import AllRegions from "./_components/AllRegions";
 | 
				
			||||||
 | 
					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() {
 | 
					export default function App() {
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
@ -14,6 +18,10 @@ export default function App() {
 | 
				
			|||||||
      <AllCountries />
 | 
					      <AllCountries />
 | 
				
			||||||
      <CreateRegion />
 | 
					      <CreateRegion />
 | 
				
			||||||
      <AllRegions />
 | 
					      <AllRegions />
 | 
				
			||||||
 | 
					      <CreateSubRegion />
 | 
				
			||||||
 | 
					      <AllSubRegions />
 | 
				
			||||||
 | 
					      <CreateProducer />
 | 
				
			||||||
 | 
					      <AllProducers />
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,9 +1,9 @@
 | 
				
			|||||||
import { Delete } from "lucide-react";
 | 
					import { Delete } from "lucide-react";
 | 
				
			||||||
import { deleteCountry } from "~/server/actions/deleteCountry";
 | 
					import { deleteCountry } from "~/server/actions/deleteCountry";
 | 
				
			||||||
import { db } from "~/server/db";
 | 
					import getAllCountries from "~/server/actions/getAllCountries";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default async function AllCountries() {
 | 
					export default async function AllCountries() {
 | 
				
			||||||
  const countries = await db.query.countries.findMany();
 | 
					  const countries = await getAllCountries();
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <div className="pt-4">
 | 
					    <div className="pt-4">
 | 
				
			||||||
      <h1 className="text-2xl">All Countries:</h1>
 | 
					      <h1 className="text-2xl">All Countries:</h1>
 | 
				
			||||||
 | 
				
			|||||||
@ -1,29 +1,24 @@
 | 
				
			|||||||
import { db } from "~/server/db";
 | 
					import { Delete } from "lucide-react";
 | 
				
			||||||
 | 
					import deleteRegion from "~/server/actions/deleteRegion";
 | 
				
			||||||
 | 
					import getAllCountries from "~/server/actions/getAllCountries";
 | 
				
			||||||
 | 
					import getAllRegions from "~/server/actions/getAllRegions";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default async function AllRegions() {
 | 
					export default async function AllRegions() {
 | 
				
			||||||
  const allRegions = await db.query.regions.findMany();
 | 
					  const allRegions = await getAllRegions();
 | 
				
			||||||
  const allCountries = await db.query.countries.findMany();
 | 
					  const allCountries = await getAllCountries();
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <div className="pt-4">
 | 
					    <div className="pt-4">
 | 
				
			||||||
      <h1 className="text-2xl">All Regions:</h1>
 | 
					      <h1 className="text-2xl">All Regions:</h1>
 | 
				
			||||||
      {allRegions[0] ? (
 | 
					 | 
				
			||||||
        <>
 | 
					 | 
				
			||||||
          <ul>
 | 
					 | 
				
			||||||
      {allRegions.map((region) => (
 | 
					      {allRegions.map((region) => (
 | 
				
			||||||
              <li key={region.id}>
 | 
					        <div key={region.id} className="flex gap-1">
 | 
				
			||||||
                {region.name} -{" "}
 | 
					          <p>{region.name}</p>
 | 
				
			||||||
                {
 | 
					          <form action={deleteRegion.bind(null, region.id)}>
 | 
				
			||||||
                  allCountries.find(
 | 
					            <button>
 | 
				
			||||||
                    (country) => country.id === region.countryId,
 | 
					              <Delete />
 | 
				
			||||||
                  )?.name
 | 
					            </button>
 | 
				
			||||||
                }
 | 
					          </form>
 | 
				
			||||||
              </li>
 | 
					        </div>
 | 
				
			||||||
      ))}
 | 
					      ))}
 | 
				
			||||||
          </ul>
 | 
					 | 
				
			||||||
        </>
 | 
					 | 
				
			||||||
      ) : (
 | 
					 | 
				
			||||||
        <p>There are no regions in the db.</p>
 | 
					 | 
				
			||||||
      )}
 | 
					 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										22
									
								
								src/app/_components/AllSubRegions.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								src/app/_components/AllSubRegions.tsx
									
									
									
									
									
										Normal file
									
								
							@ -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 (
 | 
				
			||||||
 | 
					    <div className="pt-4">
 | 
				
			||||||
 | 
					      <h1 className="text-2xl">All Sub Regions:</h1>
 | 
				
			||||||
 | 
					      {allSubRegions.map((subRegion) => (
 | 
				
			||||||
 | 
					        <div key={subRegion.id} className="flex gap-1">
 | 
				
			||||||
 | 
					          <p>{subRegion.name}</p>
 | 
				
			||||||
 | 
					          <form action={deleteSubRegion.bind(null, subRegion.id)}>
 | 
				
			||||||
 | 
					            <button>
 | 
				
			||||||
 | 
					              <Delete />
 | 
				
			||||||
 | 
					            </button>
 | 
				
			||||||
 | 
					          </form>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      ))}
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -2,9 +2,9 @@ import CreateCountryForm from "./CreateCountryForm";
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
export default function CreateCountry() {
 | 
					export default function CreateCountry() {
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <>
 | 
					    <div className="container flex w-full flex-col justify-center py-4">
 | 
				
			||||||
      <h1 className="pt-4 text-2xl">Fill the form to create a new country</h1>
 | 
					      <h1 className="pt-4 text-2xl">Fill the form to create a new country</h1>
 | 
				
			||||||
      <CreateCountryForm />
 | 
					      <CreateCountryForm />
 | 
				
			||||||
    </>
 | 
					    </div>
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										13
									
								
								src/app/_components/admin/CreateProducer.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/app/_components/admin/CreateProducer.tsx
									
									
									
									
									
										Normal file
									
								
							@ -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 (
 | 
				
			||||||
 | 
					    <div className="container flex w-full flex-col justify-center py-4">
 | 
				
			||||||
 | 
					      <h1 className="pt-4 text-2xl">Fill the form to create a new producer</h1>
 | 
				
			||||||
 | 
					      <CreateProducerForm allCountries={allCountries} />
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										108
									
								
								src/app/_components/admin/CreateProducerForm.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								src/app/_components/admin/CreateProducerForm.tsx
									
									
									
									
									
										Normal file
									
								
							@ -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 (
 | 
				
			||||||
 | 
					    <form action={formAction}>
 | 
				
			||||||
 | 
					      <Input
 | 
				
			||||||
 | 
					        name="name"
 | 
				
			||||||
 | 
					        id="name"
 | 
				
			||||||
 | 
					        placeholder="Enter the name of the producer..."
 | 
				
			||||||
 | 
					        className={clsx({ "border-red-500": formState.errors?.name })}
 | 
				
			||||||
 | 
					      />
 | 
				
			||||||
 | 
					      {formState.message !== "" && !formState.errors?.name ? (
 | 
				
			||||||
 | 
					        <Check className="text-green-500" />
 | 
				
			||||||
 | 
					      ) : (
 | 
				
			||||||
 | 
					        ""
 | 
				
			||||||
 | 
					      )}
 | 
				
			||||||
 | 
					      {formState.errors?.name ? (
 | 
				
			||||||
 | 
					        <div className="flex min-w-96 items-center gap-1 text-red-500">
 | 
				
			||||||
 | 
					          <CircleX />
 | 
				
			||||||
 | 
					          <span className="text-sm">{formState.errors?.name}</span>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      ) : (
 | 
				
			||||||
 | 
					        ""
 | 
				
			||||||
 | 
					      )}
 | 
				
			||||||
 | 
					      <Textarea
 | 
				
			||||||
 | 
					        name="description"
 | 
				
			||||||
 | 
					        id="description"
 | 
				
			||||||
 | 
					        placeholder="Enter a description of the producer..."
 | 
				
			||||||
 | 
					        className={clsx({ "border-red-500": formState.errors?.description })}
 | 
				
			||||||
 | 
					      />
 | 
				
			||||||
 | 
					      {formState.message !== "" && !formState.errors?.description ? (
 | 
				
			||||||
 | 
					        <Check className="text-green-500" />
 | 
				
			||||||
 | 
					      ) : (
 | 
				
			||||||
 | 
					        ""
 | 
				
			||||||
 | 
					      )}
 | 
				
			||||||
 | 
					      {formState.errors?.description ? (
 | 
				
			||||||
 | 
					        <div className="flex min-w-96 items-center gap-1 text-red-500">
 | 
				
			||||||
 | 
					          <CircleX />
 | 
				
			||||||
 | 
					          <span className="text-sm">{formState.errors?.description}</span>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      ) : (
 | 
				
			||||||
 | 
					        ""
 | 
				
			||||||
 | 
					      )}
 | 
				
			||||||
 | 
					      <Input
 | 
				
			||||||
 | 
					        name="imageUrl"
 | 
				
			||||||
 | 
					        id="imageUrl"
 | 
				
			||||||
 | 
					        placeholder="Image URL"
 | 
				
			||||||
 | 
					        className={clsx({ "border-red-500": formState.errors?.imageUrl })}
 | 
				
			||||||
 | 
					      />
 | 
				
			||||||
 | 
					      {formState.message !== "" && !formState.errors?.imageUrl ? (
 | 
				
			||||||
 | 
					        <Check className="text-green-500" />
 | 
				
			||||||
 | 
					      ) : (
 | 
				
			||||||
 | 
					        ""
 | 
				
			||||||
 | 
					      )}
 | 
				
			||||||
 | 
					      {formState.errors?.imageUrl ? (
 | 
				
			||||||
 | 
					        <div className="flex min-w-96 items-center gap-1 text-red-500">
 | 
				
			||||||
 | 
					          <CircleX />
 | 
				
			||||||
 | 
					          <span className="text-sm">{formState.errors?.imageUrl}</span>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      ) : (
 | 
				
			||||||
 | 
					        ""
 | 
				
			||||||
 | 
					      )}
 | 
				
			||||||
 | 
					      <Select name="countryId">
 | 
				
			||||||
 | 
					        <SelectTrigger className={`w-[180px] `}>
 | 
				
			||||||
 | 
					          <SelectValue placeholder="select country" />
 | 
				
			||||||
 | 
					        </SelectTrigger>
 | 
				
			||||||
 | 
					        <SelectContent>
 | 
				
			||||||
 | 
					          {allCountries.map((country) => (
 | 
				
			||||||
 | 
					            <SelectItem key={country.id} value={country.id}>
 | 
				
			||||||
 | 
					              {country.name}
 | 
				
			||||||
 | 
					            </SelectItem>
 | 
				
			||||||
 | 
					          ))}
 | 
				
			||||||
 | 
					        </SelectContent>
 | 
				
			||||||
 | 
					      </Select>
 | 
				
			||||||
 | 
					      <SubmitButton text={"producer"} />
 | 
				
			||||||
 | 
					    </form>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -1,13 +1,13 @@
 | 
				
			|||||||
"use server";
 | 
					"use server";
 | 
				
			||||||
import { db } from "~/server/db";
 | 
					 | 
				
			||||||
import CreateRegionForm from "./CreateRegionForm";
 | 
					import CreateRegionForm from "./CreateRegionForm";
 | 
				
			||||||
 | 
					import getAllCountries from "~/server/actions/getAllCountries";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default async function CreateRegion() {
 | 
					export default async function CreateRegion() {
 | 
				
			||||||
  const allCountries = await db.query.countries.findMany();
 | 
					  const allCountries = await getAllCountries();
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <>
 | 
					    <div className="container flex w-full flex-col justify-center py-4">
 | 
				
			||||||
      <h1 className="pt-4 text-2xl">Fill the form to create a new region</h1>
 | 
					      <h1 className="pt-4 text-2xl">Fill the form to create a new region</h1>
 | 
				
			||||||
      <CreateRegionForm countries={allCountries} />
 | 
					      <CreateRegionForm countries={allCountries} />
 | 
				
			||||||
    </>
 | 
					    </div>
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										21
									
								
								src/app/_components/admin/CreateSubRegion.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								src/app/_components/admin/CreateSubRegion.tsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,21 @@
 | 
				
			|||||||
 | 
					"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 (
 | 
				
			||||||
 | 
					    <div className="container flex w-full flex-col justify-center py-4">
 | 
				
			||||||
 | 
					      <h1 className="pt-4 text-2xl">
 | 
				
			||||||
 | 
					        Fill the form to create a new Sub Region
 | 
				
			||||||
 | 
					      </h1>
 | 
				
			||||||
 | 
					      <CreateSubRegionForm
 | 
				
			||||||
 | 
					        allRegions={allRegions}
 | 
				
			||||||
 | 
					        allCountries={allCountries}
 | 
				
			||||||
 | 
					      />
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										136
									
								
								src/app/_components/admin/CreateSubRegionForm.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										136
									
								
								src/app/_components/admin/CreateSubRegionForm.tsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,136 @@
 | 
				
			|||||||
 | 
					"use client";
 | 
				
			||||||
 | 
					import clsx from "clsx";
 | 
				
			||||||
 | 
					import { ChangeEvent, useEffect, useRef, 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 { addSubRegion } from "~/server/actions/addSubRegion";
 | 
				
			||||||
 | 
					import SubmitButton from "../SubmitButton";
 | 
				
			||||||
 | 
					import { Check, CircleX } from "lucide-react";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Region = {
 | 
				
			||||||
 | 
					  id: string;
 | 
				
			||||||
 | 
					  name: string;
 | 
				
			||||||
 | 
					  countryId: string;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					type Country = {
 | 
				
			||||||
 | 
					  id: string;
 | 
				
			||||||
 | 
					  name: string;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default function CreateSubRegionForm(props: {
 | 
				
			||||||
 | 
					  allRegions: Region[];
 | 
				
			||||||
 | 
					  allCountries: Country[];
 | 
				
			||||||
 | 
					}) {
 | 
				
			||||||
 | 
					  const { allRegions, allCountries } = props;
 | 
				
			||||||
 | 
					  const [selectCountryId, setSelectCountryId] = useState<string | undefined>(
 | 
				
			||||||
 | 
					    undefined,
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					  const [selectCountryRegions, setSelectCountryRegions] = useState<Region[]>(
 | 
				
			||||||
 | 
					    [],
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					  const [formState, formActions] = useFormState(addSubRegion, {
 | 
				
			||||||
 | 
					    message: "",
 | 
				
			||||||
 | 
					    errors: undefined,
 | 
				
			||||||
 | 
					    fieldValues: {
 | 
				
			||||||
 | 
					      name: "",
 | 
				
			||||||
 | 
					      regionId: "",
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  useEffect(() => {
 | 
				
			||||||
 | 
					    if (selectCountryId) {
 | 
				
			||||||
 | 
					      const regions = allRegions.filter(
 | 
				
			||||||
 | 
					        (region) => region.countryId === selectCountryId,
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					      setSelectCountryRegions(regions);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }, [selectCountryId]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const formRef = useRef<HTMLFormElement>(null);
 | 
				
			||||||
 | 
					  useEffect(() => {
 | 
				
			||||||
 | 
					    if (formState.message === "success") {
 | 
				
			||||||
 | 
					      formRef.current?.reset();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }, [formState.message]);
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <div className="flex flex-col gap-2">
 | 
				
			||||||
 | 
					      {/* country selector */}
 | 
				
			||||||
 | 
					      <Select
 | 
				
			||||||
 | 
					        name="country"
 | 
				
			||||||
 | 
					        onValueChange={(value) => setSelectCountryId(value)}
 | 
				
			||||||
 | 
					      >
 | 
				
			||||||
 | 
					        <SelectTrigger className={`w-[180px] `}>
 | 
				
			||||||
 | 
					          <SelectValue placeholder="select country" />
 | 
				
			||||||
 | 
					        </SelectTrigger>
 | 
				
			||||||
 | 
					        <SelectContent>
 | 
				
			||||||
 | 
					          {allCountries.map((country) => (
 | 
				
			||||||
 | 
					            <SelectItem key={country.id} value={country.id}>
 | 
				
			||||||
 | 
					              {country.name}
 | 
				
			||||||
 | 
					            </SelectItem>
 | 
				
			||||||
 | 
					          ))}
 | 
				
			||||||
 | 
					        </SelectContent>
 | 
				
			||||||
 | 
					      </Select>
 | 
				
			||||||
 | 
					      <form ref={formRef} action={formActions}>
 | 
				
			||||||
 | 
					        {/* region selector */}
 | 
				
			||||||
 | 
					        <div className="flex max-w-3xl items-center gap-2">
 | 
				
			||||||
 | 
					          <Select name="regionId">
 | 
				
			||||||
 | 
					            <SelectTrigger
 | 
				
			||||||
 | 
					              className={`w-[180px] ${clsx({ "border-red-500": formState.errors?.regionId })}`}
 | 
				
			||||||
 | 
					            >
 | 
				
			||||||
 | 
					              <SelectValue placeholder="select region" />
 | 
				
			||||||
 | 
					            </SelectTrigger>
 | 
				
			||||||
 | 
					            <SelectContent>
 | 
				
			||||||
 | 
					              {selectCountryRegions.map((region) => (
 | 
				
			||||||
 | 
					                <SelectItem key={region.id} value={region.id}>
 | 
				
			||||||
 | 
					                  {region.name}
 | 
				
			||||||
 | 
					                </SelectItem>
 | 
				
			||||||
 | 
					              ))}
 | 
				
			||||||
 | 
					            </SelectContent>
 | 
				
			||||||
 | 
					          </Select>
 | 
				
			||||||
 | 
					          {formState.message === "success" && !formState.errors?.regionId ? (
 | 
				
			||||||
 | 
					            <Check className="text-green-500" />
 | 
				
			||||||
 | 
					          ) : (
 | 
				
			||||||
 | 
					            ""
 | 
				
			||||||
 | 
					          )}
 | 
				
			||||||
 | 
					          {formState.errors?.regionId ? (
 | 
				
			||||||
 | 
					            <div className="flex min-w-40 items-center gap-1 text-red-500">
 | 
				
			||||||
 | 
					              <CircleX className="text-red-500" />
 | 
				
			||||||
 | 
					              <span className="text-sm">{formState.errors?.regionId}</span>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					          ) : (
 | 
				
			||||||
 | 
					            ""
 | 
				
			||||||
 | 
					          )}
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					        <div className="flex max-w-3xl items-center gap-2">
 | 
				
			||||||
 | 
					          <Input
 | 
				
			||||||
 | 
					            name="name"
 | 
				
			||||||
 | 
					            id="name"
 | 
				
			||||||
 | 
					            placeholder="Name the sub region"
 | 
				
			||||||
 | 
					            className={`${clsx({ "border-red-500": formState.errors?.name })}`}
 | 
				
			||||||
 | 
					          />
 | 
				
			||||||
 | 
					          {formState.message === "success" && !formState.errors?.name ? (
 | 
				
			||||||
 | 
					            <Check className="text-green-500" />
 | 
				
			||||||
 | 
					          ) : (
 | 
				
			||||||
 | 
					            ""
 | 
				
			||||||
 | 
					          )}
 | 
				
			||||||
 | 
					          {formState.errors?.name ? (
 | 
				
			||||||
 | 
					            <div className="flex min-w-40 items-center gap-1 text-red-500">
 | 
				
			||||||
 | 
					              <CircleX className="text-red-500" />
 | 
				
			||||||
 | 
					              <span className="text-sm">{formState.errors?.name}</span>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					          ) : (
 | 
				
			||||||
 | 
					            ""
 | 
				
			||||||
 | 
					          )}
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					        <SubmitButton text={"sub region"} />
 | 
				
			||||||
 | 
					      </form>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										22
									
								
								src/app/_components/allProducers.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								src/app/_components/allProducers.tsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,22 @@
 | 
				
			|||||||
 | 
					import { Delete } from "lucide-react";
 | 
				
			||||||
 | 
					import deleteProducer from "~/server/actions/deleteProducer";
 | 
				
			||||||
 | 
					import getAllProducers from "~/server/actions/getAllProducers";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default async function AllProducers() {
 | 
				
			||||||
 | 
					  const allProducers = await getAllProducers();
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <div className="pt-4">
 | 
				
			||||||
 | 
					      <h1 className="text-2xl">All Producers:</h1>
 | 
				
			||||||
 | 
					      {allProducers.map((producer) => (
 | 
				
			||||||
 | 
					        <div key={producer.id} className="flex gap-1">
 | 
				
			||||||
 | 
					          <p>{producer.name}</p>
 | 
				
			||||||
 | 
					          <form action={deleteProducer.bind(null, producer.id)}>
 | 
				
			||||||
 | 
					            <button>
 | 
				
			||||||
 | 
					              <Delete />
 | 
				
			||||||
 | 
					            </button>
 | 
				
			||||||
 | 
					          </form>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      ))}
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										24
									
								
								src/components/ui/textarea.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								src/components/ui/textarea.tsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,24 @@
 | 
				
			|||||||
 | 
					import * as React from "react"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { cn } from "~/lib/utils"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export interface TextareaProps
 | 
				
			||||||
 | 
					  extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
 | 
				
			||||||
 | 
					  ({ className, ...props }, ref) => {
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					      <textarea
 | 
				
			||||||
 | 
					        className={cn(
 | 
				
			||||||
 | 
					          "flex min-h-[80px] w-full rounded-md border border-slate-200 bg-white px-3 py-2 text-sm ring-offset-white placeholder:text-slate-500 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-slate-950 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 dark:border-slate-800 dark:bg-slate-950 dark:ring-offset-slate-950 dark:placeholder:text-slate-400 dark:focus-visible:ring-slate-300",
 | 
				
			||||||
 | 
					          className
 | 
				
			||||||
 | 
					        )}
 | 
				
			||||||
 | 
					        ref={ref}
 | 
				
			||||||
 | 
					        {...props}
 | 
				
			||||||
 | 
					      />
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					Textarea.displayName = "Textarea"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export { Textarea }
 | 
				
			||||||
							
								
								
									
										77
									
								
								src/server/actions/addProducer.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								src/server/actions/addProducer.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,77 @@
 | 
				
			|||||||
 | 
					"use server";
 | 
				
			||||||
 | 
					import { eq } from "drizzle-orm";
 | 
				
			||||||
 | 
					import { db } from "../db";
 | 
				
			||||||
 | 
					import { producers } from "../db/schema";
 | 
				
			||||||
 | 
					import { ZodError, z } from "zod";
 | 
				
			||||||
 | 
					import { revalidatePath } from "next/cache";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const addProducer = async (prevstate: any, formData: FormData) => {
 | 
				
			||||||
 | 
					  //assign formdaata to variables.
 | 
				
			||||||
 | 
					  const name = (formData.get("name") as string).toLowerCase();
 | 
				
			||||||
 | 
					  const description = (formData.get("description") as string).toLowerCase();
 | 
				
			||||||
 | 
					  const imageUrl = (formData.get("imageUrl") as string).toLowerCase();
 | 
				
			||||||
 | 
					  const countryId = formData.get("countryId") as string;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  //check if producer already exists in country
 | 
				
			||||||
 | 
					  const exists = await db
 | 
				
			||||||
 | 
					    .select({ name: producers.name })
 | 
				
			||||||
 | 
					    .from(producers)
 | 
				
			||||||
 | 
					    .where(eq(producers.name, name));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  //Define the schema for the form data
 | 
				
			||||||
 | 
					  const schema = z.object({
 | 
				
			||||||
 | 
					    name: z
 | 
				
			||||||
 | 
					      .string()
 | 
				
			||||||
 | 
					      .min(1, "Name is required")
 | 
				
			||||||
 | 
					      .refine(() => !exists[0], {
 | 
				
			||||||
 | 
					        message: `${name} already exists in selected country`,
 | 
				
			||||||
 | 
					      }),
 | 
				
			||||||
 | 
					    description: z.string(),
 | 
				
			||||||
 | 
					    imageUrl: z.string(),
 | 
				
			||||||
 | 
					    countryId: z.string().min(1, "No country selected"),
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					  //Parse the form data using the schema for validation, and check if the name already exists
 | 
				
			||||||
 | 
					  try {
 | 
				
			||||||
 | 
					    schema.parse({
 | 
				
			||||||
 | 
					      name,
 | 
				
			||||||
 | 
					      description,
 | 
				
			||||||
 | 
					      imageUrl,
 | 
				
			||||||
 | 
					      countryId,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    //If the name doesn't exist, add the country to the database abd revalidate the page
 | 
				
			||||||
 | 
					    await db
 | 
				
			||||||
 | 
					      .insert(producers)
 | 
				
			||||||
 | 
					      .values({ name, description, imageUrl, countryId });
 | 
				
			||||||
 | 
					    revalidatePath("/");
 | 
				
			||||||
 | 
					    //Return a success message
 | 
				
			||||||
 | 
					    return {
 | 
				
			||||||
 | 
					      message: "success",
 | 
				
			||||||
 | 
					      errors: undefined,
 | 
				
			||||||
 | 
					      fieldValues: {
 | 
				
			||||||
 | 
					        name: "",
 | 
				
			||||||
 | 
					        description: "",
 | 
				
			||||||
 | 
					        imageUrl: "",
 | 
				
			||||||
 | 
					        countryId: "",
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  } 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] ?? "",
 | 
				
			||||||
 | 
					        description: errorMap["description"]?.[0] ?? "",
 | 
				
			||||||
 | 
					        imageUrl: errorMap["imageUrl"]?.[0] ?? "",
 | 
				
			||||||
 | 
					        countryId: errorMap["countryId"]?.[0] ?? "",
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      fieldValues: {
 | 
				
			||||||
 | 
					        name,
 | 
				
			||||||
 | 
					        description,
 | 
				
			||||||
 | 
					        imageUrl,
 | 
				
			||||||
 | 
					        countryId,
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
							
								
								
									
										64
									
								
								src/server/actions/addSubRegion.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								src/server/actions/addSubRegion.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,64 @@
 | 
				
			|||||||
 | 
					"use server";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { eq } from "drizzle-orm";
 | 
				
			||||||
 | 
					import { db } from "../db";
 | 
				
			||||||
 | 
					import { subRegions } from "../db/schema";
 | 
				
			||||||
 | 
					import { ZodError, z } from "zod";
 | 
				
			||||||
 | 
					import { revalidatePath } from "next/cache";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const addSubRegion = async (prevstate: any, formData: FormData) => {
 | 
				
			||||||
 | 
					  //assign formdaata to variables.
 | 
				
			||||||
 | 
					  const name = (formData.get("name") as string).toLowerCase();
 | 
				
			||||||
 | 
					  const regionId = formData.get("regionId") 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[0], {
 | 
				
			||||||
 | 
					        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 });
 | 
				
			||||||
 | 
					    revalidatePath("/");
 | 
				
			||||||
 | 
					    //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,
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
							
								
								
									
										10
									
								
								src/server/actions/deleteProducer.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								src/server/actions/deleteProducer.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,10 @@
 | 
				
			|||||||
 | 
					"use server";
 | 
				
			||||||
 | 
					import { eq } from "drizzle-orm";
 | 
				
			||||||
 | 
					import { db } from "../db";
 | 
				
			||||||
 | 
					import { producers } from "../db/schema";
 | 
				
			||||||
 | 
					import { revalidatePath } from "next/cache";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default async function deleteProducer(id: string) {
 | 
				
			||||||
 | 
					  await db.delete(producers).where(eq(producers.id, id));
 | 
				
			||||||
 | 
					  revalidatePath("/");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										10
									
								
								src/server/actions/deleteRegion.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								src/server/actions/deleteRegion.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,10 @@
 | 
				
			|||||||
 | 
					"use server";
 | 
				
			||||||
 | 
					import { eq } from "drizzle-orm";
 | 
				
			||||||
 | 
					import { db } from "../db";
 | 
				
			||||||
 | 
					import { regions } from "../db/schema";
 | 
				
			||||||
 | 
					import { revalidatePath } from "next/cache";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default async function deleteRegion(id: string) {
 | 
				
			||||||
 | 
					  await db.delete(regions).where(eq(regions.id, id));
 | 
				
			||||||
 | 
					  revalidatePath("/");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										10
									
								
								src/server/actions/deleteSubRegion.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								src/server/actions/deleteSubRegion.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,10 @@
 | 
				
			|||||||
 | 
					"use server";
 | 
				
			||||||
 | 
					import { eq } from "drizzle-orm";
 | 
				
			||||||
 | 
					import { db } from "../db";
 | 
				
			||||||
 | 
					import { subRegions } from "../db/schema";
 | 
				
			||||||
 | 
					import { revalidatePath } from "next/cache";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default async function deleteSubRegion(id: string) {
 | 
				
			||||||
 | 
					  await db.delete(subRegions).where(eq(subRegions.id, id));
 | 
				
			||||||
 | 
					  revalidatePath("/");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										6
									
								
								src/server/actions/getAllCountries.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								src/server/actions/getAllCountries.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,6 @@
 | 
				
			|||||||
 | 
					import { db } from "../db";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default async function getAllCountries() {
 | 
				
			||||||
 | 
					  const allCountries = await db.query.countries.findMany();
 | 
				
			||||||
 | 
					  return allCountries;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										7
									
								
								src/server/actions/getAllProducers.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								src/server/actions/getAllProducers.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,7 @@
 | 
				
			|||||||
 | 
					"use server";
 | 
				
			||||||
 | 
					import { db } from "../db";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default async function getAllProducers() {
 | 
				
			||||||
 | 
					  const allProducers = await db.query.producers.findMany();
 | 
				
			||||||
 | 
					  return allProducers;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										6
									
								
								src/server/actions/getAllRegions.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								src/server/actions/getAllRegions.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,6 @@
 | 
				
			|||||||
 | 
					import { db } from "../db";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default async function getAllRegions() {
 | 
				
			||||||
 | 
					  const allRegions = await db.query.regions.findMany();
 | 
				
			||||||
 | 
					  return allRegions;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										7
									
								
								src/server/actions/getAllSubRegions.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								src/server/actions/getAllSubRegions.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,7 @@
 | 
				
			|||||||
 | 
					"use server";
 | 
				
			||||||
 | 
					import { db } from "../db";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default async function getAllSubRegions() {
 | 
				
			||||||
 | 
					  const allSubRegions = await db.query.subRegions.findMany();
 | 
				
			||||||
 | 
					  return allSubRegions;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user