diff --git a/api/recipe.api.ts b/api/recipe.api.ts new file mode 100644 index 0000000..bb8eba1 --- /dev/null +++ b/api/recipe.api.ts @@ -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` diff --git a/components/ui/toast.tsx b/components/ui/toast.tsx new file mode 100644 index 0000000..521b94b --- /dev/null +++ b/components/ui/toast.tsx @@ -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, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +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, + React.ComponentPropsWithoutRef & + VariantProps +>(({ className, variant, ...props }, ref) => { + return ( + + ) +}) +Toast.displayName = ToastPrimitives.Root.displayName + +const ToastAction = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +ToastAction.displayName = ToastPrimitives.Action.displayName + +const ToastClose = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + + + +)) +ToastClose.displayName = ToastPrimitives.Close.displayName + +const ToastTitle = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +ToastTitle.displayName = ToastPrimitives.Title.displayName + +const ToastDescription = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +ToastDescription.displayName = ToastPrimitives.Description.displayName + +type ToastProps = React.ComponentPropsWithoutRef + +type ToastActionElement = React.ReactElement + +export { + type ToastProps, + type ToastActionElement, + ToastProvider, + ToastViewport, + Toast, + ToastTitle, + ToastDescription, + ToastClose, + ToastAction, +} diff --git a/components/ui/toaster.tsx b/components/ui/toaster.tsx new file mode 100644 index 0000000..9773020 --- /dev/null +++ b/components/ui/toaster.tsx @@ -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 ( + + {toasts.map(function ({ id, title, description, action, ...props }) { + return ( + +
+ {title && {title}} + {description && ( + {description} + )} +
+ {action} + +
+ ) + })} + +
+ ) +} diff --git a/databaseDiagram.dbml b/databaseDiagram.dbml index 987242f..1d80491 100644 --- a/databaseDiagram.dbml +++ b/databaseDiagram.dbml @@ -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 + ); \ No newline at end of file diff --git a/db/createPool.db.tsx b/db/createPool.db.tsx deleted file mode 100644 index bfcc918..0000000 --- a/db/createPool.db.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import { Pool } from 'pg' - -const pool = new Pool({ - user: process.env.POSTGRES_USER, - password: process.env.POSTGRES_PASSWORD, - database: process.env.POSTGRES_DB, - host: 'localhost', - port: 5432, -}) - -export default pool diff --git a/db/createRecipe.db.ts b/db/createRecipe.db.ts deleted file mode 100644 index 9f6b144..0000000 --- a/db/createRecipe.db.ts +++ /dev/null @@ -1,68 +0,0 @@ -export const mainCategoryQueryBuilder = (mainCateg: string, description?: string) => { - // INSERT INTO Category (name, description, created_at, updated_at) - // VALUES ('Desserts', 'Sweet treats and baked goods', NOW(), NOW()); - const query = `INSERT INTO rs.Category (name,description) values (${mainCateg},${description});` - return query -} - -export const subCategoryQueryBuilder = (subCateg: string, parentId: string, description?: string) => { - // INSERT INTO Category (name, description, created_at, updated_at) - // VALUES ('Desserts', 'Sweet treats and baked goods', NOW(), NOW()); - if (!description) { - description = 'No description provided' - } - const query = `INSERT INTO rs.Category (name,description,parent_id) values (${subCateg},${description},${parentId})` - return query -} - -export const createNewRecipeQueryBuilder = () => { - return `INSERT INTO rs.Recipe (name, description,preview, servings, prep_time, cook_time, main_img, main_img_alt, user_id, category_id) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10) RETURNING id` -} - -export const ingridientsQueryBuilder = (valueString: string) => { - // INSERT INTO Ingredient (name, quantity, recipe_id) - // VALUES - // ('Cream Cheese', '2 cups', (SELECT id FROM Recipe WHERE title = 'Cheesecake')), - // ('Sugar', '1 cup', (SELECT id FROM Recipe WHERE title = 'Cheesecake')), - - const query = `INSERT INTO rs.Ingredient (name,quantity,recipe_id) VALUES ${valueString}` - return query -} - -export const instructionQueryBuilder = (valueString: string) => { - //INSERT INTO Instruction (step_number, description, recipe_id) - // VALUES - // (1, 'Preheat the oven to 350°F (175°C).', (SELECT id FROM Recipe WHERE title = 'Cheesecake')), - // (2, 'Mix the cream cheese and sugar until smooth.', (SELECT id FROM Recipe WHERE title = 'Cheesecake')), - const query = `INSERT INTO rs.Instruction (step_number, description, recipe_id) VALUES ${valueString}` - console.log('hello i am your query', query) - return query -} - -export const getRecipeByIdQuery = (recipeId: string) => { - return `SELECT * from rs.Recipe where id=${recipeId}` -} - -export const getRecipeByNameQuery = (recipeName: string) => { - return `SELCT * from rs.Recipe where name like '%${recipeName}%` -} - -/* -INSERT INTO Like (user_id, recipe_id, created_at) -VALUES ( - (SELECT id FROM User WHERE username = 'john_doe'), - (SELECT id FROM Recipe WHERE title = 'Cheesecake'), - NOW() - ); - - -- Inserting into Review - INSERT INTO Review (user_id, recipe_id, rating, review_text, created_at, updated_at) - VALUES ( - (SELECT id FROM User WHERE username = 'john_doe'), - (SELECT id FROM Recipe WHERE title = 'Cheesecake'), - 5, - 'This is the best cheesecake I have ever had!', - NOW(), - NOW() -); -*/ diff --git a/db/createTable.query.tsx b/db/createTable.query.tsx deleted file mode 100644 index 8c803be..0000000 --- a/db/createTable.query.tsx +++ /dev/null @@ -1,73 +0,0 @@ -export const createTableQuery = [ - `CREATE SCHEMA rs;`, - `CREATE EXTENSION IF NOT EXISTS "uuid-ossp";`, - `CREATE TABLE IF NOT EXISTS rs.User ( - id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), - username VARCHAR(255) NOT NULL UNIQUE, - email VARCHAR(255) NOT NULL UNIQUE, - password TEXT NOT NULL, - created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP -);`, - `CREATE TABLE IF NOT EXISTS rs.Category ( - id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), - name VARCHAR(255) NOT NULL UNIQUE, - description TEXT, - parent_id UUID REFERENCES rs.Category(id) ON DELETE SET NULL, - created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP -);`, - `CREATE TABLE IF NOT EXISTS rs.Recipe ( - id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), - name VARCHAR(255) NOT NULL, - description TEXT, - preview TEXT, - servings INTEGER NOT NULL, - prep_time INTEGER NOT NULL, - cook_time INTEGER NOT NULL, - main_img TEXT NOT NULL, - main_img_alt TEXT, - created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - user_id UUID NOT NULL REFERENCES rs.User(id), - category_id UUID NOT NULL REFERENCES rs.Category(id) -);`, - `CREATE TABLE IF NOT EXISTS rs.Ingredient ( - id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), - name VARCHAR(255) NOT NULL, - quantity VARCHAR(255) NOT NULL, - recipe_id UUID NOT NULL REFERENCES rs.Recipe(id) ON DELETE CASCADE -); -`, - `CREATE TABLE IF NOT EXISTS rs.RecipeImage ( - id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), - image_url TEXT NOT NULL, - alt_text TEXT, - recipe_id UUID NOT NULL REFERENCES rs.Recipe(id) ON DELETE CASCADE -);`, - `CREATE TABLE IF NOT EXISTS rs.Instruction ( - id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), - step_number INTEGER NOT NULL, - description TEXT NOT NULL, - image_id UUID REFERENCES rs.RecipeImage(id) ON DELETE SET NULL, - recipe_id UUID NOT NULL REFERENCES rs.Recipe(id) ON DELETE CASCADE -);`, - `CREATE TABLE IF NOT EXISTS rs.Like ( - id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), - user_id UUID NOT NULL REFERENCES rs.User(id), - recipe_id UUID NOT NULL REFERENCES rs.Recipe(id), - created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - UNIQUE (user_id, recipe_id) -);`, - ` -CREATE TABLE IF NOT EXISTS rs.Review ( - id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), - user_id UUID NOT NULL REFERENCES rs.User(id), - recipe_id UUID NOT NULL REFERENCES rs.Recipe(id), - rating INTEGER NOT NULL CHECK (rating >= 1 AND rating <= 5), - review_text TEXT, - created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP -); -`, -] diff --git a/db/dbFn/categoryFunctions.ts b/db/dbFn/categoryFunctions.ts index 2e8bb2c..04feb85 100644 --- a/db/dbFn/categoryFunctions.ts +++ b/db/dbFn/categoryFunctions.ts @@ -1,3 +1,3 @@ -export const getCategoryIdByName = (categoryName: string) => { - return '835f5b44-6d82-4312-9162-b5837d3b5d64' //hardcoded need to fix +export const getCategoryIdByName = async (categoryName: string) => { + return 'a0af3249-545c-4df9-a488-5279f444bf6f' //hardcoded need to fix } diff --git a/db/dbFn/imageFunctions.ts b/db/dbFn/imageFunctions.ts index 927ccf1..15e47aa 100644 --- a/db/dbFn/imageFunctions.ts +++ b/db/dbFn/imageFunctions.ts @@ -1,3 +1,3 @@ -export const getImageURL = (uploadedImage: string) => { +export const getImageURL = async (uploadedImage: string) => { return '/cheese.jpg' // hardcoded need to fix } diff --git a/db/dbFn/recipeFunction.ts b/db/dbFn/recipeFunction.ts index 0dc61cd..c434896 100644 --- a/db/dbFn/recipeFunction.ts +++ b/db/dbFn/recipeFunction.ts @@ -1,27 +1,20 @@ -import { RecipeSet, UserSet } from '@/types/database.types' -import pool from '../createPool.db' -import { createNewRecipeQueryBuilder } from '../createRecipe.db' -import { runQueryV2 } from '@/utils/runQuery' +import { postIngredientsURL, postInstructionURL } from '@/api/recipe.api' +import { RecipeSet } from '@/types/database.types' +import { makePostRequest } from '@/utils/HttpRequests' -export const extractRecifeInformation = ( - formData: FormData, - imgUrl: string = '/cheese.jpg', - categoryId: string = 'addOtherCategoryIdHere' -) => { - const recipeSet: RecipeSet = { +export const extractRecifeInformation = (formData: FormData) => { + const recipeSet: Partial = { name: formData.get('recipeName')?.toString()!, description: formData.get('imgDesc')?.toString()?.toString(), servings: +formData.get('servings')!, prep_time: +formData.get('prep_time')!, cook_time: +formData.get('cook_time')!, - main_img: imgUrl, main_img_alt: formData.get('mainImageAlt')?.toString(), - category_id: categoryId, } return recipeSet } -export const extractIngredientsInformation = (formData: FormData) => { +export const extractIngredientsInformation = (formData: FormData, recipeId: string) => { //extracting the required part const ingred = /_\d+$/ const tempIngredient: string[] = [] @@ -32,20 +25,24 @@ export const extractIngredientsInformation = (formData: FormData) => { }) //modifing the required part - const ingredientsSet: { ingredientName: string; measurementName: string; quantity: string }[] = [] + const ingredientsSet: { name: string; quantity: string; recipe_id: string }[] = [] for (let j = 0; j < tempIngredient.length; j = j + 3) { ingredientsSet.push({ - ingredientName: formData.get(tempIngredient[j]) as string, - measurementName: formData.get(tempIngredient[j + 1]) as string, - quantity: formData.get(tempIngredient[j + 2]) as string, + name: formData.get(tempIngredient[j])?.toString()!, + quantity: + formData + .get(tempIngredient[j + 2]) + ?.toString()! + .concat(formData.get(tempIngredient[j + 1])?.toString()!) ?? '', + recipe_id: recipeId, }) } return ingredientsSet } -export const extractInstructionInformation = (formData: FormData) => { +export const extractInstructionInformation = (formData: FormData, recipe_id: string) => { //extracting the required part - const instructionSet: { stepNo: number; stepDesc: string }[] = [] + const instructionSet: { step_number: number; description: string; recipe_id: string }[] = [] const instructRegex = /-\d+$/ const tempInstruction: string[] = [] Array.from(formData.keys()).map((key) => { @@ -56,61 +53,21 @@ export const extractInstructionInformation = (formData: FormData) => { //modifying the required part for (let j = 0; j < tempInstruction.length; j++) { - instructionSet.push({ stepNo: j, stepDesc: formData.get(tempInstruction[j]) as string }) + instructionSet.push({ + step_number: j, + description: formData.get(tempInstruction[j])?.toString() ?? '', + recipe_id: recipe_id, + }) } return instructionSet } -export const valueSetForIngredient = ( - ingredientsSet: ReturnType, - recipeId: string -) => { - //entiry to the database - // ('Cream Cheese', '2 cups', (SELECT id FROM Recipe WHERE title = 'Cheesecake')), - // ('Sugar', '1 cup', (SELECT id FROM Recipe WHERE title = 'Cheesecake')), - const valueSet: string[] = [] - ingredientsSet.map((i) => { - return valueSet.push(`('${i.ingredientName}','${i.quantity}${i.measurementName}','${recipeId}')`) - }) - return valueSet.toString() -} - -export const valueSetForInstruction = ( - instructionSet: ReturnType, - recipeId: string -) => { - // (1, 'Preheat the oven to 350°F (175°C).', (SELECT id FROM Recipe WHERE title = 'Cheesecake')), - // (2, 'Mix the cream cheese and sugar until smooth.', (SELECT id FROM Recipe WHERE title = 'Cheesecake') - const valueSet: string[] = [] - instructionSet.map((i) => { - return valueSet.push(`('${i.stepNo}','${i.stepDesc}','${recipeId}')`) - }) - return valueSet.toString() -} - -export const createNewRecipe = async ({ userInfo, recipeInfo }: { userInfo: UserSet; recipeInfo: RecipeSet }) => { - const { name, description, preview, servings, prep_time, cook_time, main_img, main_img_alt, category_id } = recipeInfo - const { userId } = userInfo - - const res = await runQueryV2<{ id: string }>(createNewRecipeQueryBuilder(), [ - name, - description ?? 'No description Provided', - preview ?? '', - servings, - prep_time, - cook_time, - main_img, - main_img_alt ?? 'Main image of the recipe', - userId, - category_id, - ]) - return res -} - -export const createIngredient = async (query: string) => { - await pool.query(query) +export const createIngredient1 = async (recipeid: string, formData: FormData) => { + const body = extractIngredientsInformation(formData, recipeid) + return await makePostRequest(postIngredientsURL, body) } -export const createInstruction = async (query: string) => { - await pool.query(query) +export const createInstruction1 = async (recipeid: string, formData: FormData) => { + const body = extractInstructionInformation(formData, recipeid) + return await makePostRequest(postInstructionURL, body) } diff --git a/db/dbFn/userFunctions.ts b/db/dbFn/userFunctions.ts index 65772a6..baae931 100644 --- a/db/dbFn/userFunctions.ts +++ b/db/dbFn/userFunctions.ts @@ -1,5 +1,3 @@ -export const getUserInfo = (id: string) => { - return { - userId: '9dccc09c-f566-4b98-bf1a-d4d86c9eae1b', //hardcoded Need to fix - } +export const getUserInfo = async () => { + return '01584e8b-2c72-4afa-a4a3-c73790fbaa61' //hardcoded Need to fix } diff --git a/docker-compose.yml b/docker-compose.yml deleted file mode 100644 index 6d95fee..0000000 --- a/docker-compose.yml +++ /dev/null @@ -1,15 +0,0 @@ -services: - db: - image: postgres:latest - container_name: recipeSiteContainer - environment: - POSTGRES_USER: ${POSTGRES_USER} - POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} - POSTGRES_DB: ${POSTGRES_DB} - volumes: - - postgres_data:/var/lib/postgresql/data - ports: - - '5432:5432' - -volumes: - postgres_data: diff --git a/hooks/use-toast.ts b/hooks/use-toast.ts new file mode 100644 index 0000000..02e111d --- /dev/null +++ b/hooks/use-toast.ts @@ -0,0 +1,194 @@ +"use client" + +// Inspired by react-hot-toast library +import * as React from "react" + +import type { + ToastActionElement, + ToastProps, +} from "@/components/ui/toast" + +const TOAST_LIMIT = 1 +const TOAST_REMOVE_DELAY = 1000000 + +type ToasterToast = ToastProps & { + id: string + title?: React.ReactNode + description?: React.ReactNode + action?: ToastActionElement +} + +const actionTypes = { + ADD_TOAST: "ADD_TOAST", + UPDATE_TOAST: "UPDATE_TOAST", + DISMISS_TOAST: "DISMISS_TOAST", + REMOVE_TOAST: "REMOVE_TOAST", +} as const + +let count = 0 + +function genId() { + count = (count + 1) % Number.MAX_SAFE_INTEGER + return count.toString() +} + +type ActionType = typeof actionTypes + +type Action = + | { + type: ActionType["ADD_TOAST"] + toast: ToasterToast + } + | { + type: ActionType["UPDATE_TOAST"] + toast: Partial + } + | { + type: ActionType["DISMISS_TOAST"] + toastId?: ToasterToast["id"] + } + | { + type: ActionType["REMOVE_TOAST"] + toastId?: ToasterToast["id"] + } + +interface State { + toasts: ToasterToast[] +} + +const toastTimeouts = new Map>() + +const addToRemoveQueue = (toastId: string) => { + if (toastTimeouts.has(toastId)) { + return + } + + const timeout = setTimeout(() => { + toastTimeouts.delete(toastId) + dispatch({ + type: "REMOVE_TOAST", + toastId: toastId, + }) + }, TOAST_REMOVE_DELAY) + + toastTimeouts.set(toastId, timeout) +} + +export const reducer = (state: State, action: Action): State => { + switch (action.type) { + case "ADD_TOAST": + return { + ...state, + toasts: [action.toast, ...state.toasts].slice(0, TOAST_LIMIT), + } + + case "UPDATE_TOAST": + return { + ...state, + toasts: state.toasts.map((t) => + t.id === action.toast.id ? { ...t, ...action.toast } : t + ), + } + + case "DISMISS_TOAST": { + const { toastId } = action + + // ! Side effects ! - This could be extracted into a dismissToast() action, + // but I'll keep it here for simplicity + if (toastId) { + addToRemoveQueue(toastId) + } else { + state.toasts.forEach((toast) => { + addToRemoveQueue(toast.id) + }) + } + + return { + ...state, + toasts: state.toasts.map((t) => + t.id === toastId || toastId === undefined + ? { + ...t, + open: false, + } + : t + ), + } + } + case "REMOVE_TOAST": + if (action.toastId === undefined) { + return { + ...state, + toasts: [], + } + } + return { + ...state, + toasts: state.toasts.filter((t) => t.id !== action.toastId), + } + } +} + +const listeners: Array<(state: State) => void> = [] + +let memoryState: State = { toasts: [] } + +function dispatch(action: Action) { + memoryState = reducer(memoryState, action) + listeners.forEach((listener) => { + listener(memoryState) + }) +} + +type Toast = Omit + +function toast({ ...props }: Toast) { + const id = genId() + + const update = (props: ToasterToast) => + dispatch({ + type: "UPDATE_TOAST", + toast: { ...props, id }, + }) + const dismiss = () => dispatch({ type: "DISMISS_TOAST", toastId: id }) + + dispatch({ + type: "ADD_TOAST", + toast: { + ...props, + id, + open: true, + onOpenChange: (open) => { + if (!open) dismiss() + }, + }, + }) + + return { + id: id, + dismiss, + update, + } +} + +function useToast() { + const [state, setState] = React.useState(memoryState) + + React.useEffect(() => { + listeners.push(setState) + return () => { + const index = listeners.indexOf(setState) + if (index > -1) { + listeners.splice(index, 1) + } + } + }, [state]) + + return { + ...state, + toast, + dismiss: (toastId?: string) => dispatch({ type: "DISMISS_TOAST", toastId }), + } +} + +export { useToast, toast } diff --git a/lib/actions/admin.actions.ts b/lib/actions/admin.actions.ts index 209eeb5..1547e85 100644 --- a/lib/actions/admin.actions.ts +++ b/lib/actions/admin.actions.ts @@ -1,56 +1,35 @@ 'use server' - -import { ingridientsQueryBuilder, instructionQueryBuilder } from '@/db/createRecipe.db' import { getCategoryIdByName } from '@/db/dbFn/categoryFunctions' import { getImageURL } from '@/db/dbFn/imageFunctions' -import { - createIngredient, - createInstruction, - createNewRecipe, - extractIngredientsInformation, - extractInstructionInformation, - extractRecifeInformation, - valueSetForIngredient, - valueSetForInstruction, -} from '@/db/dbFn/recipeFunction' import { getUserInfo } from '@/db/dbFn/userFunctions' -import { UserSet } from '@/types/database.types' +import { makePostRequest } from '@/utils/HttpRequests' import { errorlogger } from '@/utils/logger' -import { runQueryV2 } from '@/utils/runQuery' - -export const adminCustomQuery = async (formData: FormData) => { - try { - const response = await runQueryV2(formData.get('myQuery')?.toString()!) - if (response.status === 'fail') throw new Error(response.errorResponse) - console.log(JSON.stringify(response.queryResponse)) - } catch (e) { - console.error(e) - } -} +import { createIngredient1, createInstruction1, extractRecifeInformation } from '@/db/dbFn/recipeFunction' +import { postRecipeURL } from '@/api/recipe.api' export const addNewRecipeToDatabase = async (formData: FormData) => { try { - const userSet: UserSet = getUserInfo(`userIdGoesHere`) - - const categoryId = getCategoryIdByName(formData.get('subCategoryName')?.toString()!) - - const imgUrl = getImageURL(`imgFromFormDataGoesHere`) - - const recipeSet = extractRecifeInformation(formData, imgUrl, categoryId) - - const qRes = await createNewRecipe({ userInfo: userSet, recipeInfo: recipeSet }) - if (qRes.status === 'fail') throw new Error(qRes.errorResponse) - - const recipeId = qRes.queryResponse[0].id - console.log(recipeId) - - const ingredientsSet = extractIngredientsInformation(formData) - - createIngredient(ingridientsQueryBuilder(valueSetForIngredient(ingredientsSet, recipeId!))) - - const instructionSet = extractInstructionInformation(formData) - - createInstruction(instructionQueryBuilder(valueSetForInstruction(instructionSet, recipeId!))) + const [userid, categoryId, imgUrl, recipeSet] = await Promise.all([ + getUserInfo(), + getCategoryIdByName(formData.get('subCategoryName')?.toString()!), + getImageURL(`imgFromFormDataGoesHere`), + extractRecifeInformation(formData), + ]) + + const createRecipeSp = await makePostRequest(postRecipeURL, { + ...recipeSet, + main_img: imgUrl, + category_id: categoryId, + user_id: userid, + }) + + const recipeId = createRecipeSp[0].id + + if (recipeId) { + await Promise.all([createIngredient1(recipeId, formData), createInstruction1(recipeId, formData)]) + } else { + throw new Error('Recipe Id not found !!') + } } catch (e) { if (e instanceof Error) errorlogger(e) else console.error(e) diff --git a/package-lock.json b/package-lock.json index 3244815..ed5b3cd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,8 @@ "version": "0.1.0", "dependencies": { "@radix-ui/react-slot": "^1.1.0", + "@radix-ui/react-toast": "^1.2.1", + "@tanstack/react-query": "^5.56.2", "class-variance-authority": "^0.7.0", "clsx": "^2.1.1", "lucide-react": "^0.436.0", @@ -17,7 +19,8 @@ "react": "^18", "react-dom": "^18", "tailwind-merge": "^2.5.2", - "tailwindcss-animate": "^1.0.7" + "tailwindcss-animate": "^1.0.7", + "zustand": "^5.0.0-rc.2" }, "devDependencies": { "@types/node": "^20", @@ -407,6 +410,36 @@ "node": ">=14" } }, + "node_modules/@radix-ui/primitive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.0.tgz", + "integrity": "sha512-4Z8dn6Upk0qk4P74xBhZ6Hd/w0mPEzOOLxy4xiPXOXqjF7jZS0VAKk7/x/H6FyY2zCkYJqePf1G5KmkmNJ4RBA==" + }, + "node_modules/@radix-ui/react-collection": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.0.tgz", + "integrity": "sha512-GZsZslMJEyo1VKm5L1ZJY8tGDxZNPAoUeQUIbKeJfoi7Q4kmig5AsgLMYYuyYbfjd8fBmFORAIwYAkXMnXZgZw==", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-slot": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-compose-refs": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.0.tgz", @@ -421,6 +454,114 @@ } } }, + "node_modules/@radix-ui/react-context": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.0.tgz", + "integrity": "sha512-OKrckBy+sMEgYM/sMmqmErVn0kZqrHPJze+Ql3DzYsDDp0hl0L62nx/2122/Bvps1qz645jlcu2tD9lrRSdf8A==", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dismissable-layer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.0.tgz", + "integrity": "sha512-/UovfmmXGptwGcBQawLzvn2jOfM0t4z3/uKffoBlj724+n3FvBbZ7M0aaBOmkp6pqFYpO4yx8tSVJjx3Fl2jig==", + "dependencies": { + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-callback-ref": "1.1.0", + "@radix-ui/react-use-escape-keydown": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-portal": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.1.tgz", + "integrity": "sha512-A3UtLk85UtqhzFqtoC8Q0KvR2GbXF3mtPgACSazajqq6A41mEQgo53iPzY4i6BwDxlIFqWIhiQ2G729n+2aw/g==", + "dependencies": { + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-layout-effect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-presence": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.0.tgz", + "integrity": "sha512-Gq6wuRN/asf9H/E/VzdKoUtT8GC9PQc9z40/vEr0VCJ4u5XvvhWIrSsCB6vD2/cH7ugTdSfYq9fLJCcM00acrQ==", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-use-layout-effect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-primitive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.0.tgz", + "integrity": "sha512-ZSpFm0/uHa8zTvKBDjLFWLo8dkr4MBsiDLz0g3gMUwqgLHz9rTaRRGYDgvZPtBJgYCBKXkS9fzmoySgr8CO6Cw==", + "dependencies": { + "@radix-ui/react-slot": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-slot": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.0.tgz", @@ -438,6 +579,123 @@ } } }, + "node_modules/@radix-ui/react-toast": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-toast/-/react-toast-1.2.1.tgz", + "integrity": "sha512-5trl7piMXcZiCq7MW6r8YYmu0bK5qDpTWz+FdEPdKyft2UixkspheYbjbrLXVN5NGKHFbOP7lm8eD0biiSqZqg==", + "dependencies": { + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-collection": "1.1.0", + "@radix-ui/react-compose-refs": "1.1.0", + "@radix-ui/react-context": "1.1.0", + "@radix-ui/react-dismissable-layer": "1.1.0", + "@radix-ui/react-portal": "1.1.1", + "@radix-ui/react-presence": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-callback-ref": "1.1.0", + "@radix-ui/react-use-controllable-state": "1.1.0", + "@radix-ui/react-use-layout-effect": "1.1.0", + "@radix-ui/react-visually-hidden": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-callback-ref": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.0.tgz", + "integrity": "sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw==", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.1.0.tgz", + "integrity": "sha512-MtfMVJiSr2NjzS0Aa90NPTnvTSg6C/JLCV7ma0W6+OMV78vd8OyRpID+Ng9LxzsPbLeuBnWBA1Nq30AtBIDChw==", + "dependencies": { + "@radix-ui/react-use-callback-ref": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-escape-keydown": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.0.tgz", + "integrity": "sha512-L7vwWlR1kTTQ3oh7g1O0CBF3YCyyTj8NmhLR+phShpyA50HCfBFKVJTpshm9PzLiKmehsrQzTYTpX9HvmC9rhw==", + "dependencies": { + "@radix-ui/react-use-callback-ref": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.0.tgz", + "integrity": "sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w==", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-visually-hidden": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.1.0.tgz", + "integrity": "sha512-N8MDZqtgCgG5S3aV60INAB475osJousYpZ4cTJ2cFbMpdHS5Y6loLTH8LPtkj2QN0x93J30HT/M3qJXM0+lyeQ==", + "dependencies": { + "@radix-ui/react-primitive": "2.0.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@rushstack/eslint-patch": { "version": "1.10.4", "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.10.4.tgz", @@ -458,6 +716,30 @@ "tslib": "^2.4.0" } }, + "node_modules/@tanstack/query-core": { + "version": "5.56.2", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.56.2.tgz", + "integrity": "sha512-gor0RI3/R5rVV3gXfddh1MM+hgl0Z4G7tj6Xxpq6p2I03NGPaJ8dITY9Gz05zYYb/EJq9vPas/T4wn9EaDPd4Q==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/react-query": { + "version": "5.56.2", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.56.2.tgz", + "integrity": "sha512-SR0GzHVo6yzhN72pnRhkEFRAHMsUo5ZPzAxfTMvUxFIDVS6W9LYUp6nXW3fcHVdg0ZJl8opSH85jqahvm6DSVg==", + "dependencies": { + "@tanstack/query-core": "5.56.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^18 || ^19" + } + }, "node_modules/@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", @@ -561,7 +843,7 @@ "version": "18.3.0", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.0.tgz", "integrity": "sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==", - "dev": true, + "devOptional": true, "dependencies": { "@types/react": "*" } @@ -3578,47 +3860,11 @@ "node": ">=8" } }, - "node_modules/pg": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/pg/-/pg-8.12.0.tgz", - "integrity": "sha512-A+LHUSnwnxrnL/tZ+OLfqR1SxLN3c/pgDztZ47Rpbsd4jUytsTtwQo/TLPRzPJMp/1pbhYVhH9cuSZLAajNfjQ==", - "dependencies": { - "pg-connection-string": "^2.6.4", - "pg-pool": "^3.6.2", - "pg-protocol": "^1.6.1", - "pg-types": "^2.1.0", - "pgpass": "1.x" - }, - "engines": { - "node": ">= 8.0.0" - }, - "optionalDependencies": { - "pg-cloudflare": "^1.1.1" - }, - "peerDependencies": { - "pg-native": ">=3.0.1" - }, - "peerDependenciesMeta": { - "pg-native": { - "optional": true - } - } - }, - "node_modules/pg-cloudflare": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.1.1.tgz", - "integrity": "sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==", - "optional": true - }, - "node_modules/pg-connection-string": { - "version": "2.6.4", - "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.6.4.tgz", - "integrity": "sha512-v+Z7W/0EO707aNMaAEfiGnGL9sxxumwLl2fJvCQtMn9Fxsg+lPpPkdcyBSv/KFgpGdYkMfn+EI1Or2EHjpgLCA==" - }, "node_modules/pg-int8": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", + "dev": true, "engines": { "node": ">=4.0.0" } @@ -3632,41 +3878,11 @@ "node": ">=4" } }, - "node_modules/pg-pool": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.6.2.tgz", - "integrity": "sha512-Htjbg8BlwXqSBQ9V8Vjtc+vzf/6fVUuak/3/XXKA9oxZprwW3IMDQTGHP+KDmVL7rtd+R1QjbnCFPuTHm3G4hg==", - "peerDependencies": { - "pg": ">=8.0" - } - }, "node_modules/pg-protocol": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.6.1.tgz", - "integrity": "sha512-jPIlvgoD63hrEuihvIg+tJhoGjUsLPn6poJY9N5CnlPd91c2T18T/9zBtLxZSb1EhYxBRoZJtzScCaWlYLtktg==" - }, - "node_modules/pg-types": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", - "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", - "dependencies": { - "pg-int8": "1.0.1", - "postgres-array": "~2.0.0", - "postgres-bytea": "~1.0.0", - "postgres-date": "~1.0.4", - "postgres-interval": "^1.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/pgpass": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", - "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", - "dependencies": { - "split2": "^4.1.0" - } + "integrity": "sha512-jPIlvgoD63hrEuihvIg+tJhoGjUsLPn6poJY9N5CnlPd91c2T18T/9zBtLxZSb1EhYxBRoZJtzScCaWlYLtktg==", + "dev": true }, "node_modules/picocolors": { "version": "1.0.1", @@ -3856,41 +4072,6 @@ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" }, - "node_modules/postgres-array": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", - "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", - "engines": { - "node": ">=4" - } - }, - "node_modules/postgres-bytea": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", - "integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postgres-date": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", - "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postgres-interval": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", - "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", - "dependencies": { - "xtend": "^4.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/postgres-range": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/postgres-range/-/postgres-range-1.1.4.tgz", @@ -4286,14 +4467,6 @@ "node": ">=0.10.0" } }, - "node_modules/split2": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", - "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", - "engines": { - "node": ">= 10.x" - } - }, "node_modules/stop-iteration-iterator": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", @@ -5052,14 +5225,6 @@ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "dev": true }, - "node_modules/xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "engines": { - "node": ">=0.4" - } - }, "node_modules/yaml": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.5.0.tgz", @@ -5082,6 +5247,34 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/zustand": { + "version": "5.0.0-rc.2", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.0-rc.2.tgz", + "integrity": "sha512-o2Nwuvnk8vQBX7CcHL8WfFkZNJdxB/VKeWw0tNglw8p4cypsZ3tRT7rTRTDNeUPFS0qaMBRSKe+fVwL5xpcE3A==", + "engines": { + "node": ">=12.20.0" + }, + "peerDependencies": { + "@types/react": ">=18.0.0", + "immer": ">=9.0.6", + "react": ">=18.0.0", + "use-sync-external-store": ">=1.2.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "immer": { + "optional": true + }, + "react": { + "optional": true + }, + "use-sync-external-store": { + "optional": true + } + } } } } diff --git a/package.json b/package.json index b9c639a..7d1bc02 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,8 @@ }, "dependencies": { "@radix-ui/react-slot": "^1.1.0", + "@radix-ui/react-toast": "^1.2.1", + "@tanstack/react-query": "^5.56.2", "class-variance-authority": "^0.7.0", "clsx": "^2.1.1", "lucide-react": "^0.436.0", @@ -21,7 +23,8 @@ "react": "^18", "react-dom": "^18", "tailwind-merge": "^2.5.2", - "tailwindcss-animate": "^1.0.7" + "tailwindcss-animate": "^1.0.7", + "zustand": "^5.0.0-rc.2" }, "devDependencies": { "@types/node": "^20", diff --git a/utils/HttpRequests.ts b/utils/HttpRequests.ts new file mode 100644 index 0000000..0c40450 --- /dev/null +++ b/utils/HttpRequests.ts @@ -0,0 +1,22 @@ +import { handleHTTPError } from './httpErrorHandler.utils' + +export const makePostRequest = async (URL: string, body: any) => { + try { + const pRes = await fetch(`${URL}`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + apikey: process.env.SUPABASE_ANON_KEY ?? '', + Prefer: 'return=representation', + }, + body: JSON.stringify(body), + }) + if (!pRes.ok) throw new Error(JSON.stringify(handleHTTPError(pRes))) + const data = pRes.json() + return await data + } catch (error) { + if (error instanceof Error) { + throw new Error(error.message) + } + } +} diff --git a/utils/httpErrorHandler.utils.ts b/utils/httpErrorHandler.utils.ts new file mode 100644 index 0000000..57e2333 --- /dev/null +++ b/utils/httpErrorHandler.utils.ts @@ -0,0 +1,11 @@ +const createResponse = (code: number, message: string) => { + return { + code: code, + message: message, + } +} + +export const handleHTTPError = (res: Response) => { + console.log(res) + return createResponse(0, '') +} diff --git a/utils/runQuery.ts b/utils/runQuery.ts index cbe6a16..e101172 100644 --- a/utils/runQuery.ts +++ b/utils/runQuery.ts @@ -1,41 +1,41 @@ -import pool from '@/db/createPool.db' -import { createTimeout } from './useTimeout' -import { errorlogger } from './logger' -import { RunQueryParam, RunQueryResponse } from '@/types/actions.types' +// // import pool from '@/db/createPool.db' +// import { createTimeout } from './useTimeout' +// import { errorlogger } from './logger' +// import { RunQueryParam, RunQueryResponse } from '@/types/actions.types' -export const runQueryV2 = async (query: string, param?: RunQueryParam[]): Promise> => { - try { - const queryResponse: T[] = await createTimeout(async () => { - return (await pool.query(query, param)).rows - }) - return { - status: 'success', - queryResponse: queryResponse, - } - } catch (error) { - if (error instanceof AggregateError) { - if (error.errors[0]?.code === 'ECONNREFUSED') { - return { - status: 'fail', - errorResponse: 'Error connecting to the database', - } - } - errorlogger(error) - return { - status: 'fail', - errorResponse: 'Multiple Error occurred !!', - } - } else if (error instanceof Error) { - return { - status: 'fail', - errorResponse: error.message, - } - } else { - console.log(error) - return { - status: 'fail', - errorResponse: 'Unknown Error', - } - } - } -} +// export const runQueryV2 = async (query: string, param?: RunQueryParam[]): Promise> => { +// try { +// const queryResponse: T[] = await createTimeout(async () => { +// return (await pool.query(query, param)).rows +// }) +// return { +// status: 'success', +// queryResponse: queryResponse, +// } +// } catch (error) { +// if (error instanceof AggregateError) { +// if (error.errors[0]?.code === 'ECONNREFUSED') { +// return { +// status: 'fail', +// errorResponse: 'Error connecting to the database', +// } +// } +// errorlogger(error) +// return { +// status: 'fail', +// errorResponse: 'Multiple Error occurred !!', +// } +// } else if (error instanceof Error) { +// return { +// status: 'fail', +// errorResponse: error.message, +// } +// } else { +// console.log(error) +// return { +// status: 'fail', +// errorResponse: 'Unknown Error', +// } +// } +// } +// }