diff --git a/package.json b/package.json index 7d7ea3a..a1e67f1 100644 --- a/package.json +++ b/package.json @@ -1,61 +1,64 @@ { - "name": "ywc19-hackathon-h", - "version": "0.1.0", - "private": true, - "scripts": { - "build": "next build", - "dev": "next dev", - "postinstall": "prisma generate", - "lint": "next lint", - "start": "next start" - }, - "dependencies": { - "@next-auth/prisma-adapter": "^1.0.5", - "@prisma/client": "^4.14.0", - "@t3-oss/env-nextjs": "^0.3.1", - "@tanstack/react-query": "^4.29.7", - "@trpc/client": "^10.26.0", - "@trpc/next": "^10.26.0", - "@trpc/react-query": "^10.26.0", - "@trpc/server": "^10.26.0", - "flowbite": "^1.7.0", - "flowbite-react": "^0.4.11", - "framer-motion": "^10.12.21", - "next": "^13.4.2", - "next-auth": "^4.22.1", - "react": "18.2.0", - "react-dom": "18.2.0", - "react-lazy-load-image-component": "^1.6.0", - "superjson": "1.12.2", - "swiper": "^10.0.4", - "tailwind-merge": "^1.13.2", - "zod": "^3.21.4" - }, - "devDependencies": { - "@types/eslint": "^8.37.0", - "@types/node": "^18.16.0", - "@types/prettier": "^2.7.2", - "@types/react": "^18.2.6", - "@types/react-dom": "^18.2.4", - "@types/react-lazy-load-image-component": "^1.5.3", - "@typescript-eslint/eslint-plugin": "^5.59.6", - "@typescript-eslint/parser": "^5.59.6", - "autoprefixer": "^10.4.14", - "eslint": "^8.40.0", - "eslint-config-next": "^13.4.2", - "postcss": "^8.4.21", - "prettier": "^2.8.8", - "prettier-plugin-tailwindcss": "^0.2.8", - "prisma": "^4.14.0", - "prisma-zod-generator": "^0.8.13", - "tailwindcss": "^3.3.0", - "typescript": "^5.0.4" - }, - "ct3aMetadata": { - "initVersion": "7.15.0" - }, - "volta": { - "node": "16.20.1", - "yarn": "3.6.1" - } + "name": "ywc19-hackathon-h", + "version": "0.1.0", + "private": true, + "scripts": { + "build": "next build", + "dev": "next dev", + "postinstall": "prisma generate", + "lint": "next lint", + "start": "next start" + }, + "dependencies": { + "@next-auth/prisma-adapter": "^1.0.5", + "@prisma/client": "^4.14.0", + "@t3-oss/env-nextjs": "^0.3.1", + "@tanstack/react-query": "^4.29.7", + "@trpc/client": "^10.26.0", + "@trpc/next": "^10.26.0", + "@trpc/react-query": "^10.26.0", + "@trpc/server": "^10.26.0", + "flowbite": "^1.7.0", + "flowbite-react": "^0.4.11", + "framer-motion": "^10.12.21", + "next": "^13.4.2", + "next-auth": "^4.22.1", + "react": "18.2.0", + "react-dom": "18.2.0", + "react-lazy-load-image-component": "^1.6.0", + "superjson": "1.12.2", + "swiper": "^10.0.4", + "tailwind-merge": "^1.13.2", + "zod": "^3.21.4" + }, + "devDependencies": { + "@types/eslint": "^8.37.0", + "@types/node": "^18.16.0", + "@types/prettier": "^2.7.2", + "@types/react": "^18.2.6", + "@types/react-dom": "^18.2.4", + "@types/react-lazy-load-image-component": "^1.5.3", + "@typescript-eslint/eslint-plugin": "^5.59.6", + "@typescript-eslint/parser": "^5.59.6", + "autoprefixer": "^10.4.14", + "eslint": "^8.40.0", + "eslint-config-next": "^13.4.2", + "postcss": "^8.4.21", + "prettier": "^2.8.8", + "prettier-plugin-tailwindcss": "^0.2.8", + "prisma": "^4.14.0", + "prisma-zod-generator": "^0.8.13", + "tailwindcss": "^3.3.0", + "typescript": "^5.0.4" + }, + "ct3aMetadata": { + "initVersion": "7.15.0" + }, + "volta": { + "node": "16.20.1", + "yarn": "3.6.1" + }, + "prisma": { + "seed": "ts-node --compiler-options {\"module\":\"CommonJS\"} prisma/seed.ts" + } } diff --git a/prisma/migrations/20230715022448_dev/migration.sql b/prisma/migrations/20230715022448_dev/migration.sql deleted file mode 100644 index 8f88957..0000000 --- a/prisma/migrations/20230715022448_dev/migration.sql +++ /dev/null @@ -1,75 +0,0 @@ --- CreateTable -CREATE TABLE "Example" ( - "id" TEXT NOT NULL, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMP(3) NOT NULL, - - CONSTRAINT "Example_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "Account" ( - "id" TEXT NOT NULL, - "userId" TEXT NOT NULL, - "type" TEXT NOT NULL, - "provider" TEXT NOT NULL, - "providerAccountId" TEXT NOT NULL, - "refresh_token" TEXT, - "access_token" TEXT, - "expires_at" INTEGER, - "token_type" TEXT, - "scope" TEXT, - "id_token" TEXT, - "session_state" TEXT, - - CONSTRAINT "Account_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "Session" ( - "id" TEXT NOT NULL, - "sessionToken" TEXT NOT NULL, - "userId" TEXT NOT NULL, - "expires" TIMESTAMP(3) NOT NULL, - - CONSTRAINT "Session_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "User" ( - "id" TEXT NOT NULL, - "name" TEXT, - "email" TEXT, - "emailVerified" TIMESTAMP(3), - "image" TEXT, - - CONSTRAINT "User_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "VerificationToken" ( - "identifier" TEXT NOT NULL, - "token" TEXT NOT NULL, - "expires" TIMESTAMP(3) NOT NULL -); - --- CreateIndex -CREATE UNIQUE INDEX "Account_provider_providerAccountId_key" ON "Account"("provider", "providerAccountId"); - --- CreateIndex -CREATE UNIQUE INDEX "Session_sessionToken_key" ON "Session"("sessionToken"); - --- CreateIndex -CREATE UNIQUE INDEX "User_email_key" ON "User"("email"); - --- CreateIndex -CREATE UNIQUE INDEX "VerificationToken_token_key" ON "VerificationToken"("token"); - --- CreateIndex -CREATE UNIQUE INDEX "VerificationToken_identifier_token_key" ON "VerificationToken"("identifier", "token"); - --- AddForeignKey -ALTER TABLE "Account" ADD CONSTRAINT "Account_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "Session" ADD CONSTRAINT "Session_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/prisma/migrations/20230716025203_add/migration.sql b/prisma/migrations/20230716025203_add/migration.sql new file mode 100644 index 0000000..79b69ae --- /dev/null +++ b/prisma/migrations/20230716025203_add/migration.sql @@ -0,0 +1,148 @@ +-- CreateEnum +CREATE TYPE "BookingStatus" AS ENUM ('NOT_PAID', 'PAID'); + +-- CreateTable +CREATE TABLE "Example" ( + "id" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "Example_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Account" ( + "id" TEXT NOT NULL, + "userId" TEXT NOT NULL, + "type" TEXT NOT NULL, + "provider" TEXT NOT NULL, + "providerAccountId" TEXT NOT NULL, + "refresh_token" TEXT, + "access_token" TEXT, + "expires_at" INTEGER, + "token_type" TEXT, + "scope" TEXT, + "id_token" TEXT, + "session_state" TEXT, + + CONSTRAINT "Account_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Session" ( + "id" TEXT NOT NULL, + "sessionToken" TEXT NOT NULL, + "userId" TEXT NOT NULL, + "expires" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "Session_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "User" ( + "id" TEXT NOT NULL, + "name" TEXT, + "email" TEXT, + "emailVerified" TIMESTAMP(3), + "image" TEXT, + + CONSTRAINT "User_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "VerificationToken" ( + "identifier" TEXT NOT NULL, + "token" TEXT NOT NULL, + "expires" TIMESTAMP(3) NOT NULL +); + +-- CreateTable +CREATE TABLE "Booking" ( + "id" TEXT NOT NULL, + "userId" TEXT NOT NULL, + "menuId" TEXT NOT NULL, + "bookedTime" TIMESTAMP(3) NOT NULL, + "status" "BookingStatus" NOT NULL, + + CONSTRAINT "Booking_pkey" PRIMARY KEY ("userId","menuId","id") +); + +-- CreateTable +CREATE TABLE "Restaurant" ( + "id" TEXT NOT NULL, + "name" TEXT NOT NULL, + "description" TEXT NOT NULL, + "location" TEXT NOT NULL, + "imageUrl" TEXT, + "isRecommended" BOOLEAN NOT NULL, + + CONSTRAINT "Restaurant_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Menu" ( + "id" TEXT NOT NULL, + "restaurantId" TEXT, + "name" TEXT NOT NULL, + "price" INTEGER NOT NULL, + "isRecommended" BOOLEAN NOT NULL, + + CONSTRAINT "Menu_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Tag" ( + "id" TEXT NOT NULL, + "name" TEXT NOT NULL, + "icon" TEXT NOT NULL, + + CONSTRAINT "Tag_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "_MenuToTag" ( + "A" TEXT NOT NULL, + "B" TEXT NOT NULL +); + +-- CreateIndex +CREATE UNIQUE INDEX "Account_provider_providerAccountId_key" ON "Account"("provider", "providerAccountId"); + +-- CreateIndex +CREATE UNIQUE INDEX "Session_sessionToken_key" ON "Session"("sessionToken"); + +-- CreateIndex +CREATE UNIQUE INDEX "User_email_key" ON "User"("email"); + +-- CreateIndex +CREATE UNIQUE INDEX "VerificationToken_token_key" ON "VerificationToken"("token"); + +-- CreateIndex +CREATE UNIQUE INDEX "VerificationToken_identifier_token_key" ON "VerificationToken"("identifier", "token"); + +-- CreateIndex +CREATE UNIQUE INDEX "_MenuToTag_AB_unique" ON "_MenuToTag"("A", "B"); + +-- CreateIndex +CREATE INDEX "_MenuToTag_B_index" ON "_MenuToTag"("B"); + +-- AddForeignKey +ALTER TABLE "Account" ADD CONSTRAINT "Account_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Session" ADD CONSTRAINT "Session_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Booking" ADD CONSTRAINT "Booking_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Booking" ADD CONSTRAINT "Booking_menuId_fkey" FOREIGN KEY ("menuId") REFERENCES "Menu"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Menu" ADD CONSTRAINT "Menu_restaurantId_fkey" FOREIGN KEY ("restaurantId") REFERENCES "Restaurant"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "_MenuToTag" ADD CONSTRAINT "_MenuToTag_A_fkey" FOREIGN KEY ("A") REFERENCES "Menu"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "_MenuToTag" ADD CONSTRAINT "_MenuToTag_B_fkey" FOREIGN KEY ("B") REFERENCES "Tag"("id") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/prisma/migrations/20230716025230_make_default/migration.sql b/prisma/migrations/20230716025230_make_default/migration.sql new file mode 100644 index 0000000..add2cd0 --- /dev/null +++ b/prisma/migrations/20230716025230_make_default/migration.sql @@ -0,0 +1,5 @@ +-- AlterTable +ALTER TABLE "Menu" ALTER COLUMN "isRecommended" SET DEFAULT false; + +-- AlterTable +ALTER TABLE "Restaurant" ALTER COLUMN "isRecommended" SET DEFAULT false; diff --git a/prisma/migrations/20230716030605_edit_tag/migration.sql b/prisma/migrations/20230716030605_edit_tag/migration.sql new file mode 100644 index 0000000..52ca4de --- /dev/null +++ b/prisma/migrations/20230716030605_edit_tag/migration.sql @@ -0,0 +1,32 @@ +/* + Warnings: + + - You are about to drop the `_MenuToTag` table. If the table is not empty, all the data it contains will be lost. + +*/ +-- DropForeignKey +ALTER TABLE "_MenuToTag" DROP CONSTRAINT "_MenuToTag_A_fkey"; + +-- DropForeignKey +ALTER TABLE "_MenuToTag" DROP CONSTRAINT "_MenuToTag_B_fkey"; + +-- DropTable +DROP TABLE "_MenuToTag"; + +-- CreateTable +CREATE TABLE "_RestaurantToTag" ( + "A" TEXT NOT NULL, + "B" TEXT NOT NULL +); + +-- CreateIndex +CREATE UNIQUE INDEX "_RestaurantToTag_AB_unique" ON "_RestaurantToTag"("A", "B"); + +-- CreateIndex +CREATE INDEX "_RestaurantToTag_B_index" ON "_RestaurantToTag"("B"); + +-- AddForeignKey +ALTER TABLE "_RestaurantToTag" ADD CONSTRAINT "_RestaurantToTag_A_fkey" FOREIGN KEY ("A") REFERENCES "Restaurant"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "_RestaurantToTag" ADD CONSTRAINT "_RestaurantToTag_B_fkey" FOREIGN KEY ("B") REFERENCES "Tag"("id") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/prisma/migrations/20230716031152_rm_icon/migration.sql b/prisma/migrations/20230716031152_rm_icon/migration.sql new file mode 100644 index 0000000..4b12922 --- /dev/null +++ b/prisma/migrations/20230716031152_rm_icon/migration.sql @@ -0,0 +1,12 @@ +/* + Warnings: + + - You are about to drop the column `icon` on the `Tag` table. All the data in the column will be lost. + - A unique constraint covering the columns `[name]` on the table `Tag` will be added. If there are existing duplicate values, this will fail. + +*/ +-- AlterTable +ALTER TABLE "Tag" DROP COLUMN "icon"; + +-- CreateIndex +CREATE UNIQUE INDEX "Tag_name_key" ON "Tag"("name"); diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 96119ec..0029126 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -52,7 +52,7 @@ model User { image String? accounts Account[] sessions Session[] - Booking Booking[] + bookings Booking[] } model VerificationToken { @@ -64,16 +64,45 @@ model VerificationToken { } model Booking { - id String @default(cuid()) - userId String - user User @relation(fields: [userId], references: [id]) - restaurantId String - restaurant Restaurant @relation(fields: [restaurantId], references: [id]) + id String @default(cuid()) + userId String + user User @relation(fields: [userId], references: [id]) + menuId String + menu Menu @relation(fields: [menuId], references: [id]) + bookedTime DateTime + status BookingStatus - @@id([userId, restaurantId, id]) + @@id([userId, menuId, id]) } model Restaurant { - id String @id @default(cuid()) - Booking Booking[] + id String @id @default(cuid()) + name String + description String + location String + imageUrl String? + menus Menu[] + isRecommended Boolean @default(false) + tags Tag[] +} + +model Menu { + id String @id @default(cuid()) + restaurant Restaurant? @relation(fields: [restaurantId], references: [id]) + restaurantId String? + name String + price Int + booking Booking[] + isRecommended Boolean @default(false) +} + +model Tag { + id String @id @default(cuid()) + name String @unique + restaurants Restaurant[] +} + +enum BookingStatus { + NOT_PAID + PAID } diff --git a/prisma/seed.ts b/prisma/seed.ts new file mode 100644 index 0000000..615b0f9 --- /dev/null +++ b/prisma/seed.ts @@ -0,0 +1,44 @@ +import { type Prisma, PrismaClient } from '@prisma/client' + +const prisma = new PrismaClient() +async function main() { + + await prisma.tag.createMany({ + data: [ + { + id: 'well', + name: 'well_begin', + }, + { + id: 'water', + name: 'water_recycling', + }, + { + id: 'zero', + name: 'zero_waste', + }, + { + id: 'organic', + name: 'organic_ingredient', + }, + ] + }) + + for (let i = 0; i < 100; i++) { + await prisma.restaurant.create({ + data: { + name: `Restaurant ${i}`, + location: 'Bangkok', + imageUrl: 'https://picsum.photos/200', + description: 'Lorem ipsum dolor sit amet', + tags: { + connect: { + id: 'well' + } + } + } + }) + } +} + +void main() diff --git a/public/assets/badges/organic_ingredient.png b/public/assets/badges/organic_ingredient.png new file mode 100644 index 0000000..7307eb0 Binary files /dev/null and b/public/assets/badges/organic_ingredient.png differ diff --git a/public/assets/badges/water_recycling.png b/public/assets/badges/water_recycling.png new file mode 100644 index 0000000..89c0d0c Binary files /dev/null and b/public/assets/badges/water_recycling.png differ diff --git a/public/assets/badges/well_begin.png b/public/assets/badges/well_begin.png new file mode 100644 index 0000000..184a50f Binary files /dev/null and b/public/assets/badges/well_begin.png differ diff --git a/public/assets/badges/zero_waste.png b/public/assets/badges/zero_waste.png new file mode 100644 index 0000000..7a8a676 Binary files /dev/null and b/public/assets/badges/zero_waste.png differ diff --git a/src/components/CardRestaurant.tsx b/src/components/CardRestaurant.tsx index 39476ab..bd20473 100644 --- a/src/components/CardRestaurant.tsx +++ b/src/components/CardRestaurant.tsx @@ -1,30 +1,39 @@ -import React from "react"; +import React, { type FC } from "react"; import { LazyImage } from "./LazyImage"; +import { getBadgeUrl } from "@ywc19/utils/badge"; -export const CardRestaurant = () => { - return ( -
- -
-
- SDGs point 9.1/10.0 -
-
-
Hubuntu Restaurant
-

- Egestas elit dui scelerisque ut eu purus aliquam vitae habitasse. - Egestas elit dui Egestas elit dui scelerisque ut eu purus -

-
1.1 km
+interface ICardRestaurantProps { + name: string; + badges?: string[]; +} + +export const CardRestaurant: FC = (props) => { + const { name, badges = [] } = props + return ( +
+ +
+
+ { + badges.map((v, i) => ) + } +
+
+
{name}
+

+ Egestas elit dui scelerisque ut eu purus aliquam vitae habitasse. + Egestas elit dui Egestas elit dui scelerisque ut eu purus +

+
1.1 km
+
+
-
-
- ); + ); }; diff --git a/src/components/Caruosel.tsx b/src/components/Caruosel.tsx index 83592a2..8d540b4 100644 --- a/src/components/Caruosel.tsx +++ b/src/components/Caruosel.tsx @@ -8,78 +8,80 @@ import "swiper/css"; // import required modules import { Mousewheel, Keyboard } from "swiper/modules"; -export const Caruosel: FC<{ children: ReactNode; sliderPerPage: number }> = ({ - children, - sliderPerPage, +export const Caruosel: FC<{ children: ReactNode; sliderPerPage: number, onNext?: () => Promise }> = ({ + children, + sliderPerPage, + onNext, }) => { - const sliderRef = useRef(null); + const sliderRef = useRef(null); - const handlePrev = useCallback(() => { - if (!sliderRef.current) return; - sliderRef.current.swiper.slidePrev(); - }, []); + const handlePrev = useCallback(() => { + if (!sliderRef.current) return; + sliderRef.current.swiper.slidePrev(); + }, []); - const handleNext = useCallback(() => { - if (!sliderRef.current) return; - sliderRef.current.swiper.slideNext(); - }, []); + const handleNext = useCallback(async () => { + if (!sliderRef.current) return; + await onNext?.() + sliderRef.current.swiper.slideNext(); + }, [onNext, sliderRef]); - return ( -
- - {children} - -
- - - -
-
- - - -
-
- ); + return ( +
+ + {children} + +
+ + + +
+
+ + + +
+
+ ); }; diff --git a/src/pages/index.tsx b/src/pages/index.tsx index 0726d01..2acf6b9 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -5,145 +5,179 @@ import Head from "next/head"; import { CardMenu } from "@ywc19/components/CardMenu"; import { LazyImage } from "@ywc19/components/LazyImage"; import { type INavbarProps, Navbar } from "@ywc19/components/Navbar"; +import { Footer } from "@ywc19/components/Footer"; +import { api } from "@ywc19/utils/api"; import ModalConfirm from "@ywc19/components/ModalConfirm"; export default function Home() { - const mock = [1, 2, 3, 4, 5, 6, 7, 8]; - const category = [ - { - id: 0, - img: "/assets/appetizers.png", - name: "Appetizers", - }, - { - id: 1, - img: "/assets/dishes.png", - name: "Dishes", - }, - { - id: 2, - img: "/assets/desserts.png", - name: "Desserts", - }, - { - id: 3, - img: "/assets/drinks.png", - name: "Drinks", - }, - ]; + const mock = [1, 2, 3, 4, 5, 6, 7, 8]; + const { data: restaurant, fetchNextPage, isLoading } = api.restaurant.findMany.useInfiniteQuery( + { + limit: 2, + }, + { + getNextPageParam: (lastPage) => lastPage.nextCursor, + }, + ) + const category = [ + { + id: 0, + img: "/assets/appetizers.png", + name: "Appetizers", + }, + { + id: 1, + img: "/assets/dishes.png", + name: "Dishes", + }, + { + id: 2, + img: "/assets/desserts.png", + name: "Desserts", + }, + { + id: 3, + img: "/assets/drinks.png", + name: "Drinks", + }, + ]; - return ( - <> - - Create T3 App - - - -
- -
-

Content

+ const menu: INavbarProps["data"] = [ + { + name: "Home", + href: "#", + }, + { + name: "About", + href: "#", + }, + { + name: "Contact", + href: "#", + }, + { + name: "Service", + href: "#", + }, + ]; + return ( + <> + + Create T3 App + + + +
+ +
+

Content

-
- -
-
- - - -
- -
-
-
-
-
- {category.map((item) => ( - - ))} -
-
-
-

- Recommended Restaurants -

- -
- - {mock.map((item) => ( - - - - ))} - -
-
-
-

- Restaurant Nearby me -

- -
- - {mock.map((item) => ( - - - - ))} - -
-
-
-

Recommended Menu

- -
- - {mock.map((item) => ( - - - - ))} - -
- -
-

-
-
-
- - ); +
+ +
+
+ + + +
+ +
+
+
+
+
+ {category.map((item) => ( + + ))} +
+
+
+

+ Recommended Restaurants +

+ +
+ { + + {mock.map((item) => ( + + + + ))} + + } +
+
+
+

+ Restaurant Nearby me +

+ +
+ + {mock.map((item) => ( + + + + ))} + +
+
+
+

Recommended Menu

+ +
+ void await fetchNextPage()}> + {restaurant && restaurant.pages.map((page, i) => ( +
+ {page.items.map((item, j) => ( + + v.name)} /> + + ))} +
+ ))} +
+
+
+

+
+
+
+ + ); } diff --git a/src/server/api/routers/restaurant.ts b/src/server/api/routers/restaurant.ts index 9159b69..18bd3a3 100644 --- a/src/server/api/routers/restaurant.ts +++ b/src/server/api/routers/restaurant.ts @@ -2,13 +2,53 @@ import { createTRPCRouter, publicProcedure, } from "@ywc19/server/api/trpc"; -// import { UserFindManySchema, UserFindUniqueSchema } from "prisma/generated/schemas"; +import { z } from "zod"; + +const UserFindManySchema = z.object({ + where: z.object({ + name: z.string().optional(), + isRecommended: z.boolean().optional(), + }).optional(), + limit: z.number().min(1).max(100).nullish(), + cursor: z.string().nullish(), +}) + +const UserFindUniqueSchema = z.object({ + where: z.object({ + id: z.string() + }) +}) export const restaurantRouter = createTRPCRouter({ - // findMany: publicProcedure.input(UserFindManySchema).query(({ input, ctx }) => { - // return ctx.prisma.user.findMany(input) - // }), - // findUnique: publicProcedure.input(UserFindUniqueSchema).query(({ input, ctx }) => { - // return ctx.prisma.user.findUnique(input) - // }), + findMany: publicProcedure.input(UserFindManySchema).query(async ({ input, ctx }) => { + const limit = input.limit ?? 50; + const items = await ctx.prisma.restaurant.findMany({ + where: input.where?.name ? { + name: input.where?.name ? { + contains: input.where.name + } : undefined, + isRecommended: input.where?.isRecommended ? input.where.isRecommended : undefined, + } : undefined, + cursor: input.cursor ? { id: input.cursor } : undefined, + take: limit + 1, + orderBy: { id: 'asc' }, + include: { + tags: true + } + }) + + let nextCursor: typeof input.cursor | undefined = undefined; + if (items.length > limit) { + const nextItem = items.pop(); + nextCursor = nextItem?.id; + } + return { + items, + nextCursor, + }; + }), + + findUnique: publicProcedure.input(UserFindUniqueSchema).query(({ input, ctx }) => { + return ctx.prisma.user.findUnique(input) + }), }); diff --git a/src/utils/badge.ts b/src/utils/badge.ts new file mode 100644 index 0000000..aa23c35 --- /dev/null +++ b/src/utils/badge.ts @@ -0,0 +1,3 @@ +export const getBadgeUrl = (badge: string) => { + return `/assets/badges/${badge}.png` +}