Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Supabase migration #13

Merged
merged 4 commits into from
Sep 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions api/recipe.api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
const env = process.env.DOMAIN

export const postRecipeURL = `${env}/rest/v1/recipe`
export const postInstructionURL = `${env}/rest/v1/instruction`
export const postIngredientsURL = `${env}/rest/v1/ingredient`
129 changes: 129 additions & 0 deletions components/ui/toast.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
"use client"

import * as React from "react"
import * as ToastPrimitives from "@radix-ui/react-toast"
import { cva, type VariantProps } from "class-variance-authority"
import { X } from "lucide-react"

import { cn } from "@/lib/utils"

const ToastProvider = ToastPrimitives.Provider

const ToastViewport = React.forwardRef<
React.ElementRef<typeof ToastPrimitives.Viewport>,
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Viewport>
>(({ className, ...props }, ref) => (
<ToastPrimitives.Viewport
ref={ref}
className={cn(
"fixed top-0 z-[100] flex max-h-screen w-full flex-col-reverse p-4 sm:bottom-0 sm:right-0 sm:top-auto sm:flex-col md:max-w-[420px]",
className
)}
{...props}
/>
))
ToastViewport.displayName = ToastPrimitives.Viewport.displayName

const toastVariants = cva(
"group pointer-events-auto relative flex w-full items-center justify-between space-x-4 overflow-hidden rounded-md border p-6 pr-8 shadow-lg transition-all data-[swipe=cancel]:translate-x-0 data-[swipe=end]:translate-x-[var(--radix-toast-swipe-end-x)] data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)] data-[swipe=move]:transition-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[swipe=end]:animate-out data-[state=closed]:fade-out-80 data-[state=closed]:slide-out-to-right-full data-[state=open]:slide-in-from-top-full data-[state=open]:sm:slide-in-from-bottom-full",
{
variants: {
variant: {
default: "border bg-background text-foreground",
destructive:
"destructive group border-destructive bg-destructive text-destructive-foreground",
},
},
defaultVariants: {
variant: "default",
},
}
)

const Toast = React.forwardRef<
React.ElementRef<typeof ToastPrimitives.Root>,
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Root> &
VariantProps<typeof toastVariants>
>(({ className, variant, ...props }, ref) => {
return (
<ToastPrimitives.Root
ref={ref}
className={cn(toastVariants({ variant }), className)}
{...props}
/>
)
})
Toast.displayName = ToastPrimitives.Root.displayName

const ToastAction = React.forwardRef<
React.ElementRef<typeof ToastPrimitives.Action>,
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Action>
>(({ className, ...props }, ref) => (
<ToastPrimitives.Action
ref={ref}
className={cn(
"inline-flex h-8 shrink-0 items-center justify-center rounded-md border bg-transparent px-3 text-sm font-medium ring-offset-background transition-colors hover:bg-secondary focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 group-[.destructive]:border-muted/40 group-[.destructive]:hover:border-destructive/30 group-[.destructive]:hover:bg-destructive group-[.destructive]:hover:text-destructive-foreground group-[.destructive]:focus:ring-destructive",
className
)}
{...props}
/>
))
ToastAction.displayName = ToastPrimitives.Action.displayName

const ToastClose = React.forwardRef<
React.ElementRef<typeof ToastPrimitives.Close>,
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Close>
>(({ className, ...props }, ref) => (
<ToastPrimitives.Close
ref={ref}
className={cn(
"absolute right-2 top-2 rounded-md p-1 text-foreground/50 opacity-0 transition-opacity hover:text-foreground focus:opacity-100 focus:outline-none focus:ring-2 group-hover:opacity-100 group-[.destructive]:text-red-300 group-[.destructive]:hover:text-red-50 group-[.destructive]:focus:ring-red-400 group-[.destructive]:focus:ring-offset-red-600",
className
)}
toast-close=""
{...props}
>
<X className="h-4 w-4" />
</ToastPrimitives.Close>
))
ToastClose.displayName = ToastPrimitives.Close.displayName

const ToastTitle = React.forwardRef<
React.ElementRef<typeof ToastPrimitives.Title>,
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Title>
>(({ className, ...props }, ref) => (
<ToastPrimitives.Title
ref={ref}
className={cn("text-sm font-semibold", className)}
{...props}
/>
))
ToastTitle.displayName = ToastPrimitives.Title.displayName

const ToastDescription = React.forwardRef<
React.ElementRef<typeof ToastPrimitives.Description>,
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Description>
>(({ className, ...props }, ref) => (
<ToastPrimitives.Description
ref={ref}
className={cn("text-sm opacity-90", className)}
{...props}
/>
))
ToastDescription.displayName = ToastPrimitives.Description.displayName

type ToastProps = React.ComponentPropsWithoutRef<typeof Toast>

type ToastActionElement = React.ReactElement<typeof ToastAction>

export {
type ToastProps,
type ToastActionElement,
ToastProvider,
ToastViewport,
Toast,
ToastTitle,
ToastDescription,
ToastClose,
ToastAction,
}
35 changes: 35 additions & 0 deletions components/ui/toaster.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
"use client"

import { useToast } from "@/components/hooks/use-toast"
import {
Toast,
ToastClose,
ToastDescription,
ToastProvider,
ToastTitle,
ToastViewport,
} from "@/components/ui/toast"

export function Toaster() {
const { toasts } = useToast()

return (
<ToastProvider>
{toasts.map(function ({ id, title, description, action, ...props }) {
return (
<Toast key={id} {...props}>
<div className="grid gap-1">
{title && <ToastTitle>{title}</ToastTitle>}
{description && (
<ToastDescription>{description}</ToastDescription>
)}
</div>
{action}
<ToastClose />
</Toast>
)
})}
<ToastViewport />
</ToastProvider>
)
}
143 changes: 79 additions & 64 deletions databaseDiagram.dbml
Original file line number Diff line number Diff line change
@@ -1,71 +1,86 @@
Table User {
id UUID [pk, unique, not null]
username String [not null, unique]
email String [not null, unique]
password String [not null]
created_at Timestamp [not null, default: `now()`]
updated_at Timestamp [not null, default: `now()`]
}
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";

Table Recipe {
id UUID [pk, unique, not null]
title String [not null]
description Text
servings Integer [not null]
prep_time Integer [not null] // in minutes
cook_time Integer [not null] // in minutes
main_img String [not null] // URL or path to the main image
main_img_alt String // Alt text for the main image
created_at Timestamp [not null, default: `now()`]
updated_at Timestamp [not null, default: `now()`]
user_id UUID [not null, ref: > User.id]
category_id UUID [not null, ref: > Category.id] // References a category (can be main or sub)
}
CREATE TABLE
public.category (
id UUID NOT NULL DEFAULT uuid_generate_v4 () PRIMARY KEY,
NAME TEXT NOT NULL UNIQUE,
description TEXT,
parent_id UUID REFERENCES public.category (id) ON DELETE SET NULL,
created_at TIMESTAMP WITHOUT TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITHOUT TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
);

Table Category {
id UUID [pk, unique, not null]
name String [not null, unique]
description Text
parent_id UUID [ref: > Category.id] // Self-referential foreign key for subcategories
created_at Timestamp [not null, default: `now()`]
updated_at Timestamp [not null, default: `now()`]
}
CREATE TABLE
public.user (
id UUID NOT NULL DEFAULT uuid_generate_v4 () PRIMARY KEY,
username TEXT NOT NULL UNIQUE,
email TEXT NOT NULL UNIQUE,
PASSWORD TEXT NOT NULL,
created_at TIMESTAMP WITHOUT TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITHOUT TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
);

Table Ingredient {
id UUID [pk, unique, not null]
name String [not null]
quantity String [not null] // e.g., "1 cup", "2 tbsp"
recipe_id UUID [not null, ref: > Recipe.id]
}
CREATE TABLE
public.recipe (
id UUID NOT NULL DEFAULT uuid_generate_v4 () PRIMARY KEY,
NAME TEXT NOT NULL,
description TEXT,
preview TEXT,
servings INTEGER NOT NULL,
prep_time TEXT NOT NULL,
cook_time TEXT NOT NULL,
main_img TEXT NOT NULL,
main_img_alt TEXT,
created_at TIMESTAMP WITHOUT TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITHOUT TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
user_id UUID NOT NULL REFERENCES public.user (id),
category_id UUID NOT NULL REFERENCES public.category (id)
);

Table RecipeImage {
id UUID [pk, unique, not null]
image_url String [not null] // URL or path to the image
alt_text String // Alt text for the image
recipe_id UUID [not null, ref: > Recipe.id]
}
CREATE TABLE
public.recipeimage (
id UUID NOT NULL DEFAULT uuid_generate_v4 () PRIMARY KEY,
image_url TEXT NOT NULL,
alt_text TEXT,
recipe_id UUID NOT NULL REFERENCES public.recipe (id) ON DELETE CASCADE
);

Table Instruction {
id UUID [pk, unique, not null]
step_number Integer [not null]
description Text [not null]
image_id UUID [ref: > RecipeImage.id] // Optional image for this step
recipe_id UUID [not null, ref: > Recipe.id]
}
CREATE TABLE
public.ingredient (
id UUID NOT NULL DEFAULT uuid_generate_v4 () PRIMARY KEY,
NAME TEXT NOT NULL,
quantity TEXT NOT NULL,
recipe_id UUID NOT NULL REFERENCES public.recipe (id) ON DELETE CASCADE
);

Table Like {
id UUID [pk, unique, not null]
user_id UUID [not null, ref: > User.id]
recipe_id UUID [not null, ref: > Recipe.id]
created_at Timestamp [not null, default: `now()`]
}
CREATE TABLE
public.instruction (
id UUID NOT NULL DEFAULT uuid_generate_v4 () PRIMARY KEY,
step_number INTEGER NOT NULL,
description TEXT NOT NULL,
image_id UUID REFERENCES public.recipeimage (id) ON DELETE SET NULL,
recipe_id UUID NOT NULL REFERENCES public.recipe (id) ON DELETE CASCADE
);

Table Review {
id UUID [pk, unique, not null]
user_id UUID [not null, ref: > User.id]
recipe_id UUID [not null, ref: > Recipe.id]
rating Integer [not null] // Star rating out of 5
review_text Text // Actual review text
created_at Timestamp [not null, default: `now()`]
updated_at Timestamp [not null, default: `now()`]
}
CREATE TABLE
public.like (
id UUID NOT NULL DEFAULT uuid_generate_v4 () PRIMARY KEY,
user_id UUID NOT NULL REFERENCES public.user (id),
recipe_id UUID NOT NULL REFERENCES public.recipe (id),
created_at TIMESTAMP WITHOUT TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
UNIQUE (user_id, recipe_id)
);

CREATE TABLE
public.review (
id UUID NOT NULL DEFAULT uuid_generate_v4 () PRIMARY KEY,
user_id UUID NOT NULL REFERENCES public.user (id),
recipe_id UUID NOT NULL REFERENCES public.recipe (id),
rating INTEGER NOT NULL CHECK (
rating >= 1
AND rating <= 5
),
review_text TEXT,
created_at TIMESTAMP WITHOUT TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITHOUT TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
);
11 changes: 0 additions & 11 deletions db/createPool.db.tsx

This file was deleted.

Loading