diff --git a/src/backend/docker/docker-compose.yml b/src/backend/docker/docker-compose.yml index 468b06fdc..538acf464 100644 --- a/src/backend/docker/docker-compose.yml +++ b/src/backend/docker/docker-compose.yml @@ -63,12 +63,18 @@ services: # context: ./web/web.admin/dashboard # dockerfile: local.Dockerfile - # web-app: - # image: restaurant/web - # build: - # context: ./web/web.client/web-app - # dockerfile: local.Dockerfile - + web-app: + image: restaurant/web-app + build: + context: ./web/web.client/web-app-new + dockerfile: Dockerfile + ports: + - 3001:3000 + environment: + - BASE_URL=http://traefik:80 + - NEXT_SHARP_PATH=./node_modules/sharp + - AUTH_ISSUER=http://traefik:80/identity + order-db: image: postgres:alpine volumes: diff --git a/src/backend/scripts/release.sh b/src/backend/scripts/release.sh deleted file mode 100644 index 63bccedc5..000000000 --- a/src/backend/scripts/release.sh +++ /dev/null @@ -1,34 +0,0 @@ - -image_tag=$(date '+%Y%m%d%H%M') -container_registry='jurabek' -push_images='yes' - -while [[ $# -gt 0 ]]; do - case "$1" in - --skip-image-push ) - push_images=''; shift ;; - -h | --help ) - usage; exit 1 ;; - *) - echo "Unknown option $1" - usage; exit 2 ;; - esac -done - -echo "#################### Building Docker images ####################" -docker-compose -f ./docker-compose.yml build - -# Remove temporary images -# docker rmi $(docker images -qf "dangling=true") - -echo "#################### Tagging images to registry ####################" -services=(identity menu basket order dashboard) - -for service in "${services[@]}" -do - docker tag "restaurant/$service" "$container_registry/$service" - if [[ $push_images ]]; then - echo "Pushing image for service $service..." - docker push "$container_registry/$service" - fi -done \ No newline at end of file diff --git a/src/backend/services/checkout-api/.nvmrc b/src/backend/services/checkout-api/.nvmrc new file mode 100644 index 000000000..2edeafb09 --- /dev/null +++ b/src/backend/services/checkout-api/.nvmrc @@ -0,0 +1 @@ +20 \ No newline at end of file diff --git a/src/backend/web/web.client/web-app-new/.nvmrc b/src/backend/web/web.client/web-app-new/.nvmrc new file mode 100644 index 000000000..2edeafb09 --- /dev/null +++ b/src/backend/web/web.client/web-app-new/.nvmrc @@ -0,0 +1 @@ +20 \ No newline at end of file diff --git a/src/backend/web/web.client/web-app-new/Dockerfile b/src/backend/web/web.client/web-app-new/Dockerfile new file mode 100644 index 000000000..e392e95c6 --- /dev/null +++ b/src/backend/web/web.client/web-app-new/Dockerfile @@ -0,0 +1,52 @@ +FROM node:20-alpine AS base + +# 1. Install dependencies only when needed +FROM base AS deps +# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed. +RUN apk add --no-cache libc6-compat + +WORKDIR /app + +# Install dependencies based on the preferred package manager +COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* ./ +RUN \ + if [ -f yarn.lock ]; then yarn --frozen-lockfile; \ + elif [ -f package-lock.json ]; then npm ci; \ + elif [ -f pnpm-lock.yaml ]; then yarn global add pnpm && pnpm i; \ + else echo "Lockfile not found." && exit 1; \ + fi + +# 2. Rebuild the source code only when needed +FROM base AS builder +WORKDIR /app +COPY --from=deps /app/node_modules ./node_modules +COPY . . + +COPY .env.local .env.production +RUN yarn build + +# 3. Production image, copy all the files and run next +FROM base AS runner +WORKDIR /app + +ENV NODE_ENV=production + +RUN addgroup -g 1001 -S nodejs +RUN adduser -S nextjs -u 1001 + +COPY --from=builder /app/public ./public + +# Automatically leverage output traces to reduce image size +# https://nextjs.org/docs/advanced-features/output-file-tracing +COPY --from=builder /app/.next/standalone ./ +COPY --from=builder /app/.next/static ./.next/static + +RUN ls -a + + +EXPOSE 3000 + +ENV PORT 3000 +ENV HOSTNAME 0.0.0.0 + +CMD ["node", "server.js"] \ No newline at end of file diff --git a/src/backend/web/web.client/web-app-new/next.config.js b/src/backend/web/web.client/web-app-new/next.config.js index 696800684..7827089aa 100644 --- a/src/backend/web/web.client/web-app-new/next.config.js +++ b/src/backend/web/web.client/web-app-new/next.config.js @@ -1,5 +1,11 @@ /** @type {import('next').NextConfig} */ const nextConfig = { + output: "standalone", + logging: { + fetches: { + fullUrl: true, + }, + }, images: { remotePatterns: [ { @@ -10,6 +16,10 @@ const nextConfig = { protocol: "http", hostname: "localhost", }, + { + protocol: "http", + hostname: "traefik", + }, ], }, diff --git a/src/backend/web/web.client/web-app-new/package.json b/src/backend/web/web.client/web-app-new/package.json index 520ce6d64..301057a53 100644 --- a/src/backend/web/web.client/web-app-new/package.json +++ b/src/backend/web/web.client/web-app-new/package.json @@ -3,19 +3,19 @@ "version": "0.1.0", "private": true, "scripts": { - "dev": "next dev -p 3001", + "dev": "next dev -p 30011", "build": "next build", - "start": "next start -p 3001", + "start": "next start -p 30011", "lint": "next lint" }, "dependencies": { "@heroicons/react": "^2.0.18", - "clsx": "^2.1.0", "next": "14.0.3", "next-auth": "^4.24.5", "next-themes": "^0.2.1", "react": "^18", "react-dom": "^18", + "sharp": "^0.33.1", "zod": "^3.22.4" }, "devDependencies": { diff --git a/src/backend/web/web.client/web-app-new/src/app/api/auth/[...nextauth]/route.ts b/src/backend/web/web.client/web-app-new/src/app/api/auth/[...nextauth]/route.ts index ed9e5051d..b52a6752f 100644 --- a/src/backend/web/web.client/web-app-new/src/app/api/auth/[...nextauth]/route.ts +++ b/src/backend/web/web.client/web-app-new/src/app/api/auth/[...nextauth]/route.ts @@ -1,23 +1,23 @@ import NextAuth, { AuthOptions } from "next-auth" import IdentityServer4Provider from "next-auth/providers/identity-server4"; -export const authOptions: AuthOptions = { +const authOptions: AuthOptions = { providers: [ IdentityServer4Provider({ id: "web-app", name: "Restaraunt App Identity", - clientId: "nextjs-web-app", - clientSecret: "secret", - issuer: "http://localhost:8080/identity", + clientId: process.env.AUTH_CLIENT_ID, + clientSecret: process.env.AUTH_CLIENT_SECRET, + issuer: process.env.AUTH_ISSUER, authorization: { params: { scope: "openid profile catalog-api order-api basket-api payment-api checkout-api" } }, }) ], secret: process.env.NEXTAUTH_SECRET, callbacks: { async session({ session, token, user }) { - session.user.user_id = token.sub; + session.user = token; return session - } + }, } } diff --git a/src/backend/web/web.client/web-app-new/src/app/checkout/page.tsx b/src/backend/web/web.client/web-app-new/src/app/checkout/page.tsx index f263fe613..193edb838 100644 --- a/src/backend/web/web.client/web-app-new/src/app/checkout/page.tsx +++ b/src/backend/web/web.client/web-app-new/src/app/checkout/page.tsx @@ -1,14 +1,11 @@ -import { getServerSession } from "next-auth"; -import { authOptions } from "../api/auth/[...nextauth]/route"; +"use client"; + import { CheckoutComponent } from "./checkout"; -import { redirect } from "next/navigation"; +import { signIn, useSession } from "next-auth/react"; -const Page = async () => { - const session = await getServerSession(authOptions); - - return ( - <>{session?.user ? : redirect("api/auth/signin")} - ); +const Page = () => { + const { status } = useSession(); + return <>{status === "authenticated" ? : signIn()}; }; export default Page; diff --git a/src/backend/web/web.client/web-app-new/src/app/foods/[category]/page.tsx b/src/backend/web/web.client/web-app-new/src/app/foods/[category]/page.tsx index b29e9b740..9e42c50c8 100644 --- a/src/backend/web/web.client/web-app-new/src/app/foods/[category]/page.tsx +++ b/src/backend/web/web.client/web-app-new/src/app/foods/[category]/page.tsx @@ -1,5 +1,5 @@ import React from "react"; -import { fetchFoodItemsByCategory } from "../fetch"; +import { fetchFoodItemsByCategory } from "../../../lib/fetch"; import { FoodsPage } from "../foods"; const Page = async ({ params }: { params: { category: string } }) => { diff --git a/src/backend/web/web.client/web-app-new/src/app/foods/foods.tsx b/src/backend/web/web.client/web-app-new/src/app/foods/foods.tsx index 8a265b741..37fd3f6e9 100644 --- a/src/backend/web/web.client/web-app-new/src/app/foods/foods.tsx +++ b/src/backend/web/web.client/web-app-new/src/app/foods/foods.tsx @@ -1,6 +1,6 @@ import CategoriesSidebar from "@/components/CategoriesSidebar"; import FoodItem from "@/components/FoodItem"; -import { FoodItems } from "./fetch"; +import { FoodItems } from "../../lib/fetch"; import RightSidebar from "@/components/RightSidebar"; export const FoodsPage = ({ foodItems }: { foodItems: FoodItems }) => { diff --git a/src/backend/web/web.client/web-app-new/src/app/foods/page.tsx b/src/backend/web/web.client/web-app-new/src/app/foods/page.tsx index fcb5e7f6c..c84cf1894 100644 --- a/src/backend/web/web.client/web-app-new/src/app/foods/page.tsx +++ b/src/backend/web/web.client/web-app-new/src/app/foods/page.tsx @@ -1,5 +1,5 @@ import React from "react"; -import { fetchFoodItems } from "./fetch"; +import { fetchFoodItems } from "../../lib/fetch"; import { FoodsPage } from "./foods"; @@ -10,4 +10,6 @@ const Page = async () => { ); }; +export const dynamic = 'force-dynamic' + export default Page; diff --git a/src/backend/web/web.client/web-app-new/src/components/cart/open-cart.tsx b/src/backend/web/web.client/web-app-new/src/components/cart/open-cart.tsx index c67a1098f..01efc1936 100644 --- a/src/backend/web/web.client/web-app-new/src/components/cart/open-cart.tsx +++ b/src/backend/web/web.client/web-app-new/src/components/cart/open-cart.tsx @@ -1,5 +1,4 @@ import { ShoppingCartIcon } from "@heroicons/react/24/solid"; -import clsx from "clsx"; export default function OpenCart({ className, @@ -10,12 +9,7 @@ export default function OpenCart({ }) { return (
- + {quantity ? (
{quantity} diff --git a/src/backend/web/web.client/web-app-new/src/components/navbar/index.tsx b/src/backend/web/web.client/web-app-new/src/components/navbar/index.tsx index 245d4c4af..f7c40e6fd 100644 --- a/src/backend/web/web.client/web-app-new/src/components/navbar/index.tsx +++ b/src/backend/web/web.client/web-app-new/src/components/navbar/index.tsx @@ -30,7 +30,7 @@ const Navbar: React.FC = () => {
- +
diff --git a/src/backend/web/web.client/web-app-new/src/components/navbar/user-profile.tsx b/src/backend/web/web.client/web-app-new/src/components/navbar/user-profile.tsx index c60e40219..517d1dea9 100644 --- a/src/backend/web/web.client/web-app-new/src/components/navbar/user-profile.tsx +++ b/src/backend/web/web.client/web-app-new/src/components/navbar/user-profile.tsx @@ -1,16 +1,13 @@ "use client"; import { UserCircleIcon } from "@heroicons/react/24/solid"; -import { getProviders, signIn, signOut, useSession } from "next-auth/react"; -import Link from "next/link"; +import { signIn, signOut, useSession } from "next-auth/react"; import { useState } from "react"; export default function OpenUserProfile() { const [isDropdownOpen, setIsDropdownOpen] = useState(false); const { status } = useSession(); - getProviders().then((providers) => console.log("Providers", providers)); - return (
@@ -25,7 +22,7 @@ export default function OpenUserProfile() { {isDropdownOpen && (
{status === "unauthenticated" && ( -