added form to create country
This commit is contained in:
		
							parent
							
								
									ef08c000ec
								
							
						
					
					
						commit
						2f158c49d6
					
				@ -1,17 +1,15 @@
 | 
				
			|||||||
"use client";
 | 
					 | 
				
			||||||
import useFilterStore from "./store";
 | 
					 | 
				
			||||||
import WineList from "./_components/WineList";
 | 
					import WineList from "./_components/WineList";
 | 
				
			||||||
 | 
					import FilterStatus from "./_components/FilterState";
 | 
				
			||||||
 | 
					import CreateCountry from "./_components/admin/CreateCountry";
 | 
				
			||||||
 | 
					import AllCountries from "./_components/AllCountries";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default function App() {
 | 
					export default function App() {
 | 
				
			||||||
  const filters = useFilterStore((state) => state.filters);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <div className="container flex w-full flex-col justify-center">
 | 
					    <div className="container flex w-full flex-col justify-center">
 | 
				
			||||||
      <h1 className="text-2xl">Filter state:</h1>
 | 
					      <FilterStatus />
 | 
				
			||||||
      {JSON.stringify(filters)}
 | 
					      <WineList />
 | 
				
			||||||
 | 
					      <CreateCountry />
 | 
				
			||||||
 | 
					      <AllCountries />
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										7
									
								
								src/app/_components/AllCountries.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								src/app/_components/AllCountries.tsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,7 @@
 | 
				
			|||||||
 | 
					export default async function AllCountries() {
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <div className="pt-4">
 | 
				
			||||||
 | 
					      <h1 className="text-2xl">All Countries:</h1>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -1,76 +0,0 @@
 | 
				
			|||||||
"use client";
 | 
					 | 
				
			||||||
import { useActionState, useEffect, useState } from "react";
 | 
					 | 
				
			||||||
import { Button } from "~/components/ui/button";
 | 
					 | 
				
			||||||
import { Input } from "~/components/ui/input";
 | 
					 | 
				
			||||||
import {
 | 
					 | 
				
			||||||
  Select,
 | 
					 | 
				
			||||||
  SelectContent,
 | 
					 | 
				
			||||||
  SelectItem,
 | 
					 | 
				
			||||||
  SelectTrigger,
 | 
					 | 
				
			||||||
  SelectValue,
 | 
					 | 
				
			||||||
} from "~/components/ui/select";
 | 
					 | 
				
			||||||
import { addWine } from "~/server/actions/addWine";
 | 
					 | 
				
			||||||
import { getProducers } from "~/server/actions/allProducers";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
async function fetchProducers() {
 | 
					 | 
				
			||||||
  const producers = await getProducers();
 | 
					 | 
				
			||||||
  return producers;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type ProducersData = {
 | 
					 | 
				
			||||||
  id: string;
 | 
					 | 
				
			||||||
  name: string;
 | 
					 | 
				
			||||||
  createdAt: Date;
 | 
					 | 
				
			||||||
  country: string;
 | 
					 | 
				
			||||||
  region: string;
 | 
					 | 
				
			||||||
  email: string;
 | 
					 | 
				
			||||||
}[];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export default function CreateWine() {
 | 
					 | 
				
			||||||
  const [formState, formAction] = useActionState(addWine, {
 | 
					 | 
				
			||||||
    message: "",
 | 
					 | 
				
			||||||
    errors: undefined,
 | 
					 | 
				
			||||||
    fieldValues: {
 | 
					 | 
				
			||||||
      name: "",
 | 
					 | 
				
			||||||
      producer: "",
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
  const [producers, setProducers] = useState<ProducersData>([]);
 | 
					 | 
				
			||||||
  useEffect(() => {
 | 
					 | 
				
			||||||
    async function loadProducers() {
 | 
					 | 
				
			||||||
      const producersData = await fetchProducers();
 | 
					 | 
				
			||||||
      setProducers(producersData);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    loadProducers();
 | 
					 | 
				
			||||||
  }, []);
 | 
					 | 
				
			||||||
  return (
 | 
					 | 
				
			||||||
    <div className="flex w-full flex-col">
 | 
					 | 
				
			||||||
      <form action={formAction} className="flex flex-col gap-2">
 | 
					 | 
				
			||||||
        <Input
 | 
					 | 
				
			||||||
          placeholder="Enter wine name"
 | 
					 | 
				
			||||||
          className="border-2"
 | 
					 | 
				
			||||||
          type="text"
 | 
					 | 
				
			||||||
          name="name"
 | 
					 | 
				
			||||||
        />
 | 
					 | 
				
			||||||
        <Select name="producer">
 | 
					 | 
				
			||||||
          <SelectTrigger className="w-[280px]">
 | 
					 | 
				
			||||||
            <SelectValue placeholder="Select a producer" />
 | 
					 | 
				
			||||||
          </SelectTrigger>
 | 
					 | 
				
			||||||
          <SelectContent>
 | 
					 | 
				
			||||||
            {producers.map((producer, i) => (
 | 
					 | 
				
			||||||
              <SelectItem key={i} value={producer.id}>
 | 
					 | 
				
			||||||
                {producer.name}
 | 
					 | 
				
			||||||
              </SelectItem>
 | 
					 | 
				
			||||||
            ))}
 | 
					 | 
				
			||||||
          </SelectContent>
 | 
					 | 
				
			||||||
        </Select>
 | 
					 | 
				
			||||||
        <Button type="submit">Add wine</Button>
 | 
					 | 
				
			||||||
      </form>
 | 
					 | 
				
			||||||
      {formState.message === "success" ? (
 | 
					 | 
				
			||||||
        <span className="text-green-400">Wine succesfully submitted</span>
 | 
					 | 
				
			||||||
      ) : (
 | 
					 | 
				
			||||||
        ""
 | 
					 | 
				
			||||||
      )}
 | 
					 | 
				
			||||||
    </div>
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										12
									
								
								src/app/_components/FilterState.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/app/_components/FilterState.tsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,12 @@
 | 
				
			|||||||
 | 
					"use client";
 | 
				
			||||||
 | 
					import useFilterStore, { FilterState } from "../store";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default function FilterStatus() {
 | 
				
			||||||
 | 
					  const filters = useFilterStore((state) => state.filters);
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <>
 | 
				
			||||||
 | 
					      <h1 className="text-2xl">Filter state:</h1>
 | 
				
			||||||
 | 
					      {JSON.stringify(filters, null, 2)}
 | 
				
			||||||
 | 
					    </>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -1,26 +0,0 @@
 | 
				
			|||||||
import {
 | 
					 | 
				
			||||||
  Card,
 | 
					 | 
				
			||||||
  CardContent,
 | 
					 | 
				
			||||||
  CardDescription,
 | 
					 | 
				
			||||||
  CardFooter,
 | 
					 | 
				
			||||||
  CardHeader,
 | 
					 | 
				
			||||||
  CardTitle,
 | 
					 | 
				
			||||||
} from "~/components/ui/card";
 | 
					 | 
				
			||||||
import CreateWine from "./CreateWine";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export default function FormCard() {
 | 
					 | 
				
			||||||
  return (
 | 
					 | 
				
			||||||
    <Card>
 | 
					 | 
				
			||||||
      <CardHeader>
 | 
					 | 
				
			||||||
        <CardTitle>Add wine</CardTitle>
 | 
					 | 
				
			||||||
        <CardDescription>All fields are required so get to it!</CardDescription>
 | 
					 | 
				
			||||||
      </CardHeader>
 | 
					 | 
				
			||||||
      <CardContent>
 | 
					 | 
				
			||||||
        <CreateWine />
 | 
					 | 
				
			||||||
      </CardContent>
 | 
					 | 
				
			||||||
      <CardFooter>
 | 
					 | 
				
			||||||
        <p>Card Footer</p>
 | 
					 | 
				
			||||||
      </CardFooter>
 | 
					 | 
				
			||||||
    </Card>
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,3 +0,0 @@
 | 
				
			|||||||
export default function Wine(wine) {
 | 
					 | 
				
			||||||
  return <li key={wine.id}>{wine.name}</li>;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,17 +1,23 @@
 | 
				
			|||||||
"use server";
 | 
					"use server";
 | 
				
			||||||
import { db } from "~/server/db";
 | 
					import { db } from "~/server/db";
 | 
				
			||||||
import Wine from "./Wine";
 | 
					import WineName from "./WineName";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const wines = await db.query.wines.findMany();
 | 
				
			||||||
export default async function WineList() {
 | 
					export default async function WineList() {
 | 
				
			||||||
  const wines = await db.query.wines.findMany();
 | 
					 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <>
 | 
					    <div className="pt-4">
 | 
				
			||||||
      <h1>All wines:</h1>
 | 
					      <h1 className="text-2xl">All wines:</h1>
 | 
				
			||||||
      <ul>
 | 
					      {wines && wines.length > 0 ? (
 | 
				
			||||||
        {wines.map((wine) => (
 | 
					        <>
 | 
				
			||||||
          <Wine wine={wine} />
 | 
					          <ul>
 | 
				
			||||||
        ))}
 | 
					            {wines.map((wine) => (
 | 
				
			||||||
      </ul>
 | 
					              <WineName key={wine.id} name={wine.name} />
 | 
				
			||||||
    </>
 | 
					            ))}
 | 
				
			||||||
 | 
					          </ul>
 | 
				
			||||||
 | 
					        </>
 | 
				
			||||||
 | 
					      ) : (
 | 
				
			||||||
 | 
					        <p>There are no wines in the db.</p>
 | 
				
			||||||
 | 
					      )}
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										4
									
								
								src/app/_components/WineName.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								src/app/_components/WineName.tsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,4 @@
 | 
				
			|||||||
 | 
					export default function WineName(props: { name: string }) {
 | 
				
			||||||
 | 
					  const { name } = props;
 | 
				
			||||||
 | 
					  return <p>{name}</p>;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										10
									
								
								src/app/_components/admin/CreateCountry.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								src/app/_components/admin/CreateCountry.tsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,10 @@
 | 
				
			|||||||
 | 
					import CreateCountryForm from "./CreateCountryForm";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default function CreateCountry() {
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <>
 | 
				
			||||||
 | 
					      <h1 className="pt-4 text-2xl">Fill the form to create a new country</h1>
 | 
				
			||||||
 | 
					      <CreateCountryForm />
 | 
				
			||||||
 | 
					    </>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										26
									
								
								src/app/_components/admin/CreateCountryForm.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								src/app/_components/admin/CreateCountryForm.tsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,26 @@
 | 
				
			|||||||
 | 
					import { revalidatePath } from "next/cache";
 | 
				
			||||||
 | 
					import { Button } from "~/components/ui/button";
 | 
				
			||||||
 | 
					import { Input } from "~/components/ui/input";
 | 
				
			||||||
 | 
					import { db } from "~/server/db";
 | 
				
			||||||
 | 
					import { countries } from "~/server/db/schema";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type NewCountry = {
 | 
				
			||||||
 | 
					  name: string;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default async function CreateCountryForm() {
 | 
				
			||||||
 | 
					  const addCountry = async (formData: FormData) => {
 | 
				
			||||||
 | 
					    "use server";
 | 
				
			||||||
 | 
					    const newCountry: NewCountry = {
 | 
				
			||||||
 | 
					      name: formData.get("name") as string,
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    await db.insert(countries).values(newCountry).returning();
 | 
				
			||||||
 | 
					    revalidatePath("/");
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <form action={addCountry}>
 | 
				
			||||||
 | 
					      <Input name="name" required />
 | 
				
			||||||
 | 
					      <Button>Add country</Button>
 | 
				
			||||||
 | 
					    </form>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -2,7 +2,7 @@ import { create } from "zustand";
 | 
				
			|||||||
import { produce } from "immer";
 | 
					import { produce } from "immer";
 | 
				
			||||||
import { persist, createJSONStorage } from "zustand/middleware";
 | 
					import { persist, createJSONStorage } from "zustand/middleware";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface FilterState {
 | 
					export interface FilterState {
 | 
				
			||||||
  filters: Filters;
 | 
					  filters: Filters;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -82,7 +82,7 @@ const useFilterStore = create<FilterState & FilterActions>()(
 | 
				
			|||||||
      setSearchQuery: (searchQuery: string) =>
 | 
					      setSearchQuery: (searchQuery: string) =>
 | 
				
			||||||
        set(
 | 
					        set(
 | 
				
			||||||
          produce((state: FilterState) => {
 | 
					          produce((state: FilterState) => {
 | 
				
			||||||
              state.filters.searchQuery = searchQuery;
 | 
					            state.filters.searchQuery = searchQuery;
 | 
				
			||||||
          }),
 | 
					          }),
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
      addRegion: (region) =>
 | 
					      addRegion: (region) =>
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user