Compare commits
2 Commits
ef08c000ec
...
e70ff89833
Author | SHA1 | Date | |
---|---|---|---|
e70ff89833 | |||
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>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
13
src/app/_components/AllCountries.tsx
Normal file
13
src/app/_components/AllCountries.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { db } from "~/server/db";
|
||||||
|
|
||||||
|
export default async function AllCountries() {
|
||||||
|
const countries = await db.query.countries.findMany();
|
||||||
|
return (
|
||||||
|
<div className="pt-4">
|
||||||
|
<h1 className="text-2xl">All Countries:</h1>
|
||||||
|
{countries.map((country) => (
|
||||||
|
<p key={country.id}>{country.name}</p>
|
||||||
|
))}
|
||||||
|
</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";
|
||||||
|
|
||||||
export default async function WineList() {
|
export default async function WineList() {
|
||||||
const wines = await db.query.wines.findMany();
|
const wines = await db.query.wines.findMany();
|
||||||
return (
|
return (
|
||||||
|
<div className="pt-4">
|
||||||
|
<h1 className="text-2xl">All wines:</h1>
|
||||||
|
{wines && wines.length > 0 ? (
|
||||||
<>
|
<>
|
||||||
<h1>All wines:</h1>
|
|
||||||
<ul>
|
<ul>
|
||||||
{wines.map((wine) => (
|
{wines.map((wine) => (
|
||||||
<Wine wine={wine} />
|
<WineName key={wine.id} name={wine.name} />
|
||||||
))}
|
))}
|
||||||
</ul>
|
</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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ import {
|
|||||||
pgTableCreator,
|
pgTableCreator,
|
||||||
text,
|
text,
|
||||||
timestamp,
|
timestamp,
|
||||||
uuid
|
uuid,
|
||||||
} from "drizzle-orm/pg-core";
|
} from "drizzle-orm/pg-core";
|
||||||
import { relations } from "drizzle-orm";
|
import { relations } from "drizzle-orm";
|
||||||
|
|
||||||
@ -17,9 +17,9 @@ export const producers = createTable(
|
|||||||
"producer",
|
"producer",
|
||||||
{
|
{
|
||||||
id: uuid("id").primaryKey().defaultRandom(),
|
id: uuid("id").primaryKey().defaultRandom(),
|
||||||
name: text("name").notNull(),
|
name: text("name").notNull().unique(),
|
||||||
description: text("description"),
|
description: text("description"),
|
||||||
imageUrl: text('imageUrl'),
|
imageUrl: text("imageUrl"),
|
||||||
countryId: uuid("countryId").notNull(),
|
countryId: uuid("countryId").notNull(),
|
||||||
createdAt: timestamp("createdAt").defaultNow().notNull(),
|
createdAt: timestamp("createdAt").defaultNow().notNull(),
|
||||||
updatedAt: timestamp("updatedAt").defaultNow(),
|
updatedAt: timestamp("updatedAt").defaultNow(),
|
||||||
@ -37,16 +37,20 @@ export const producersRelations = relations(producers, ({ many }) => ({
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
// Wines schema
|
// Wines schema
|
||||||
export const typeEnum = pgEnum('type', ['sparkling', 'white', 'red', 'sweet', 'other']);
|
export const typeEnum = pgEnum("type", [
|
||||||
|
"sparkling",
|
||||||
|
"white",
|
||||||
|
"red",
|
||||||
|
"sweet",
|
||||||
|
"other",
|
||||||
|
]);
|
||||||
|
|
||||||
export const wines = createTable(
|
export const wines = createTable("wine", {
|
||||||
"wine",
|
|
||||||
{
|
|
||||||
id: uuid("id").primaryKey().defaultRandom(),
|
id: uuid("id").primaryKey().defaultRandom(),
|
||||||
name: text("name").notNull(),
|
name: text("name").notNull(),
|
||||||
type: typeEnum("type").notNull(),
|
type: typeEnum("type").notNull(),
|
||||||
description: text("description"),
|
description: text("description"),
|
||||||
imageUrl: text('imageUrl'),
|
imageUrl: text("imageUrl"),
|
||||||
producerId: uuid("producerId").notNull(),
|
producerId: uuid("producerId").notNull(),
|
||||||
subRegionId: uuid("subRegionId"),
|
subRegionId: uuid("subRegionId"),
|
||||||
regionId: uuid("regionId").notNull(),
|
regionId: uuid("regionId").notNull(),
|
||||||
@ -55,8 +59,7 @@ export const wines = createTable(
|
|||||||
inStock: boolean("inStock").notNull().default(false),
|
inStock: boolean("inStock").notNull().default(false),
|
||||||
createdAt: timestamp("createdAt").defaultNow().notNull(),
|
createdAt: timestamp("createdAt").defaultNow().notNull(),
|
||||||
updatedAt: timestamp("updatedAt").defaultNow(),
|
updatedAt: timestamp("updatedAt").defaultNow(),
|
||||||
},
|
});
|
||||||
);
|
|
||||||
|
|
||||||
// many-to-one relationship wine -> producer
|
// many-to-one relationship wine -> producer
|
||||||
export const winesRelations = relations(wines, ({ one }) => ({
|
export const winesRelations = relations(wines, ({ one }) => ({
|
||||||
@ -75,53 +78,44 @@ export const winesRelations = relations(wines, ({ one }) => ({
|
|||||||
country: one(countries, {
|
country: one(countries, {
|
||||||
fields: [wines.countryId],
|
fields: [wines.countryId],
|
||||||
references: [countries.id],
|
references: [countries.id],
|
||||||
})
|
}),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export const subRegions = createTable(
|
export const subRegions = createTable("subRegion", {
|
||||||
"subRegion",
|
|
||||||
{
|
|
||||||
id: uuid("id").primaryKey().notNull().defaultRandom(),
|
id: uuid("id").primaryKey().notNull().defaultRandom(),
|
||||||
name: text("name").notNull().unique(),
|
name: text("name").notNull().unique(),
|
||||||
regionId: uuid("regionId").notNull(),
|
regionId: uuid("regionId").notNull(),
|
||||||
},
|
});
|
||||||
);
|
|
||||||
|
|
||||||
export const subRegionsRelations = relations(subRegions, ({ many, one }) => ({
|
export const subRegionsRelations = relations(subRegions, ({ many, one }) => ({
|
||||||
wines: many(wines),
|
wines: many(wines),
|
||||||
region: one(regions, {
|
region: one(regions, {
|
||||||
fields: [subRegions.regionId],
|
fields: [subRegions.regionId],
|
||||||
references: [regions.id]
|
references: [regions.id],
|
||||||
})
|
}),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export const regions = createTable(
|
export const regions = createTable("region", {
|
||||||
"region",
|
|
||||||
{
|
|
||||||
id: uuid("id").primaryKey().notNull().defaultRandom(),
|
id: uuid("id").primaryKey().notNull().defaultRandom(),
|
||||||
name: text("name").notNull().unique(),
|
name: text("name").notNull().unique(),
|
||||||
countryId: uuid("countryId").notNull(),
|
countryId: uuid("countryId").notNull(),
|
||||||
},
|
});
|
||||||
);
|
|
||||||
|
|
||||||
export const regionsRelations = relations(regions, ({ many, one }) => ({
|
export const regionsRelations = relations(regions, ({ many, one }) => ({
|
||||||
wines: many(wines),
|
wines: many(wines),
|
||||||
subRegions: many(subRegions),
|
subRegions: many(subRegions),
|
||||||
country: one(countries, {
|
country: one(countries, {
|
||||||
fields: [regions.countryId],
|
fields: [regions.countryId],
|
||||||
references: [countries.id]
|
references: [countries.id],
|
||||||
})
|
}),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export const countries = createTable(
|
export const countries = createTable("country", {
|
||||||
"country",
|
|
||||||
{
|
|
||||||
id: uuid("id").primaryKey().notNull().defaultRandom(),
|
id: uuid("id").primaryKey().notNull().defaultRandom(),
|
||||||
name: text("name").notNull(),
|
name: text("name").notNull().unique(),
|
||||||
},
|
});
|
||||||
);
|
|
||||||
|
|
||||||
export const countriesRelations = relations(countries, ({ many }) => ({
|
export const countriesRelations = relations(countries, ({ many }) => ({
|
||||||
wines: many(wines),
|
wines: many(wines),
|
||||||
regions: many(regions)
|
regions: many(regions),
|
||||||
}));
|
}));
|
||||||
|
Loading…
Reference in New Issue
Block a user