diff --git a/.eslintrc.json b/.eslintrc.json
index cfc136b..4e4dede 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -1,6 +1,7 @@
{
"extends": "next",
"rules": {
- "no-unused-vars": "warn"
+ "no-unused-vars": "warn",
+ "react/display-name": "off"
}
}
diff --git a/.github/workflows/push_registry.yaml b/.github/workflows/push_registry.yaml
index 52854e6..2b6bb2a 100644
--- a/.github/workflows/push_registry.yaml
+++ b/.github/workflows/push_registry.yaml
@@ -22,7 +22,7 @@ jobs:
run: echo ${{ secrets.DOCKER_PASSWORD }} | docker login -u ${{ secrets.DOCKER_USERNAME }} --password-stdin ${{ secrets.DOCKER_REGISTRY }}
- name: Build Docker Image
- run: docker build -t ${{ secrets.DOCKER_USERNAME }}/menuroo-admin:${{ env.SHORT_SHA }} .
+ run: docker build --build-arg NEXT_PUBLIC_API_URL="https://api.menuroo.cz/query" -t ${{ secrets.DOCKER_USERNAME }}/menuroo-admin:${{ env.SHORT_SHA }} .
- name: Tag Docker Image
run: docker tag ${{ secrets.DOCKER_USERNAME }}/menuroo-admin:${{ env.SHORT_SHA }} ${{ secrets.DOCKER_REGISTRY }}/${{ secrets.DOCKER_USERNAME }}/menuroo-admin:${{ env.SHORT_SHA }}
diff --git a/.github/workflows/push_registry_dev.yaml b/.github/workflows/push_registry_dev.yaml
new file mode 100644
index 0000000..e197f32
--- /dev/null
+++ b/.github/workflows/push_registry_dev.yaml
@@ -0,0 +1,31 @@
+name: Build and Push Docker Image
+
+on:
+ push:
+ branches:
+ - stage
+
+
+jobs:
+ build_and_push:
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v2
+
+ - name: Get SHA for last commit
+ run: echo "SHORT_SHA=`echo ${GITHUB_SHA} | cut -c1-8`" >> $GITHUB_ENV
+
+
+ - name: Login to Docker Registry
+ run: echo ${{ secrets.DOCKER_PASSWORD }} | docker login -u ${{ secrets.DOCKER_USERNAME }} --password-stdin ${{ secrets.DOCKER_REGISTRY }}
+
+ - name: Build Docker Image
+ run: docker build --build-arg NEXT_PUBLIC_API_URL="https://api.dev.menuroo.cz/query" -t ${{ secrets.DOCKER_USERNAME }}/menuroo-admin-dev:${{ env.SHORT_SHA }} .
+
+ - name: Tag Docker Image
+ run: docker tag ${{ secrets.DOCKER_USERNAME }}/menuroo-admin-dev:${{ env.SHORT_SHA }} ${{ secrets.DOCKER_REGISTRY }}/${{ secrets.DOCKER_USERNAME }}/menuroo-admin-dev:${{ env.SHORT_SHA }}
+
+ - name: Push Docker Image
+ run: docker push ${{ secrets.DOCKER_REGISTRY }}/${{ secrets.DOCKER_USERNAME }}/menuroo-admin-dev:${{ env.SHORT_SHA }}
diff --git a/.gitignore b/.gitignore
index 64fe91e..d96baf0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -40,3 +40,5 @@ jspm_packages
.node_repl_history
.next
.vercel
+
+.DS_Store
diff --git a/Dockerfile b/Dockerfile
index 60fd060..7f5d405 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,6 +1,10 @@
FROM node:18-alpine
-ARG NEXT_PUBLIC_API_URL="https://api.menuroo.com/query"
+# Declare a build argument with a default value
+ARG NEXT_PUBLIC_API_URL="https://api.dev.menuroo.com/query"
+
+# Set the environment variable with the build argument value
+ENV NEXT_PUBLIC_API_URL=${NEXT_PUBLIC_API_URL}
RUN mkdir -p /app
WORKDIR /app
diff --git a/bun.lockb b/bun.lockb
index 0fa73f3..76cbd9b 100755
Binary files a/bun.lockb and b/bun.lockb differ
diff --git a/jest.config.ts b/jest.config.ts
new file mode 100644
index 0000000..0dd0922
--- /dev/null
+++ b/jest.config.ts
@@ -0,0 +1,13 @@
+import type { Config } from "jest";
+import nextJest from "next/jest.js";
+
+const createJestConfig = nextJest({
+ dir: "./",
+});
+
+const config: Config = {
+ coverageProvider: "v8",
+ testEnvironment: "jsdom",
+};
+
+export default createJestConfig(config);
diff --git a/package.json b/package.json
index 8673098..37b4459 100644
--- a/package.json
+++ b/package.json
@@ -7,32 +7,41 @@
"build": "next build",
"start": "next start",
"lint": "next lint",
- "analyze": "ANALYZE=true next build"
+ "analyze": "ANALYZE=true next build",
+ "test": "jest",
+ "test:watch": "jest --watch"
},
"dependencies": {
"@ant-design/cssinjs": "^1.17.0",
"@apollo/client": "latest",
- "@apollo/experimental-nextjs-app-support": "^0.4.2",
+ "@apollo/experimental-nextjs-app-support": "^0.5.2",
"@next/bundle-analyzer": "^14.0.3",
"@vercel/analytics": "^1.0.2",
"antd": "^5.9.0",
+ "classnames": "^2.3.2",
"dayjs": "^1.11.9",
"dayjs-plugin-utc": "^0.1.2",
"graphql": "^16.8.0",
"install": "^0.13.0",
- "next": "13.5.4",
+ "next": "14.0.4",
"react": "18.2.0",
"react-dom": "18.2.0"
},
"devDependencies": {
+ "@testing-library/jest-dom": "^6.1.5",
+ "@testing-library/react": "^14.1.2",
+ "@types/jest": "^29.5.11",
"@types/node": "20.6.0",
"@types/react": "18.2.21",
"@types/react-dom": "18.2.7",
- "eslint": "8.49.0",
- "eslint-config-next": "13.5.4",
"autoprefixer": "10.4.15",
+ "eslint": "8.49.0",
+ "eslint-config-next": "14.0.4",
+ "jest": "^29.7.0",
+ "jest-environment-jsdom": "^29.7.0",
"postcss": "8.4.29",
- "tailwindcss": "3.3.3",
+ "ts-jest": "^29.1.1",
+ "ts-node-dev": "^2.0.0",
"typescript": "5.2.2"
}
}
diff --git a/postcss.config.js b/postcss.config.js
index 12a703d..a47ef4f 100644
--- a/postcss.config.js
+++ b/postcss.config.js
@@ -1,6 +1,5 @@
module.exports = {
plugins: {
- tailwindcss: {},
autoprefixer: {},
},
};
diff --git a/public/fonts/Nunito-Black.ttf b/public/fonts/Nunito-Black.ttf
new file mode 100644
index 0000000..81d557c
Binary files /dev/null and b/public/fonts/Nunito-Black.ttf differ
diff --git a/public/fonts/Nunito-BlackItalic.ttf b/public/fonts/Nunito-BlackItalic.ttf
new file mode 100644
index 0000000..b4ba5a1
Binary files /dev/null and b/public/fonts/Nunito-BlackItalic.ttf differ
diff --git a/public/fonts/Nunito-Bold.ttf b/public/fonts/Nunito-Bold.ttf
new file mode 100644
index 0000000..886134d
Binary files /dev/null and b/public/fonts/Nunito-Bold.ttf differ
diff --git a/public/fonts/Nunito-BoldItalic.ttf b/public/fonts/Nunito-BoldItalic.ttf
new file mode 100644
index 0000000..0cb4efa
Binary files /dev/null and b/public/fonts/Nunito-BoldItalic.ttf differ
diff --git a/public/fonts/Nunito-ExtraBold.ttf b/public/fonts/Nunito-ExtraBold.ttf
new file mode 100644
index 0000000..711765e
Binary files /dev/null and b/public/fonts/Nunito-ExtraBold.ttf differ
diff --git a/public/fonts/Nunito-ExtraBoldItalic.ttf b/public/fonts/Nunito-ExtraBoldItalic.ttf
new file mode 100644
index 0000000..bffce10
Binary files /dev/null and b/public/fonts/Nunito-ExtraBoldItalic.ttf differ
diff --git a/public/fonts/Nunito-ExtraLight.ttf b/public/fonts/Nunito-ExtraLight.ttf
new file mode 100644
index 0000000..d9eabf9
Binary files /dev/null and b/public/fonts/Nunito-ExtraLight.ttf differ
diff --git a/public/fonts/Nunito-ExtraLightItalic.ttf b/public/fonts/Nunito-ExtraLightItalic.ttf
new file mode 100644
index 0000000..2037f4a
Binary files /dev/null and b/public/fonts/Nunito-ExtraLightItalic.ttf differ
diff --git a/public/fonts/Nunito-Italic.ttf b/public/fonts/Nunito-Italic.ttf
new file mode 100644
index 0000000..f4ab114
Binary files /dev/null and b/public/fonts/Nunito-Italic.ttf differ
diff --git a/public/fonts/Nunito-Light.ttf b/public/fonts/Nunito-Light.ttf
new file mode 100644
index 0000000..e64c0fe
Binary files /dev/null and b/public/fonts/Nunito-Light.ttf differ
diff --git a/public/fonts/Nunito-LightItalic.ttf b/public/fonts/Nunito-LightItalic.ttf
new file mode 100644
index 0000000..b465e5a
Binary files /dev/null and b/public/fonts/Nunito-LightItalic.ttf differ
diff --git a/public/fonts/Nunito-Medium.ttf b/public/fonts/Nunito-Medium.ttf
new file mode 100644
index 0000000..e24c1d6
Binary files /dev/null and b/public/fonts/Nunito-Medium.ttf differ
diff --git a/public/fonts/Nunito-MediumItalic.ttf b/public/fonts/Nunito-MediumItalic.ttf
new file mode 100644
index 0000000..6fec095
Binary files /dev/null and b/public/fonts/Nunito-MediumItalic.ttf differ
diff --git a/public/fonts/Nunito-Regular.ttf b/public/fonts/Nunito-Regular.ttf
new file mode 100644
index 0000000..9411bfb
Binary files /dev/null and b/public/fonts/Nunito-Regular.ttf differ
diff --git a/public/fonts/Nunito-SemiBold.ttf b/public/fonts/Nunito-SemiBold.ttf
new file mode 100644
index 0000000..1326a7d
Binary files /dev/null and b/public/fonts/Nunito-SemiBold.ttf differ
diff --git a/public/fonts/Nunito-SemiBoldItalic.ttf b/public/fonts/Nunito-SemiBoldItalic.ttf
new file mode 100644
index 0000000..d20e95f
Binary files /dev/null and b/public/fonts/Nunito-SemiBoldItalic.ttf differ
diff --git a/public/img/arrowUp.svg b/public/img/arrowUp.svg
new file mode 100644
index 0000000..134c1d8
--- /dev/null
+++ b/public/img/arrowUp.svg
@@ -0,0 +1,3 @@
+
diff --git a/public/img/closeCrossRed.svg b/public/img/closeCrossRed.svg
new file mode 100644
index 0000000..e208ce0
--- /dev/null
+++ b/public/img/closeCrossRed.svg
@@ -0,0 +1,4 @@
+
diff --git a/public/img/cross.svg b/public/img/cross.svg
new file mode 100644
index 0000000..a4857b6
--- /dev/null
+++ b/public/img/cross.svg
@@ -0,0 +1,4 @@
+
\ No newline at end of file
diff --git a/public/img/headerIcon.svg b/public/img/headerIcon.svg
new file mode 100644
index 0000000..758a8e2
--- /dev/null
+++ b/public/img/headerIcon.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/public/img/redCross.svg b/public/img/redCross.svg
new file mode 100644
index 0000000..881e5a1
--- /dev/null
+++ b/public/img/redCross.svg
@@ -0,0 +1,4 @@
+
diff --git a/public/img/smallArrow.svg b/public/img/smallArrow.svg
new file mode 100644
index 0000000..733f876
--- /dev/null
+++ b/public/img/smallArrow.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/public/img/splitter.svg b/public/img/splitter.svg
new file mode 100644
index 0000000..82a9a0c
--- /dev/null
+++ b/public/img/splitter.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/app/(admin)/[date]/page.tsx b/src/app/(admin)/[date]/page.tsx
new file mode 100644
index 0000000..3e890d1
--- /dev/null
+++ b/src/app/(admin)/[date]/page.tsx
@@ -0,0 +1,46 @@
+"use server";
+
+import CreateMenu from "@/modules/CreateMenu/CreateMenu";
+import getToken from "@/utils/getToken";
+import getMenusByDate from "@/queries/getMenusByDate";
+import { getClient } from "@/lib/ssrApolloClient";
+import getTime from "@/lib/getTime";
+
+const CreateMenuPage = async ({ params }: { params: { date: string } }) => {
+ const token = getToken();
+
+ const { data: menusByDate } = await getClient()
+ .query({
+ query: getMenusByDate,
+ variables: {
+ dateFrom: getTime({
+ date: params.date,
+ day: "middle",
+ }),
+ dateTo: getTime({
+ date: params.date,
+ day: "middle",
+ }),
+ },
+ context: {
+ headers: {
+ Authorization: getToken(),
+ },
+ fetchOptions: {
+ next: { tags: ["menusByDate"] },
+ },
+ },
+ fetchPolicy: "network-only",
+ })
+ .catch((err) => err);
+
+ return (
+
+ );
+};
+
+export default CreateMenuPage;
diff --git a/src/app/(admin)/finance/page.tsx b/src/app/(admin)/finance/page.tsx
new file mode 100644
index 0000000..e0cc2f0
--- /dev/null
+++ b/src/app/(admin)/finance/page.tsx
@@ -0,0 +1,7 @@
+import { Fragment } from "react";
+
+const Page = async () => {
+ return ;
+};
+
+export default Page;
diff --git a/src/app/(admin)/jidelni-listek/page.tsx b/src/app/(admin)/jidelni-listek/page.tsx
new file mode 100644
index 0000000..13d98bd
--- /dev/null
+++ b/src/app/(admin)/jidelni-listek/page.tsx
@@ -0,0 +1,12 @@
+"use server";
+
+import AdminPage from "@/modules/AdminPage/AdminPage";
+import getMenus from "@/modules/AdminPage/actions/getMenus";
+
+const Page = async () => {
+ const menusByDate = await getMenus();
+
+ return ;
+};
+
+export default Page;
diff --git a/src/app/(admin)/layout.tsx b/src/app/(admin)/layout.tsx
new file mode 100644
index 0000000..4fab7fb
--- /dev/null
+++ b/src/app/(admin)/layout.tsx
@@ -0,0 +1,54 @@
+import React from "react";
+import type { Metadata } from "next";
+import { ApolloWrapper } from "../ApolloWrapper";
+import { Analytics } from "@vercel/analytics/react";
+import { redirect } from "next/navigation";
+import { cookies } from "next/headers";
+import dayjs from "dayjs";
+import utc from "dayjs/plugin/utc";
+import updateLocale from "dayjs/plugin/updateLocale";
+import { AdminLayout } from "@/components/AdminLayout";
+
+import "../globals.css";
+
+export const metadata: Metadata = {
+ title: "Menuroo",
+ description: "Menuroo administrace",
+};
+
+const Layout = ({ children }: { children: React.ReactNode }) => {
+ dayjs.extend(updateLocale, utc);
+ dayjs.updateLocale("en", {
+ weekStart: 1,
+ });
+
+ const cookieStore = cookies();
+
+ const isAdmin = () => {
+ const jwt = cookieStore.get("token")?.value;
+ if (jwt) {
+ const decodedToken = JSON.parse(atob(jwt.split(".")[1]));
+ return decodedToken.role === "admin";
+ }
+
+ return false;
+ };
+
+ if (!isAdmin()) {
+ return redirect("/");
+ }
+
+ return (
+
+
+
+
+ {children}
+
+
+
+
+ );
+};
+
+export default Layout;
diff --git a/src/app/(admin)/nastaveni/page.tsx b/src/app/(admin)/nastaveni/page.tsx
new file mode 100644
index 0000000..a2244a8
--- /dev/null
+++ b/src/app/(admin)/nastaveni/page.tsx
@@ -0,0 +1,9 @@
+"use server";
+
+import SettingsPage from "@/modules/Settings/SettingsPage";
+
+const Page = async () => {
+ return ;
+};
+
+export default Page;
diff --git a/src/app/(admin)/not-found.tsx b/src/app/(admin)/not-found.tsx
new file mode 100644
index 0000000..abf4006
--- /dev/null
+++ b/src/app/(admin)/not-found.tsx
@@ -0,0 +1,11 @@
+import { cookies } from "next/headers";
+import Link from "next/link";
+import React from "react";
+
+const RootNotFound = () => {
+ const redirectUrl = cookies().get("token") ? "/jidelni-listek" : "/";
+
+ return Domů;
+};
+
+export default RootNotFound;
diff --git a/src/app/(admin)/objednavky/page.tsx b/src/app/(admin)/objednavky/page.tsx
new file mode 100644
index 0000000..ab04818
--- /dev/null
+++ b/src/app/(admin)/objednavky/page.tsx
@@ -0,0 +1,12 @@
+"use server";
+
+import MenuOrdersPage from "@/modules/MenuOrdersPage/MenuOrdersPage";
+import getMenuOrders from "@/modules/MenuOrdersPage/actions/getOrders";
+
+const Page = async () => {
+ const menuOrders = await getMenuOrders();
+
+ return ;
+};
+
+export default Page;
diff --git a/src/app/admin/resources/page.tsx b/src/app/(admin)/resources/page.tsx
similarity index 100%
rename from src/app/admin/resources/page.tsx
rename to src/app/(admin)/resources/page.tsx
diff --git a/src/app/admin/settings/page.tsx b/src/app/(admin)/settings/page.tsx
similarity index 52%
rename from src/app/admin/settings/page.tsx
rename to src/app/(admin)/settings/page.tsx
index 9132a92..f75e76e 100644
--- a/src/app/admin/settings/page.tsx
+++ b/src/app/(admin)/settings/page.tsx
@@ -1,56 +1,59 @@
-import { PriceLevel, PriceLevelGroup } from "@/components/Settings/components";
+import { PriceLevel, PriceLevelGroup } from "@/modules/Settings/components";
import adminGetAllPriceLvlGroups from "@/queries/adminGetAllPriceLvlGroups";
import getToken from "@/utils/getToken";
import adminGetAllFoodPriceLvls from "@/queries/adminGetAllFoodPriceLvls";
-import UserGroup from "@/components/Settings/components/UserGroup/UserGroup";
+import UserGroup from "@/modules/Settings/components/UserGroup/UserGroup";
import { getClient } from "@/lib/ssrApolloClient";
import adminGetAllUserGroups from "@/queries/adminGetAllUserGroups";
-import { revalidatePath } from "next/cache";
- const getData = async () => {
- "use server";
+const getData = async () => {
+ "use server";
- revalidatePath("/admin/settings");
+ const { data: allPriceLvlGroupsData } = await getClient().query({
+ query: adminGetAllPriceLvlGroups,
+ context: {
+ headers: {
+ Authorization: getToken(),
+ },
+ fetchOptions: {
+ next: { tags: ["priceLvlGroups"] },
+ },
+ },
+ fetchPolicy: "network-only",
+ });
- const { data: allPriceLvlGroupsData } = await getClient().query({
- query: adminGetAllPriceLvlGroups,
- context: {
- headers: {
- Authorization: getToken(),
- },
- },
- fetchPolicy: "network-only",
- });
+ const { data: priceLevelsData } = await getClient().query({
+ query: adminGetAllFoodPriceLvls,
+ context: {
+ headers: {
+ Authorization: getToken(),
+ },
+ fetchOptions: {
+ next: { tags: ["priceLevels"] },
+ },
+ },
+ fetchPolicy: "network-only",
+ });
- const { data: priceLevelsData } = await getClient().query({
- query: adminGetAllFoodPriceLvls,
- context: {
- headers: {
- Authorization: getToken(),
- },
- },
- fetchPolicy: "network-only",
- });
+ const { data: userGroupsData } = await getClient().query({
+ query: adminGetAllUserGroups,
+ context: {
+ headers: {
+ Authorization: getToken(),
+ },
+ fetchOptions: {
+ next: { tags: ["userGroups"] },
+ },
+ },
+ fetchPolicy: "network-only",
+ });
- const { data: userGroupsData } = await getClient().query({
- query: adminGetAllUserGroups,
- context: {
- headers: {
- Authorization: getToken(),
- },
- fetchOptions: {
- next: { revalidate: 5 },
- },
- },
- fetchPolicy: "network-only",
- });
-
- return {
- allPriceLvlGroupsData,
- priceLevelsData,
- userGroupsData,
- };
- };
+ return {
+ allPriceLvlGroupsData,
+ priceLevelsData,
+ userGroupsData,
+ };
+};
const Page = async () => {
const token = getToken();
@@ -67,18 +70,15 @@ const Page = async () => {
{
const token = getToken();
diff --git a/src/app/(admin)/vydej/page.tsx b/src/app/(admin)/vydej/page.tsx
new file mode 100644
index 0000000..5acaab3
--- /dev/null
+++ b/src/app/(admin)/vydej/page.tsx
@@ -0,0 +1,11 @@
+import WaiterOrdersPage from "@/modules/WaiterOrdersPage/WaiterOrdersPage";
+import getWaiterOrders from "@/modules/WaiterOrdersPage/actions/getWaiterOrders";
+
+const Page = async () => {
+ // TODO: remove the "1"
+ const waiterOrders = await getWaiterOrders(1);
+
+ return ;
+};
+
+export default Page;
diff --git a/src/app/layout.tsx b/src/app/(login)/layout.tsx
similarity index 85%
rename from src/app/layout.tsx
rename to src/app/(login)/layout.tsx
index efaa66d..120890a 100644
--- a/src/app/layout.tsx
+++ b/src/app/(login)/layout.tsx
@@ -1,40 +1,29 @@
import React from "react";
import type { Metadata } from "next";
-import { ConfigProvider } from "antd";
-import { ApolloWrapper } from "./ApolloWrapper";
+import { ApolloWrapper } from "../ApolloWrapper";
import { Analytics } from "@vercel/analytics/react";
-import themeConfig from "@/theme/themeConfig";
-
-import StyledComponentsRegistry from "@/lib/AntdRegistry";
-
-import "./globals.css";
+import "../globals.css";
export const metadata: Metadata = {
title: "Menuroo",
description: "Menuroo administrace",
};
-const RootLayout = ({ children }: { children: React.ReactNode }) => {
+const LoginLayout = ({ children }: { children: React.ReactNode }) => {
return (
-
-
-
-
-
+ {children}
+
);
};
-export default RootLayout;
+export default LoginLayout;
// ⠀⢀⣒⠒⠆⠤⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
// ⢠⡛⠛⠻⣷⣶⣦⣬⣕⡒⠤⢀⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
diff --git a/src/app/page.tsx b/src/app/(login)/page.tsx
similarity index 65%
rename from src/app/page.tsx
rename to src/app/(login)/page.tsx
index 2d7b6d4..47912e6 100644
--- a/src/app/page.tsx
+++ b/src/app/(login)/page.tsx
@@ -1,14 +1,15 @@
import { cookies } from "next/headers";
-import LoginPage from "@/components/Login/LoginPage";
+import { LoginPage } from "@/modules/login/screens";
-const HomePage = () => {
+const Page = () => {
const setToken = async (token: string) => {
"use server";
cookies().set("token", token);
};
+
return ;
};
-export default HomePage;
+export default Page;
diff --git a/src/app/admin/[date]/page.tsx b/src/app/admin/[date]/page.tsx
deleted file mode 100644
index 0718d4d..0000000
--- a/src/app/admin/[date]/page.tsx
+++ /dev/null
@@ -1,12 +0,0 @@
-"use server";
-
-import CreateMenu from "@/components/CreateMenu/CreateMenu";
-import getToken from "@/utils/getToken";
-
-const CreateMenuPage = ({ params }: { params: { date: string } }) => {
- const token = getToken();
-
- return ;
-};
-
-export default CreateMenuPage;
diff --git a/src/app/admin/layout.tsx b/src/app/admin/layout.tsx
deleted file mode 100644
index f92e028..0000000
--- a/src/app/admin/layout.tsx
+++ /dev/null
@@ -1,146 +0,0 @@
-"use client";
-
-import React, { useLayoutEffect } from "react";
-import Link from "next/link";
-import { useRouter } from "next/navigation";
-import { usePathname } from "next/navigation";
-import { Button } from "antd";
-import dayjs from "dayjs";
-import utc from "dayjs/plugin/utc";
-import { LogoutOutlined } from "@ant-design/icons";
-import updateLocale from "dayjs/plugin/updateLocale";
-import { navbarItems } from "@/components/Layout/constants";
-import isTokenInLocalStorage from "@/utils/isTokenInLocalStorage";
-
-const AdminLayout = ({ children }: { children: React.ReactNode }) => {
- const [selectedKey, setSelectedKey] = React.useState("");
- const [isLogged, setIsLogged] = React.useState(false);
- const [isMenuOpen, setIsMenuOpen] = React.useState(false);
- const pathname = usePathname();
- const router = useRouter();
-
- dayjs.extend(updateLocale, utc);
- dayjs.updateLocale("en", {
- weekStart: 1,
- });
-
- useLayoutEffect(() => {
- const isAdmin = () => {
- const token = localStorage.getItem("token");
- if (token) {
- const decodedToken = JSON.parse(atob(token.split(".")[1]));
- return decodedToken.role === "admin";
- }
- };
-
- if (isTokenInLocalStorage() && isAdmin()) {
- setIsLogged(true);
- } else {
- router.push("/");
- }
-
- setSelectedKey(
- pathname === "/admin"
- ? "1"
- : pathname === "/admin/queue"
- ? "2"
- : pathname === "/admin/statistics"
- ? "3"
- : pathname === "/admin/resources"
- ? "4"
- : pathname === "/admin/settings"
- ? "5"
- : "1"
- );
- }, [pathname, router]);
-
- const handleLogout = () => {
- localStorage.removeItem("token");
- router.push("/");
- };
-
- const onTabClick = (key: string) => {
- switch (key) {
- case "1":
- return "/admin";
- case "2":
- return "/admin/queue";
- case "3":
- return "/admin/statistics";
- case "4":
- // return "/admin/resources";
- case "5":
- return "/admin/settings";
- default:
- return "/admin";
- }
- };
-
- const HamburgerIcon = (
-
-
-
-
-
- );
-
- const CloseIcon = (
-
-
-
-
- );
-
- return (
- <>
- {isLogged && (
-
-
-
-
-
-
- {navbarItems.map((item) => {
- const isSelected = item.key === selectedKey;
- return (
-
- {item.label}
-
- );
- })}
-
-
}
- onClick={handleLogout}
- >
- Odhlásit se
-
-
- {children}
-
- )}
- >
- );
-};
-
-export default AdminLayout;
diff --git a/src/app/admin/page.tsx b/src/app/admin/page.tsx
deleted file mode 100644
index 33d44d8..0000000
--- a/src/app/admin/page.tsx
+++ /dev/null
@@ -1,12 +0,0 @@
-"use server";
-
-import getToken from "@/utils/getToken";
-import AdminPage from "@/components/AdminPage/AdminPage";
-
-const Page = () => {
- const token = getToken();
-
- return ;
-};
-
-export default Page;
diff --git a/src/app/admin/queue/page.tsx b/src/app/admin/queue/page.tsx
deleted file mode 100644
index f3146e2..0000000
--- a/src/app/admin/queue/page.tsx
+++ /dev/null
@@ -1,10 +0,0 @@
-import QueuePage from "@/components/QueuePage/QueuePage";
-import getToken from "@/utils/getToken";
-
-const Page = () => {
- const token = getToken();
-
- return ;
-};
-
-export default Page;
diff --git a/src/app/globals.css b/src/app/globals.css
index 3727e2e..dcee558 100644
--- a/src/app/globals.css
+++ b/src/app/globals.css
@@ -1,10 +1,116 @@
-@tailwind base;
-@tailwind components;
-@tailwind utilities;
+@font-face {
+ font-family: "Nunito";
+ src: url("/fonts/Nunito-Black.ttf") format("truetype");
+ font-weight: 900;
+ font-style: normal;
+}
+
+@font-face {
+ font-family: "Nunito";
+ src: url("/fonts/Nunito-BlackItalic.ttf") format("truetype");
+ font-weight: 900;
+ font-style: italic;
+}
+
+@font-face {
+ font-family: "Nunito";
+ src: url("/fonts/Nunito-Bold.ttf") format("truetype");
+ font-weight: 700;
+ font-style: normal;
+}
+
+@font-face {
+ font-family: "Nunito";
+ src: url("/fonts/Nunito-BoldItalic.ttf") format("truetype");
+ font-weight: 700;
+ font-style: italic;
+}
+
+@font-face {
+ font-family: "Nunito";
+ src: url("/fonts/Nunito-ExtraBold.ttf") format("truetype");
+ font-weight: 800;
+ font-style: normal;
+}
+
+@font-face {
+ font-family: "Nunito";
+ src: url("/fonts/Nunito-ExtraBoldItalic.ttf") format("truetype");
+ font-weight: 800;
+ font-style: italic;
+}
+
+@font-face {
+ font-family: "Nunito";
+ src: url("/fonts/Nunito-Italic.ttf") format("truetype");
+ font-weight: 400;
+ font-style: italic;
+}
+
+@font-face {
+ font-family: "Nunito";
+ src: url("/fonts/Nunito-Light.ttf") format("truetype");
+ font-weight: 300;
+ font-style: normal;
+}
+@font-face {
+ font-family: "Nunito";
+ src: url("/fonts/Nunito-LightItalic.ttf") format("truetype");
+ font-weight: 300;
+ font-style: italic;
+}
+
+@font-face {
+ font-family: "Nunito";
+ src: url("/fonts/Nunito-Medium.ttf") format("truetype");
+ font-weight: 500;
+ font-style: normal;
+}
+
+@font-face {
+ font-family: "Nunito";
+ src: url("/fonts/Nunito-MediumItalic.ttf") format("truetype");
+ font-weight: 500;
+ font-style: italic;
+}
+
+@font-face {
+ font-family: "Nunito";
+ src: url("/fonts/Nunito-Regular.ttf") format("truetype");
+ font-weight: 400;
+ font-style: normal;
+}
+
+@font-face {
+ font-family: "Nunito";
+ src: url("/fonts/Nunito-SemiBold.ttf") format("truetype");
+ font-weight: 600;
+ font-style: normal;
+}
+
+@font-face {
+ font-family: "Nunito";
+ src: url("/fonts/Nunito-SemiBoldItalic.ttf") format("truetype");
+ font-weight: 600;
+ font-style: italic;
+}
+
+html,
body {
- color: #1f2937;
- background: #fff;
+ font-family: "Nunito", sans-serif;
+ color: #030202;
+ background: var(--beige-web, #f9f7f2);
+}
+
+* {
+ margin: 0;
+ padding: 0;
+ outline: none;
+ border: none;
+ box-sizing: border-box;
+ text-decoration: none;
+ font-family: "Nunito", sans-serif;
}
/* Hide scrollbar for Chrome, Safari and Opera */
diff --git a/src/app/not-found.tsx b/src/app/not-found.tsx
deleted file mode 100644
index 7dd4232..0000000
--- a/src/app/not-found.tsx
+++ /dev/null
@@ -1,25 +0,0 @@
-"use client";
-
-import Link from "next/link";
-import React from "react";
-import { Button, Result } from "antd";
-import isTokenInLocalStorage from "@/utils/isTokenInLocalStorage";
-
-const RootNotFound = () => {
- const redirectUrl = isTokenInLocalStorage() ? "/admin" : "/";
-
- return (
-
- Domů
-
- }
- />
- );
-};
-
-export default RootNotFound;
diff --git a/src/app/privacy/layout.tsx b/src/app/privacy/layout.tsx
new file mode 100644
index 0000000..ccd16be
--- /dev/null
+++ b/src/app/privacy/layout.tsx
@@ -0,0 +1,23 @@
+import React from "react";
+import type { Metadata } from "next";
+import { Analytics } from "@vercel/analytics/react";
+
+import "../globals.css";
+
+export const metadata: Metadata = {
+ title: "Menuroo - Privacy",
+ description: "Menuroo administrace",
+};
+
+const PrivacyLayout = ({ children }: { children: React.ReactNode }) => {
+ return (
+
+
+ {children}
+
+
+
+ );
+};
+
+export default PrivacyLayout;
diff --git a/src/components/AdminLayout/AdminLayout.module.css b/src/components/AdminLayout/AdminLayout.module.css
new file mode 100644
index 0000000..c09c75f
--- /dev/null
+++ b/src/components/AdminLayout/AdminLayout.module.css
@@ -0,0 +1,12 @@
+.container {
+ display: flex;
+ flex-direction: row;
+ min-height: 100vh;
+ height: 100vh;
+}
+
+.children {
+ width: 100%;
+ padding: 8rem 6rem 11.69rem 6rem;
+ box-sizing: border-box;
+}
\ No newline at end of file
diff --git a/src/components/AdminLayout/AdminLayout.tsx b/src/components/AdminLayout/AdminLayout.tsx
new file mode 100644
index 0000000..f86c6e4
--- /dev/null
+++ b/src/components/AdminLayout/AdminLayout.tsx
@@ -0,0 +1,19 @@
+import { ReactNode } from "react";
+import { Sidebar } from "./components/Sidebar";
+
+import styles from "./AdminLayout.module.css";
+
+interface Props {
+ children: ReactNode;
+}
+
+const Adminlayout = (props: Props) => {
+ return (
+
+ );
+};
+
+export default Adminlayout;
diff --git a/src/components/AdminLayout/components/Sidebar/Sidebar.module.css b/src/components/AdminLayout/components/Sidebar/Sidebar.module.css
new file mode 100644
index 0000000..20f594c
--- /dev/null
+++ b/src/components/AdminLayout/components/Sidebar/Sidebar.module.css
@@ -0,0 +1,44 @@
+.container {
+ display: flex;
+ flex-direction: column;
+ justify-content: space-between;
+ padding: 4rem 2.62rem 2.5rem 0;
+ width: 21.9375rem;
+ height: 100%;
+ box-sizing: border-box;
+ border-right: 1px solid var(--storking-my-shi, #EBEBEB);
+}
+
+.content {
+ display: flex;
+ flex-direction: column;
+ justify-content: space-between;
+ width: 100%;
+ gap: 4.5rem;
+}
+
+.nav {
+ width: 100%;
+ height: 100%;
+}
+
+.menu {
+ display: flex;
+ flex-direction: column;
+}
+
+.footer {
+ display: flex;
+ flex-direction: column;
+ justify-content: flex-end;
+ align-items: flex-start;
+ width: 100%;
+}
+
+.footer h3 {
+ padding-left: 4.5rem;
+}
+
+.restaurantTitle {
+ color: #9E9E9E;
+}
\ No newline at end of file
diff --git a/src/components/AdminLayout/components/Sidebar/Sidebar.tsx b/src/components/AdminLayout/components/Sidebar/Sidebar.tsx
new file mode 100644
index 0000000..231f34c
--- /dev/null
+++ b/src/components/AdminLayout/components/Sidebar/Sidebar.tsx
@@ -0,0 +1,57 @@
+"use server";
+
+import { headers } from "next/headers";
+import { Typography } from "@/components/Typography";
+import { LogoHeader } from "@/components/LogoHeader";
+import sidebarItems from "./constants/sidebarItems";
+import { Logout } from "./components/Logout";
+import { SidebarItem } from "./components/SidebarItem";
+
+import styles from "./Sidebar.module.css";
+
+const Sidebar = () => {
+ const url = headers().get("x-url");
+
+ const isActive = (link: string) => {
+ const path = url?.split("/");
+ const length = path?.length;
+
+ if (length && "/" + path[length - 1] === link) {
+ return true;
+ }
+
+ return false;
+ };
+
+ return (
+
+
+
+
+ {sidebarItems.map((item) => (
+
+ {item.name}
+
+ ))}
+
+
+
+
+
+ Zlatá Štika
+
+
+
+ );
+};
+
+export default Sidebar;
diff --git a/src/components/AdminLayout/components/Sidebar/components/Logout/Logout.module.css b/src/components/AdminLayout/components/Sidebar/components/Logout/Logout.module.css
new file mode 100644
index 0000000..3d5423f
--- /dev/null
+++ b/src/components/AdminLayout/components/Sidebar/components/Logout/Logout.module.css
@@ -0,0 +1,3 @@
+.logout {
+ cursor: pointer;
+}
\ No newline at end of file
diff --git a/src/components/AdminLayout/components/Sidebar/components/Logout/Logout.tsx b/src/components/AdminLayout/components/Sidebar/components/Logout/Logout.tsx
new file mode 100644
index 0000000..fbad0f4
--- /dev/null
+++ b/src/components/AdminLayout/components/Sidebar/components/Logout/Logout.tsx
@@ -0,0 +1,29 @@
+"use client";
+
+import { useRouter } from "next/navigation";
+import { Typography } from "@/components/Typography";
+
+import styles from "./Logout.module.css";
+
+const Logout = () => {
+ const router = useRouter();
+
+ const handleLogout = () => {
+ document.cookie = "token=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";
+ router.push("/");
+ };
+
+ return (
+
+ Odhlásit se
+
+ );
+};
+
+export default Logout;
diff --git a/src/components/AdminLayout/components/Sidebar/components/Logout/index.tsx b/src/components/AdminLayout/components/Sidebar/components/Logout/index.tsx
new file mode 100644
index 0000000..3ba3c9b
--- /dev/null
+++ b/src/components/AdminLayout/components/Sidebar/components/Logout/index.tsx
@@ -0,0 +1 @@
+export { default as Logout } from "./Logout";
diff --git a/src/components/AdminLayout/components/Sidebar/components/SidebarItem/SidebarItem.module.css b/src/components/AdminLayout/components/Sidebar/components/SidebarItem/SidebarItem.module.css
new file mode 100644
index 0000000..e765069
--- /dev/null
+++ b/src/components/AdminLayout/components/Sidebar/components/SidebarItem/SidebarItem.module.css
@@ -0,0 +1,25 @@
+.sidebarItemContainer {
+ display: flex;
+ justify-content: flex-start;
+ align-items: center;
+ width: 19.3125rem;
+ height: 3.75rem;
+
+ &.isActive {
+ border-radius: 0rem 6.25rem 6.25rem 0rem;
+ background: rgba(255, 0, 0, 0.03);
+ }
+}
+
+.sidebarItem {
+ display: block;
+ color: #000;
+ font-size: 1.5rem;
+ font-weight: 800;
+ padding-left: 4.5rem;
+
+ &.isActive {
+ color: var(--red, #D51F2C);
+ text-decoration: underline;
+ }
+}
\ No newline at end of file
diff --git a/src/components/AdminLayout/components/Sidebar/components/SidebarItem/SidebarItem.tsx b/src/components/AdminLayout/components/Sidebar/components/SidebarItem/SidebarItem.tsx
new file mode 100644
index 0000000..3d19e1c
--- /dev/null
+++ b/src/components/AdminLayout/components/Sidebar/components/SidebarItem/SidebarItem.tsx
@@ -0,0 +1,48 @@
+"use client";
+
+import { Typography } from "@/components/Typography";
+import Link from "next/link";
+import { usePathname } from "next/navigation";
+import { useState, useEffect } from "react";
+
+import styles from "./SidebarItem.module.css";
+
+interface Props {
+ active: boolean;
+ link: string;
+ children: string;
+}
+
+const SidebarItem = (props: Props) => {
+ const pathname = usePathname();
+
+ const [isActiveStyle, setIsActiveStyle] = useState(
+ props.active ? styles.isActive : ""
+ );
+
+ useEffect(() => {
+ if (pathname.includes(props.link)) {
+ setIsActiveStyle(styles.isActive);
+ } else {
+ setIsActiveStyle("");
+ }
+ }, [pathname]);
+
+ return (
+
+
+
+ {props.children}
+
+
+
+ );
+};
+
+export default SidebarItem;
diff --git a/src/components/AdminLayout/components/Sidebar/components/SidebarItem/index.tsx b/src/components/AdminLayout/components/Sidebar/components/SidebarItem/index.tsx
new file mode 100644
index 0000000..0a11928
--- /dev/null
+++ b/src/components/AdminLayout/components/Sidebar/components/SidebarItem/index.tsx
@@ -0,0 +1 @@
+export { default as SidebarItem } from "./SidebarItem";
diff --git a/src/components/AdminLayout/components/Sidebar/constants/sidebarItems.ts b/src/components/AdminLayout/components/Sidebar/constants/sidebarItems.ts
new file mode 100644
index 0000000..86e2922
--- /dev/null
+++ b/src/components/AdminLayout/components/Sidebar/constants/sidebarItems.ts
@@ -0,0 +1,24 @@
+const sidebarItems = [
+ {
+ name: "Jídelní lístky",
+ link: "/jidelni-listek",
+ },
+ {
+ name: "Výdej",
+ link: "/vydej",
+ },
+ {
+ name: "Objednávky",
+ link: "/objednavky",
+ },
+ {
+ name: "Finance",
+ link: "/finance",
+ },
+ {
+ name: "Nastavení",
+ link: "/nastaveni",
+ },
+];
+
+export default sidebarItems;
diff --git a/src/components/AdminLayout/components/Sidebar/index.tsx b/src/components/AdminLayout/components/Sidebar/index.tsx
new file mode 100644
index 0000000..c3c6406
--- /dev/null
+++ b/src/components/AdminLayout/components/Sidebar/index.tsx
@@ -0,0 +1 @@
+export { default as Sidebar } from "./Sidebar";
diff --git a/src/components/AdminLayout/index.tsx b/src/components/AdminLayout/index.tsx
new file mode 100644
index 0000000..4e9ad31
--- /dev/null
+++ b/src/components/AdminLayout/index.tsx
@@ -0,0 +1 @@
+export { default as AdminLayout } from "./AdminLayout";
diff --git a/src/components/Dropdown/Dropdown.module.css b/src/components/Dropdown/Dropdown.module.css
new file mode 100644
index 0000000..09a7b24
--- /dev/null
+++ b/src/components/Dropdown/Dropdown.module.css
@@ -0,0 +1,64 @@
+.container {
+ width: 100%;
+ min-height: 100%;
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0.875rem 1.5rem;
+ cursor: pointer;
+ position: relative;
+
+ border-radius: 0.75rem;
+ border: 2px solid var(--Beige, #EEE8DA);
+ background: var(--Light-beige-copy, #F5F2EB);
+}
+
+.container h4 {
+ z-index: 1;
+}
+
+.chevron {
+ position: relative;
+ width: 1rem;
+ height: 1rem;
+ rotate: 180deg;
+ transition: rotate 0.2s ease-in-out;
+ z-index: 1;
+
+ &.isOpen {
+ rotate: 0deg;
+ }
+}
+
+.dropdownMenu {
+ position: absolute;
+ display: none;
+ padding-top: 3rem;
+ flex-direction: column;
+ width: 100%;
+ left: 0;
+ top: 0;
+
+ &.isOpen {
+ display: flex;
+ }
+}
+
+.dropdownMenu>div:last-child {
+ border-bottom-left-radius: 0.75rem;
+ border-bottom-right-radius: 0.75rem;
+ border-bottom: 2px solid var(--Beige, #EEE8DA);
+
+}
+
+.dropdownItem {
+ display: flex;
+ height: 2.5rem;
+ padding: 0.5rem 1.5rem;
+ width: 100%;
+ border-left: 2px solid var(--Beige, #EEE8DA);
+ border-right: 2px solid var(--Beige, #EEE8DA);
+ background: var(--Light-beige-copy, #F5F2EB);
+ cursor: pointer;
+}
diff --git a/src/components/Dropdown/Dropdown.tsx b/src/components/Dropdown/Dropdown.tsx
new file mode 100644
index 0000000..d2d589d
--- /dev/null
+++ b/src/components/Dropdown/Dropdown.tsx
@@ -0,0 +1,63 @@
+import { useRef, useState, Ref, MouseEvent, MutableRefObject } from "react";
+import { Typography } from "@/components/Typography";
+import Image from "next/image"
+import type { dropdownItem } from "./types/dropdownItem"
+import cx from "classnames";
+
+import styles from "./Dropdown.module.css"
+
+interface Props {
+ items: dropdownItem[]
+ className?: string
+ valueRef: MutableRefObject
+}
+
+const Dropdown = (props: Props) => {
+ const [isOpened, setIsOpened] = useState(false)
+
+ const handleOpen = () => {
+ setIsOpened(!isOpened)
+ }
+
+ const handleSelect = (index: number) => {
+ const dropdownItem = props.items.at(index)?.index
+
+ if (dropdownItem != null) {
+ props.valueRef.current = dropdownItem
+ }
+ }
+
+ return (
+
+
+
+
+ {props.items.map((item: dropdownItem, index: number) => {
+ return (
+
handleSelect(index)}>
+
+ {item.value}
+
+
+ )
+ })}
+
+
+
+ )
+}
+
+export default Dropdown;
diff --git a/src/components/Dropdown/index.tsx b/src/components/Dropdown/index.tsx
new file mode 100644
index 0000000..ade5256
--- /dev/null
+++ b/src/components/Dropdown/index.tsx
@@ -0,0 +1 @@
+export { default as Dropdown } from './Dropdown';
diff --git a/src/components/Dropdown/types/dropdownItem.ts b/src/components/Dropdown/types/dropdownItem.ts
new file mode 100644
index 0000000..da735cb
--- /dev/null
+++ b/src/components/Dropdown/types/dropdownItem.ts
@@ -0,0 +1,6 @@
+export interface dropdownItem {
+ value: string;
+ index: number;
+ selectable?: boolean;
+ selected?: boolean;
+}
diff --git a/src/components/Input/Input.module.css b/src/components/Input/Input.module.css
new file mode 100644
index 0000000..2f32631
--- /dev/null
+++ b/src/components/Input/Input.module.css
@@ -0,0 +1,15 @@
+.input {
+ display: flex;
+ width: 100%;
+ padding: 1rem;
+ height: 3.375rem;
+ align-self: stretch;
+ border-radius: 1rem;
+ border: 1px solid var(--Divider, #CACACA);
+ color: var(--black, #030202);
+ font-size: 1rem;
+ font-style: normal;
+ font-weight: 500;
+ line-height: normal;
+ outline: none;
+}
\ No newline at end of file
diff --git a/src/components/Input/Input.tsx b/src/components/Input/Input.tsx
new file mode 100644
index 0000000..39db162
--- /dev/null
+++ b/src/components/Input/Input.tsx
@@ -0,0 +1,42 @@
+import {
+ ChangeEvent,
+ forwardRef,
+ DetailedHTMLProps,
+ InputHTMLAttributes,
+} from "react";
+import cx from "classnames";
+
+import styles from "./Input.module.css";
+
+interface Props {
+ type: string;
+ required?: boolean;
+ className?: string;
+ onChange?: (e: ChangeEvent) => void;
+ children: string;
+}
+
+const Input = forwardRef<
+ HTMLInputElement,
+ Props &
+ DetailedHTMLProps, HTMLInputElement>
+>(
+ (
+ { type, required = true, className, onChange, children, ...other }: Props,
+ ref
+ ) => {
+ return (
+
+ );
+ }
+);
+
+export default Input;
diff --git a/src/components/Input/index.tsx b/src/components/Input/index.tsx
new file mode 100644
index 0000000..a5f313c
--- /dev/null
+++ b/src/components/Input/index.tsx
@@ -0,0 +1 @@
+export { default as Input } from "./Input";
diff --git a/src/components/Login/LoginPage.tsx b/src/components/Login/LoginPage.tsx
deleted file mode 100644
index 6d4c828..0000000
--- a/src/components/Login/LoginPage.tsx
+++ /dev/null
@@ -1,114 +0,0 @@
-"use client";
-
-import React, { useEffect } from "react";
-import { useRouter } from "next/navigation";
-import { LockOutlined, UserOutlined } from "@ant-design/icons";
-import { Button, Form, Input, message, Typography } from "antd";
-import { useLazyQuery } from "@apollo/client";
-import login from "@/queries/login";
-
-interface Props {
- setToken: (token: string) => void;
-}
-
-const LoginPage = (props: Props) => {
- const [messageApi, contextHolder] = message.useMessage();
- const { Title } = Typography;
- const router = useRouter();
-
- const [loginQuery, { data, error }] = useLazyQuery(login, {
- fetchPolicy: "network-only",
- });
-
- useEffect(() => {
- if (!data?.login) return;
-
- props.setToken(data.login);
- localStorage.setItem("token", data.login);
- router.push("/admin");
- }, [data]);
-
- useEffect(() => {
- if (error) {
- messageApiError();
- }
- }, [error]);
-
- const messageApiError = () => {
- messageApi.open({
- type: "error",
- content: "Zadané údaje nejsou správné!",
- });
- };
-
- const onFinish = (values: { email: string; password: string }) => {
- loginQuery({
- variables: {
- email: values.email,
- password: values.password,
- },
- });
- };
-
- return (
- <>
- {contextHolder}
-
-
-
Vítejte v
-
- Menuroo
-
-
- }
- placeholder="Email"
- size="large"
- />
-
-
- }
- type="password"
- placeholder="Heslo"
- size="large"
- />
-
-
-
-
-
-
-
- >
- );
-};
-
-export default LoginPage;
diff --git a/src/components/LogoHeader/LoginTitle.test.tsx b/src/components/LogoHeader/LoginTitle.test.tsx
new file mode 100644
index 0000000..e0b7d53
--- /dev/null
+++ b/src/components/LogoHeader/LoginTitle.test.tsx
@@ -0,0 +1,14 @@
+import "@testing-library/jest-dom";
+import { render, screen } from "@testing-library/react";
+import LogoHeader from "./LogoHeader";
+
+describe("Login title", () => {
+ it("renders the application title", () => {
+ render();
+
+ const heading = screen.getByRole("heading", { level: 1 });
+
+ expect(heading).toBeInTheDocument();
+ expect(heading).toHaveTextContent("Menuroo");
+ });
+});
diff --git a/src/components/LogoHeader/LogoHeader.module.css b/src/components/LogoHeader/LogoHeader.module.css
new file mode 100644
index 0000000..913d9fb
--- /dev/null
+++ b/src/components/LogoHeader/LogoHeader.module.css
@@ -0,0 +1,29 @@
+.container {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ width: 100%;
+ gap: 0.5rem;
+}
+
+.container > h1 {
+ color: #000;
+ text-align: center;
+ font-family: 'Nunito', sans-serif;
+ font-weight: 900;
+ font-size: 2rem;
+ font-style: normal;
+ line-height: normal;
+}
+
+.container > h2 {
+ color: #000;
+ font-family: "Nunito", sans-serif;
+ font-weight: 900;
+ text-align: center;
+ font-size: 1rem;
+ font-style: normal;
+ line-height: normal;
+}
+
diff --git a/src/components/LogoHeader/LogoHeader.tsx b/src/components/LogoHeader/LogoHeader.tsx
new file mode 100644
index 0000000..e5719e0
--- /dev/null
+++ b/src/components/LogoHeader/LogoHeader.tsx
@@ -0,0 +1,25 @@
+import Image from "next/image";
+import { Typography } from "@/components/Typography";
+
+import styles from "./LogoHeader.module.css";
+
+interface Props {
+ header: string;
+ subheader: string;
+}
+
+const LogoHeader = (props: Props) => {
+ return (
+
+
+
+ {props.header}
+
+
+ {props.subheader}
+
+
+ );
+};
+
+export default LogoHeader;
diff --git a/src/components/LogoHeader/index.tsx b/src/components/LogoHeader/index.tsx
new file mode 100644
index 0000000..901c27d
--- /dev/null
+++ b/src/components/LogoHeader/index.tsx
@@ -0,0 +1 @@
+export { default as LogoHeader } from "./LogoHeader";
diff --git a/src/components/Table/Table.module.css b/src/components/Table/Table.module.css
new file mode 100644
index 0000000..e69de29
diff --git a/src/components/Table/Table.tsx b/src/components/Table/Table.tsx
new file mode 100644
index 0000000..fa7c507
--- /dev/null
+++ b/src/components/Table/Table.tsx
@@ -0,0 +1,41 @@
+type TableDataTypes = string | number | boolean | JSX.Element;
+
+interface Props {
+ headings: Array;
+ data: Array>;
+}
+
+const Table = (props: Props) => {
+ return (
+
+
+
+ {props.headings.map((heading, index) => (
+ |
+ {heading}
+ |
+ ))}
+
+
+
+ {props.data.map((row, index) => (
+
+ {Object.values(row).map((value, index) => (
+ |
+ {value}
+ |
+ ))}
+
+ ))}
+
+
+ );
+};
+
+export default Table;
diff --git a/src/components/Table/index.tsx b/src/components/Table/index.tsx
new file mode 100644
index 0000000..6c9ff96
--- /dev/null
+++ b/src/components/Table/index.tsx
@@ -0,0 +1 @@
+export { default as Table } from "./Table";
diff --git a/src/components/Typography/Typography.module.css b/src/components/Typography/Typography.module.css
new file mode 100644
index 0000000..304a942
--- /dev/null
+++ b/src/components/Typography/Typography.module.css
@@ -0,0 +1,69 @@
+.element {
+ &.light {
+ font-weight: 300;
+ }
+
+ &.normal {
+ font-weight: 600;
+ }
+
+ &.base {
+ font-weight: 500;
+ }
+
+ &.semibold {
+ font-weight: 700;
+ }
+
+ &.semibolder {
+ font-weight: 800;
+ }
+
+ &.bold {
+ font-weight: 900;
+ }
+
+ &.heading {
+ font-size: 1rem;
+
+ &.sm {
+ font-size: 0.75rem;
+ }
+
+ &.smMd {
+ font-size: 1.125rem;
+ }
+
+ &.XLsmMd {
+ font-size: 1.25rem;
+ }
+
+ &.md {
+ font-size: 1.5rem;
+ }
+
+ &.mdLg {
+ font-size: 1.75rem;
+ }
+
+ &.lg {
+ font-size: 2rem;
+ }
+ }
+
+ &.button {
+ font-size: 1rem;
+
+ &.sm {
+ font-size: 0.75rem;
+ }
+
+ &.md {
+ font-size: 1.5rem;
+ }
+
+ &.lg {
+ font-size: 2rem;
+ }
+ }
+}
diff --git a/src/components/Typography/Typography.tsx b/src/components/Typography/Typography.tsx
new file mode 100644
index 0000000..2de6d68
--- /dev/null
+++ b/src/components/Typography/Typography.tsx
@@ -0,0 +1,108 @@
+import {
+ ReactElement,
+ ReactNode,
+ cloneElement,
+ forwardRef,
+ DetailedHTMLProps,
+ ButtonHTMLAttributes,
+ HTMLAttributes,
+} from "react";
+import cx from "classnames";
+
+import styles from "./Typography.module.css";
+
+type Variant = "heading" | "button";
+type Size = "sm" | "smMd" | "XLsmMd" | "md" | "mdLg" | "lg" | "xl";
+type Weight = "light" | "normal" | "base" | "semibold" | "semibolder" | "bold";
+
+interface Props {
+ size?: Size;
+ weight?: Weight;
+ className?: string;
+ children: ReactNode;
+}
+
+const Typography = ({
+ size,
+ weight,
+ variant,
+ className,
+ children,
+}: Props & { children: ReactElement; variant: Variant }) => {
+ const isVariant = (styleVariant: Variant) => variant === styleVariant;
+ const isSize = (styleSize: Size) => size === styleSize;
+ const isWeight = (styleWeight: Weight) => weight === styleWeight;
+
+ return cloneElement(children, {
+ className: cx(
+ styles.element,
+ {
+ [styles.heading]: isVariant("heading"),
+ [styles.button]: isVariant("button"),
+ [styles.sm]: isSize("sm"),
+ [styles.smMd]: isSize("smMd"),
+ [styles.XLsmMd]: isSize("XLsmMd"),
+ [styles.md]: isSize("md"),
+ [styles.mdLg]: isSize("mdLg"),
+ [styles.lg]: isSize("lg"),
+ [styles.xl]: isSize("xl"),
+ [styles.light]: isWeight("light"),
+ [styles.normal]: isWeight("normal"),
+ [styles.base]: isWeight("base"),
+ [styles.semibold]: isWeight("semibold"),
+ [styles.semibolder]: isWeight("semibolder"),
+ [styles.bold]: isWeight("bold"),
+ },
+ className
+ ),
+ });
+};
+
+interface HeadingProps extends Props {
+ Tag: "h1" | "h2" | "h3" | "h4" | "h5" | "h6";
+}
+const TypographyHeading = forwardRef<
+ HTMLHeadingElement,
+ HeadingProps &
+ DetailedHTMLProps, HTMLHeadingElement>
+>(({ Tag, size, weight, className, children, ...other }: HeadingProps, ref) => {
+ return (
+
+
+ {children}
+
+
+ );
+});
+
+const TypographyButton = forwardRef<
+ HTMLButtonElement,
+ Props &
+ DetailedHTMLProps<
+ ButtonHTMLAttributes,
+ HTMLButtonElement
+ >
+>(({ size, weight, className, children, ...other }: Props, ref) => {
+ return (
+
+
+
+ );
+});
+
+Typography.Heading = TypographyHeading;
+Typography.Button = TypographyButton;
+
+export default Typography;
diff --git a/src/components/Typography/index.tsx b/src/components/Typography/index.tsx
new file mode 100644
index 0000000..d9c03aa
--- /dev/null
+++ b/src/components/Typography/index.tsx
@@ -0,0 +1 @@
+export { default as Typography } from "./Typography";
diff --git a/src/lib/dayjs.ts b/src/lib/dayjs.ts
new file mode 100644
index 0000000..f63645e
--- /dev/null
+++ b/src/lib/dayjs.ts
@@ -0,0 +1,8 @@
+import dayjs from "dayjs";
+import "dayjs/locale/cs";
+import utc from "dayjs/plugin/utc";
+
+dayjs.locale("cs");
+dayjs.extend(utc);
+
+export default dayjs;
diff --git a/src/middleware.ts b/src/middleware.ts
new file mode 100644
index 0000000..fe0996a
--- /dev/null
+++ b/src/middleware.ts
@@ -0,0 +1,27 @@
+import { NextRequest, NextResponse } from "next/server";
+
+const middleware = (request: NextRequest) => {
+ if (
+ request.method !== "GET" ||
+ request.nextUrl.pathname.startsWith("/_next/") ||
+ request.nextUrl.pathname.startsWith("/_vercel/")
+ ) {
+ return NextResponse.next();
+ }
+
+ const requestHeaders = new Headers(request.headers);
+
+ if (request?.url) {
+ requestHeaders.set("x-url", request.url);
+ } else {
+ return NextResponse.next();
+ }
+
+ return NextResponse.next({
+ request: {
+ headers: requestHeaders,
+ },
+ });
+};
+
+export default middleware;
diff --git a/src/modules/AdminPage/AdminPage.tsx b/src/modules/AdminPage/AdminPage.tsx
new file mode 100644
index 0000000..5c46e91
--- /dev/null
+++ b/src/modules/AdminPage/AdminPage.tsx
@@ -0,0 +1,27 @@
+"use client";
+
+import React, { useState } from "react";
+import { MenuInterface, DayMenu } from "@/types/MenuInterface";
+import { Table } from "./components/Table";
+import mapMenusToSequencedMonthDays from "./utils/mapMenusToSequencedMonthDays";
+import getMenus from "./actions/getMenus";
+
+interface Props {
+ menusByDate: MenuInterface[];
+}
+
+const AdminPage = (props: Props) => {
+ const [groupedMenus, setGroupedMenus] = useState(
+ mapMenusToSequencedMonthDays(props.menusByDate)
+ );
+
+ const updateMenus = async (unix: number) => {
+ const newMenus = await getMenus(unix);
+ setGroupedMenus(mapMenusToSequencedMonthDays(newMenus, unix));
+ };
+
+ return (
+
+ );
+};
+export default AdminPage;
diff --git a/src/modules/AdminPage/actions/getMenus.ts b/src/modules/AdminPage/actions/getMenus.ts
new file mode 100644
index 0000000..2c81584
--- /dev/null
+++ b/src/modules/AdminPage/actions/getMenus.ts
@@ -0,0 +1,36 @@
+"use server";
+
+import getToken from "@/utils/getToken";
+import getMenusByDate from "@/queries/getMenusByDate";
+import { getClient } from "@/lib/ssrApolloClient";
+import updateMenuInterval from "@/modules/AdminPage/utils/updateMenuInterval";
+
+const getMenus = async (unix?: number) => {
+ try {
+ const viewedDatesUnix = updateMenuInterval(unix);
+
+ const { data: menusByDate } = await getClient().query({
+ query: getMenusByDate,
+ variables: {
+ dateFrom: viewedDatesUnix[0],
+ dateTo: viewedDatesUnix[1],
+ },
+ context: {
+ headers: {
+ Authorization: getToken(),
+ },
+ fetchOptions: {
+ next: { tags: ["menusByDate"] },
+ },
+ },
+ fetchPolicy: "network-only",
+ });
+
+ return menusByDate.getMenusByDate ?? [];
+ } catch (error) {
+ return [];
+ }
+};
+
+export default getMenus;
+
diff --git a/src/modules/AdminPage/components/AdminPageContent/AdminPageContent.module.css b/src/modules/AdminPage/components/AdminPageContent/AdminPageContent.module.css
new file mode 100644
index 0000000..a472b62
--- /dev/null
+++ b/src/modules/AdminPage/components/AdminPageContent/AdminPageContent.module.css
@@ -0,0 +1,4 @@
+.container {
+ width: 100%;
+ height: 100%;
+}
\ No newline at end of file
diff --git a/src/components/AdminPage/AdminPage.tsx b/src/modules/AdminPage/components/AdminPageContent/AdminPageContent.tsx
similarity index 62%
rename from src/components/AdminPage/AdminPage.tsx
rename to src/modules/AdminPage/components/AdminPageContent/AdminPageContent.tsx
index d345a05..53257ec 100644
--- a/src/components/AdminPage/AdminPage.tsx
+++ b/src/modules/AdminPage/components/AdminPageContent/AdminPageContent.tsx
@@ -3,31 +3,33 @@
import React, { useEffect, useState } from "react";
import { useLazyQuery } from "@apollo/client";
import { useRouter } from "next/navigation";
-import { Typography, Calendar } from "antd";
+import { Calendar } from "antd";
import type { Dayjs } from "dayjs";
-import dayjs from "dayjs";
+import dayjs from "@/lib/dayjs";
import utc from "dayjs/plugin/utc";
import pickerLocale from "@/constants/PickerLocale";
import getMenusByDate from "@/queries/getMenusByDate";
import { MenuInterface } from "@/types/MenuInterface";
+import styles from "./AdminPageContent.module.css";
+
interface Props {
token: string;
+ menusByDate: MenuInterface[];
}
-const AdminPage = (props: Props) => {
- dayjs.extend(utc);
+const AdminPageContent = (props: Props) => {
const [menuMap, setMenuMap] = useState
- {menuByDate.loading && }
);
diff --git a/src/components/Layout/constants.ts b/src/modules/Layout/constants.ts
similarity index 100%
rename from src/components/Layout/constants.ts
rename to src/modules/Layout/constants.ts
diff --git a/src/components/LunchItem/LunchItem.tsx b/src/modules/LunchItem/LunchItem.tsx
similarity index 100%
rename from src/components/LunchItem/LunchItem.tsx
rename to src/modules/LunchItem/LunchItem.tsx
diff --git a/src/components/LunchOrderTable.tsx b/src/modules/LunchOrderTable.tsx
similarity index 100%
rename from src/components/LunchOrderTable.tsx
rename to src/modules/LunchOrderTable.tsx
diff --git a/src/components/MenuItem/AutoCompleteInput.tsx b/src/modules/MenuItem/AutoCompleteInput.tsx
similarity index 100%
rename from src/components/MenuItem/AutoCompleteInput.tsx
rename to src/modules/MenuItem/AutoCompleteInput.tsx
diff --git a/src/components/MenuItem/MenuItem.tsx b/src/modules/MenuItem/MenuItem.tsx
similarity index 96%
rename from src/components/MenuItem/MenuItem.tsx
rename to src/modules/MenuItem/MenuItem.tsx
index c335824..5687148 100644
--- a/src/components/MenuItem/MenuItem.tsx
+++ b/src/modules/MenuItem/MenuItem.tsx
@@ -55,7 +55,7 @@ const MenuItem = ({
}, [menu]);
useEffect(() => {
- const updatedMenu: MenuInterface[] = (menu ?? []).map((item) => {
+ const updatedMenu: any[] = (menu ?? []).map((item) => {
if (item.key === index) {
return { id: item.id, key: index, level, meal, soup, drink, order };
}
@@ -66,7 +66,7 @@ const MenuItem = ({
}, [meal, soup, drink, level, order]);
const handleDelete = () => {
- const updatedMenu: MenuInterface[] = (menu ?? []).filter(
+ const updatedMenu: any[] = (menu ?? []).filter(
(item) => item.key !== index
);
diff --git a/src/modules/MenuOrdersPage/MenuOrdersPage.module.css b/src/modules/MenuOrdersPage/MenuOrdersPage.module.css
new file mode 100644
index 0000000..c676d50
--- /dev/null
+++ b/src/modules/MenuOrdersPage/MenuOrdersPage.module.css
@@ -0,0 +1,11 @@
+.container {
+ display: flex;
+ flex-direction: column;
+ gap: 1rem;
+}
+
+.boxWrapper {
+ display: flex;
+ flex-direction: column;
+ gap: 2.5rem;
+}
\ No newline at end of file
diff --git a/src/modules/MenuOrdersPage/MenuOrdersPage.tsx b/src/modules/MenuOrdersPage/MenuOrdersPage.tsx
new file mode 100644
index 0000000..64ddd8a
--- /dev/null
+++ b/src/modules/MenuOrdersPage/MenuOrdersPage.tsx
@@ -0,0 +1,29 @@
+"use client";
+
+import { Typography } from "@/components/Typography";
+import { MenuOrdersInterface } from "./types/MenuOrders";
+import { DayBox } from "./components/DayBox";
+
+import styles from "./MenuOrdersPage.module.css";
+
+interface Props {
+ menuOrders: MenuOrdersInterface[];
+}
+
+const MenuOrdersPage = (props: Props) => {
+ console.log(props.menuOrders);
+ return (
+
+
+ Objednávky
+
+
+ {props.menuOrders.map((day: MenuOrdersInterface) => (
+
+ ))}
+
+
+ );
+};
+
+export default MenuOrdersPage;
diff --git a/src/modules/MenuOrdersPage/actions/getOrders.ts b/src/modules/MenuOrdersPage/actions/getOrders.ts
new file mode 100644
index 0000000..9c8edfc
--- /dev/null
+++ b/src/modules/MenuOrdersPage/actions/getOrders.ts
@@ -0,0 +1,34 @@
+"use server";
+
+import getToken from "@/utils/getToken";
+import adminGetMenuOrders from "@/queries/adminGetMenuOrders";
+import dayjs from "@/lib/dayjs";
+import { getClient } from "@/lib/ssrApolloClient";
+
+const getMenuOrders = async (unix?: number) => {
+ // TODO: add dateFrom and dateTo
+ try {
+ const { data: getMenuOrders } = await getClient().query({
+ query: adminGetMenuOrders,
+ variables: {
+ dateFrom: 0,
+ dateTo: dayjs().utc().endOf("day").unix(),
+ },
+ context: {
+ headers: {
+ Authorization: getToken(),
+ },
+ fetchOptions: {
+ next: { tags: ["menusByDate"] },
+ },
+ },
+ fetchPolicy: "network-only",
+ });
+
+ return getMenuOrders.adminGetMenuOrders ?? [];
+ } catch (error) {
+ return [];
+ }
+};
+
+export default getMenuOrders;
diff --git a/src/modules/MenuOrdersPage/components/DayBox/DayBox.module.css b/src/modules/MenuOrdersPage/components/DayBox/DayBox.module.css
new file mode 100644
index 0000000..83c1e06
--- /dev/null
+++ b/src/modules/MenuOrdersPage/components/DayBox/DayBox.module.css
@@ -0,0 +1,16 @@
+.container {
+ height: fit-content;
+ display: flex;
+ width: 55.375rem;
+ padding: 2rem 3rem 4rem 3rem;
+ flex-direction: column;
+ align-items: flex-start;
+ gap: 1.5rem;
+ border-radius: 1rem;
+ border: 1px solid var(--Beige, #EEE8DA);
+ background: var(--beige-light, #F5F2EB);
+}
+
+.header {
+
+}
\ No newline at end of file
diff --git a/src/modules/MenuOrdersPage/components/DayBox/DayBox.tsx b/src/modules/MenuOrdersPage/components/DayBox/DayBox.tsx
new file mode 100644
index 0000000..238b189
--- /dev/null
+++ b/src/modules/MenuOrdersPage/components/DayBox/DayBox.tsx
@@ -0,0 +1,35 @@
+import { Typography } from "@/components/Typography";
+import dayjs from "@/lib/dayjs";
+import { MenuOrdersInterface } from "../../types/MenuOrders";
+import styles from "./DayBox.module.css";
+
+interface Props {
+ data: MenuOrdersInterface;
+}
+
+const DayBox = (props: Props) => {
+ return (
+
+
+
+ {dayjs.unix(props.data.date).utc().format("DD.MM.YYYY")}
+
+
+
+
+ Polévky
+
+ {props.data.soup}
+
+
+
+ Hlavní jídla
+
+ {props.data.meal}
+
+
+
+ );
+};
+
+export default DayBox;
diff --git a/src/modules/MenuOrdersPage/components/DayBox/index.tsx b/src/modules/MenuOrdersPage/components/DayBox/index.tsx
new file mode 100644
index 0000000..77f561e
--- /dev/null
+++ b/src/modules/MenuOrdersPage/components/DayBox/index.tsx
@@ -0,0 +1 @@
+export { default as DayBox } from "./DayBox";
diff --git a/src/modules/MenuOrdersPage/types/MenuOrders.ts b/src/modules/MenuOrdersPage/types/MenuOrders.ts
new file mode 100644
index 0000000..cc4cb4a
--- /dev/null
+++ b/src/modules/MenuOrdersPage/types/MenuOrders.ts
@@ -0,0 +1,9 @@
+export interface MenuOrdersInterface {
+ id: string;
+ date: number;
+ meal: string;
+ drink: string;
+ soup: string;
+ Order: number;
+ Count: number;
+}
diff --git a/src/components/OrderItem.tsx b/src/modules/OrderItem.tsx
similarity index 93%
rename from src/components/OrderItem.tsx
rename to src/modules/OrderItem.tsx
index dfd8ca8..6a794dd 100644
--- a/src/components/OrderItem.tsx
+++ b/src/modules/OrderItem.tsx
@@ -1,7 +1,7 @@
"use client";
import React from "react";
-import type { LunchOrder } from "@/types/LunchOrder";
+import type { WaiterOrder } from "./WaiterOrdersPage/types/waiterOrder";
import dayjs from "dayjs";
interface ColInterface {
@@ -15,7 +15,7 @@ const OrderItem = ({
index,
columns,
}: {
- order: LunchOrder;
+ order: WaiterOrder;
index: number;
columns: ColInterface[];
}) => {
diff --git a/src/components/PageTitle.tsx b/src/modules/PageTitle.tsx
similarity index 100%
rename from src/components/PageTitle.tsx
rename to src/modules/PageTitle.tsx
diff --git a/src/components/QueuePage/QueuePage.tsx b/src/modules/QueuePage/QueuePage.tsx
similarity index 92%
rename from src/components/QueuePage/QueuePage.tsx
rename to src/modules/QueuePage/QueuePage.tsx
index 33d7d96..1340115 100644
--- a/src/components/QueuePage/QueuePage.tsx
+++ b/src/modules/QueuePage/QueuePage.tsx
@@ -2,10 +2,10 @@
import React, { useEffect, useState } from "react";
import { useLazyQuery } from "@apollo/client";
-import PageTitle from "@/components/PageTitle";
-import LunchOrderTable from "@/components/LunchOrderTable";
+import PageTitle from "@/modules/PageTitle";
+import LunchOrderTable from "@/modules/LunchOrderTable";
import { Button, DatePicker } from "antd";
-import RefreshButton from "@/components/RefreshButton";
+import RefreshButton from "@/modules/RefreshButton";
import dayjs from "dayjs";
import utc from "dayjs/plugin/utc";
import pickerLocale from "@/constants/PickerLocale";
diff --git a/src/components/RefreshButton.tsx b/src/modules/RefreshButton.tsx
similarity index 100%
rename from src/components/RefreshButton.tsx
rename to src/modules/RefreshButton.tsx
diff --git a/src/modules/Settings/SettingsPage.module.css b/src/modules/Settings/SettingsPage.module.css
new file mode 100644
index 0000000..e69de29
diff --git a/src/modules/Settings/SettingsPage.tsx b/src/modules/Settings/SettingsPage.tsx
new file mode 100644
index 0000000..cac493c
--- /dev/null
+++ b/src/modules/Settings/SettingsPage.tsx
@@ -0,0 +1,32 @@
+import { Table } from "./components/Table";
+
+import styles from "./SettingsPage.module.css";
+
+export interface SettingItem {
+ rowTitle: string;
+}
+
+const Settings = () => {
+ const settingsItems: SettingItem[] = [
+ {
+ rowTitle: "Uživatelé restaurace",
+ },
+ {
+ rowTitle: "Nápoje",
+ },
+ {
+ rowTitle: "Skupiny strávníků",
+ },
+ {
+ rowTitle: "Cenové hladiny",
+ },
+ ];
+
+ return (
+
+ );
+};
+
+export default Settings;
diff --git a/src/modules/Settings/components/Table/Table.module.css b/src/modules/Settings/components/Table/Table.module.css
new file mode 100644
index 0000000..50b2021
--- /dev/null
+++ b/src/modules/Settings/components/Table/Table.module.css
@@ -0,0 +1,14 @@
+.container {
+ width: 100%;
+ max-width: 41.875rem;
+ max-height: 45rem;
+ display: flex;
+ flex-direction: column;
+ border-radius: 1rem;
+ border: 1px solid var(--Beige, #EEE8DA);
+ overflow-y: scroll;
+}
+
+.container::-webkit-scrollbar {
+ display: none;
+}
\ No newline at end of file
diff --git a/src/modules/Settings/components/Table/Table.tsx b/src/modules/Settings/components/Table/Table.tsx
new file mode 100644
index 0000000..9bb3e9d
--- /dev/null
+++ b/src/modules/Settings/components/Table/Table.tsx
@@ -0,0 +1,21 @@
+import { Row } from "./components";
+import type { SettingItem } from "../../SettingsPage";
+
+import styles from "./Table.module.css";
+
+interface Props {
+ data: SettingItem[];
+}
+const Table = (props: Props) => {
+ return (
+
+ {props.data.map((item: SettingItem, index: number) => (
+
+ {item}
+
+ ))}
+
+ );
+};
+
+export default Table;
diff --git a/src/modules/Settings/components/Table/components/Row.module.css b/src/modules/Settings/components/Table/components/Row.module.css
new file mode 100644
index 0000000..817aa59
--- /dev/null
+++ b/src/modules/Settings/components/Table/components/Row.module.css
@@ -0,0 +1,31 @@
+.row {
+ display: flex;
+ height: 5.625rem;
+ padding: 0 3rem 0 3rem;
+ justify-content: space-between;
+ align-items: center;
+
+ &.beigeBackground {
+ background: #F5F2EB;
+ }
+}
+
+
+.editRowButton {
+ outline: none;
+ border: none;
+ background: none;
+ cursor: pointer;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 1rem;
+ text-decoration: underline;
+}
+
+.rightArrow {
+ width: 0.5625rem;
+ height: 0.9375rem;
+ position: relative;
+}
+
diff --git a/src/modules/Settings/components/Table/components/Row.tsx b/src/modules/Settings/components/Table/components/Row.tsx
new file mode 100644
index 0000000..c7babf3
--- /dev/null
+++ b/src/modules/Settings/components/Table/components/Row.tsx
@@ -0,0 +1,35 @@
+import Image from "next/image";
+import { Typography } from "@/components/Typography";
+import type { SettingItem } from "@/modules/Settings/SettingsPage";
+import cx from "classnames";
+
+import styles from "./Row.module.css";
+
+interface Props {
+ children: SettingItem;
+ isEven: boolean;
+}
+
+const Row = (props: Props) => {
+ return (
+
+
+ {props.children.rowTitle}
+
+
+
+ );
+};
+
+export default Row;
diff --git a/src/modules/Settings/components/Table/components/index.tsx b/src/modules/Settings/components/Table/components/index.tsx
new file mode 100644
index 0000000..9abd55d
--- /dev/null
+++ b/src/modules/Settings/components/Table/components/index.tsx
@@ -0,0 +1 @@
+export { default as Row } from "./Row";
diff --git a/src/modules/Settings/components/Table/index.tsx b/src/modules/Settings/components/Table/index.tsx
new file mode 100644
index 0000000..6c9ff96
--- /dev/null
+++ b/src/modules/Settings/components/Table/index.tsx
@@ -0,0 +1 @@
+export { default as Table } from "./Table";
diff --git a/src/components/Settings/components/PriceLevel/PriceLevel.tsx b/src/modules/SettingsOld/components/PriceLevel/PriceLevel.tsx
similarity index 97%
rename from src/components/Settings/components/PriceLevel/PriceLevel.tsx
rename to src/modules/SettingsOld/components/PriceLevel/PriceLevel.tsx
index 93be87d..36d27df 100644
--- a/src/components/Settings/components/PriceLevel/PriceLevel.tsx
+++ b/src/modules/SettingsOld/components/PriceLevel/PriceLevel.tsx
@@ -16,9 +16,9 @@ import adminCreateFoodPriceLvl from "@/queries/adminCreateFoodPriceLvl";
import adminDeleteFoodPriceLvl from "@/queries/adminDeleteFoodPriceLvl";
import adminUpdateFoodPriceLvl from "@/queries/adminUpdateFoodPriceLvl";
import { tableSortLocale } from "@/constants/PickerLocale";
+import revalidate from "@/utils/revalidate";
interface Props {
- revalidateData: () => void;
data: PriceLevelInterface[];
token: string;
}
@@ -76,7 +76,7 @@ const PriceLevel = (props: Props) => {
},
});
- props.revalidateData();
+ revalidate("priceLevels");
};
const deleteModalSubmitCallback = () => {
@@ -95,7 +95,7 @@ const PriceLevel = (props: Props) => {
},
});
- props.revalidateData();
+ revalidate("priceLevels");
};
const updateModalSubmitCallback = (data: PriceLevelInterface) => {
@@ -117,7 +117,7 @@ const PriceLevel = (props: Props) => {
},
});
- props.revalidateData();
+ revalidate("priceLevels");
};
return (
diff --git a/src/components/Settings/components/PriceLevelGroup/PriceLevelGroup.tsx b/src/modules/SettingsOld/components/PriceLevelGroup/PriceLevelGroup.tsx
similarity index 98%
rename from src/components/Settings/components/PriceLevelGroup/PriceLevelGroup.tsx
rename to src/modules/SettingsOld/components/PriceLevelGroup/PriceLevelGroup.tsx
index d12d370..d65d6cd 100644
--- a/src/components/Settings/components/PriceLevelGroup/PriceLevelGroup.tsx
+++ b/src/modules/SettingsOld/components/PriceLevelGroup/PriceLevelGroup.tsx
@@ -17,7 +17,7 @@ import type {
CreatePriceTypeGroupInterface,
GetPriceLevelGroupInterface,
MutatedPriceLevelGroupInterface,
-} from "@/components/Settings/types";
+} from "@/modules/Settings/types";
import adminCreatePriceLvlGroup from "@/queries/adminCreatePriceLvlGroup";
import adminDeletePriceLvlGroup from "@/queries/adminDeletePriceLvlGroup";
import adminUpdatePriceLvlGroup from "@/queries/adminUpdatePriceLvlGroup";
@@ -29,13 +29,13 @@ import pickerLocale from "@/constants/PickerLocale";
import { PriceLevelInterface } from "@/types/PriceLevelInterface";
import { tableSortLocale } from "@/constants/PickerLocale";
import filterSelectOptions from "@/utils/filterSelectOption";
+import revalidate from "@/utils/revalidate";
interface Props {
data: GetPriceLevelGroupInterface[];
priceLevels: PriceLevelInterface[];
userGroups: PriceLevelInterface[];
token: string;
- revalidateData: () => void;
}
const PriceLevelGroup = (props: Props) => {
@@ -149,7 +149,7 @@ const PriceLevelGroup = (props: Props) => {
},
});
- props.revalidateData();
+ revalidate("priceLvlGroups");
};
const deleteModalSubmitCallback = () => {
@@ -168,7 +168,7 @@ const PriceLevelGroup = (props: Props) => {
},
});
- props.revalidateData();
+ revalidate("priceLvlGroups");
};
const updateModalSubmitCallback = (data: MutatedPriceLevelGroupInterface) => {
@@ -216,7 +216,7 @@ const PriceLevelGroup = (props: Props) => {
},
});
- props.revalidateData();
+ revalidate("priceLvlGroups");
};
const mutateDataToSelect = (data: PriceLevelInterface[]) => {
diff --git a/src/components/Settings/components/UserGroup/EmailHandles.tsx b/src/modules/SettingsOld/components/UserGroup/EmailHandles.tsx
similarity index 100%
rename from src/components/Settings/components/UserGroup/EmailHandles.tsx
rename to src/modules/SettingsOld/components/UserGroup/EmailHandles.tsx
diff --git a/src/components/Settings/components/UserGroup/UserGroup.tsx b/src/modules/SettingsOld/components/UserGroup/UserGroup.tsx
similarity index 97%
rename from src/components/Settings/components/UserGroup/UserGroup.tsx
rename to src/modules/SettingsOld/components/UserGroup/UserGroup.tsx
index 65aee4b..b25c71b 100644
--- a/src/components/Settings/components/UserGroup/UserGroup.tsx
+++ b/src/modules/SettingsOld/components/UserGroup/UserGroup.tsx
@@ -17,13 +17,13 @@ import {
CreateUserGroupInterface,
EmailHandleInterface,
UserGroupInterface,
-} from "@/components/Settings/types";
+} from "@/modules/Settings/types";
import EmailHandles from "./EmailHandles";
import { UserGroupContextProvider } from "./UserGroupContext";
import { tableSortLocale } from "@/constants/PickerLocale";
+import revalidate from "@/utils/revalidate";
interface Props {
- revalidateData: () => void;
data: UserGroupInterface[];
token: string;
}
@@ -121,7 +121,7 @@ const UserGroup = (props: Props) => {
});
setEditPriceModalOpen(false);
- props.revalidateData();
+ revalidate("userGroups");
};
const createModalSubmitCallback = (data: CreateUserGroupInterface) => {
@@ -136,7 +136,7 @@ const UserGroup = (props: Props) => {
},
});
- props.revalidateData();
+ revalidate("userGroups");
};
const deleteModalSubmitCallback = () => {
@@ -155,7 +155,7 @@ const UserGroup = (props: Props) => {
},
});
- props.revalidateData();
+ revalidate("userGroups");
};
const updateModalSubmitCallback = (data: UserGroupInterface) => {
@@ -189,7 +189,7 @@ const UserGroup = (props: Props) => {
},
});
- props.revalidateData();
+ revalidate("userGroups");
};
const memoizedContextValue = useMemo(() => {
diff --git a/src/components/Settings/components/UserGroup/UserGroupContext.tsx b/src/modules/SettingsOld/components/UserGroup/UserGroupContext.tsx
similarity index 96%
rename from src/components/Settings/components/UserGroup/UserGroupContext.tsx
rename to src/modules/SettingsOld/components/UserGroup/UserGroupContext.tsx
index 8cc6bca..72fda76 100644
--- a/src/components/Settings/components/UserGroup/UserGroupContext.tsx
+++ b/src/modules/SettingsOld/components/UserGroup/UserGroupContext.tsx
@@ -14,7 +14,7 @@ interface UserGroupContextValue {
const UserGroupContext = createContext({
emailHandles: [],
- setEmailHandles: () => {},
+ setEmailHandles: () => { },
});
export const useUserGroupContext = () => {
diff --git a/src/components/Settings/components/index.ts b/src/modules/SettingsOld/components/index.ts
similarity index 100%
rename from src/components/Settings/components/index.ts
rename to src/modules/SettingsOld/components/index.ts
diff --git a/src/components/Settings/components/modals/ModifyModal/ModifyModal.tsx b/src/modules/SettingsOld/components/modals/ModifyModal/ModifyModal.tsx
similarity index 100%
rename from src/components/Settings/components/modals/ModifyModal/ModifyModal.tsx
rename to src/modules/SettingsOld/components/modals/ModifyModal/ModifyModal.tsx
diff --git a/src/components/Settings/types.ts b/src/modules/SettingsOld/types.ts
similarity index 100%
rename from src/components/Settings/types.ts
rename to src/modules/SettingsOld/types.ts
diff --git a/src/components/Settings/utils.ts b/src/modules/SettingsOld/utils.ts
similarity index 100%
rename from src/components/Settings/utils.ts
rename to src/modules/SettingsOld/utils.ts
diff --git a/src/components/Sidebar/Sidebar.tsx b/src/modules/Sidebar/Sidebar.tsx
similarity index 100%
rename from src/components/Sidebar/Sidebar.tsx
rename to src/modules/Sidebar/Sidebar.tsx
diff --git a/src/components/Statistics/StatisticsPage.tsx b/src/modules/Statistics/StatisticsPage.tsx
similarity index 98%
rename from src/components/Statistics/StatisticsPage.tsx
rename to src/modules/Statistics/StatisticsPage.tsx
index 6412f89..c82f924 100644
--- a/src/components/Statistics/StatisticsPage.tsx
+++ b/src/modules/Statistics/StatisticsPage.tsx
@@ -12,7 +12,7 @@ import type {
ValueKeyInterface,
} from "@/types/OrdersInterface";
import pickerLocale from "@/constants/PickerLocale";
-import { StatisticsTable } from "@/components/Statistics";
+import { StatisticsTable } from "@/modules/Statistics";
import getTime from "@/lib/getTime";
interface Props {
diff --git a/src/components/Statistics/Table.tsx b/src/modules/Statistics/Table.tsx
similarity index 100%
rename from src/components/Statistics/Table.tsx
rename to src/modules/Statistics/Table.tsx
diff --git a/src/components/Statistics/index.ts b/src/modules/Statistics/index.ts
similarity index 100%
rename from src/components/Statistics/index.ts
rename to src/modules/Statistics/index.ts
diff --git a/src/modules/WaiterOrdersPage/WaiterOrdersPage.module.css b/src/modules/WaiterOrdersPage/WaiterOrdersPage.module.css
new file mode 100644
index 0000000..87de2ea
--- /dev/null
+++ b/src/modules/WaiterOrdersPage/WaiterOrdersPage.module.css
@@ -0,0 +1,5 @@
+.container {
+ display: flex;
+ flex-direction: column;
+ gap: 1rem;
+}
\ No newline at end of file
diff --git a/src/modules/WaiterOrdersPage/WaiterOrdersPage.tsx b/src/modules/WaiterOrdersPage/WaiterOrdersPage.tsx
new file mode 100644
index 0000000..8c2fe9a
--- /dev/null
+++ b/src/modules/WaiterOrdersPage/WaiterOrdersPage.tsx
@@ -0,0 +1,42 @@
+"use client";
+
+import { useState, useRef } from "react";
+import { Typography } from "@/components/Typography";
+import { Table } from "./components/Table";
+import { Footer } from "./components/Footer";
+import dayjs from "@/lib/dayjs";
+import transformWaiterOrders from "./utils/transformWaiterOrders";
+import type { WaiterOrder } from "./types/waiterOrder";
+import getWaiterOrders from "./actions/getWaiterOrders";
+
+import styles from "./WaiterOrdersPage.module.css";
+
+interface Props {
+ waiterOrders: WaiterOrder[];
+}
+
+const WaiterOrdersPage = (props: Props) => {
+ const initialSSRData = transformWaiterOrders(props.waiterOrders);
+
+ const [waiterOrders, setWaiterOrders] =
+ useState(initialSSRData);
+
+ const ordersDateRef = useRef(dayjs().utc().startOf("day").unix());
+
+ const handleOrdersUpdate = async () => {
+ const newOrders = await getWaiterOrders(1);
+ setWaiterOrders(transformWaiterOrders(newOrders));
+ };
+
+ return (
+
+ );
+};
+
+export default WaiterOrdersPage;
diff --git a/src/modules/WaiterOrdersPage/actions/getWaiterOrders.ts b/src/modules/WaiterOrdersPage/actions/getWaiterOrders.ts
new file mode 100644
index 0000000..7196d30
--- /dev/null
+++ b/src/modules/WaiterOrdersPage/actions/getWaiterOrders.ts
@@ -0,0 +1,33 @@
+"use server";
+
+import dayjs from "@/lib/dayjs"
+import getToken from "@/utils/getToken";
+import waiterOrders from "@/queries/waiterOrders";
+import { getClient } from "@/lib/ssrApolloClient";
+
+const getWaiterOrders = async (unix?: number) => {
+ try {
+ const { data: getWaiterOrders } = await getClient().query({
+ query: waiterOrders,
+ variables: {
+ date: unix ? unix : dayjs().utc().startOf("day").unix(),
+ },
+ context: {
+ headers: {
+ Authorization: getToken(),
+ },
+ fetchOptions: {
+ next: { tags: ["waiterOrders"] },
+ },
+ },
+ fetchPolicy: "network-only",
+ });
+
+ return getWaiterOrders.waiterOrders ?? [];
+ } catch (error) {
+ return [];
+ }
+};
+
+export default getWaiterOrders;
+
diff --git a/src/modules/WaiterOrdersPage/components/Footer/Footer.module.css b/src/modules/WaiterOrdersPage/components/Footer/Footer.module.css
new file mode 100644
index 0000000..b60b2ad
--- /dev/null
+++ b/src/modules/WaiterOrdersPage/components/Footer/Footer.module.css
@@ -0,0 +1,20 @@
+.container {
+ width: 100%;
+ display: flex;
+ margin-top: 1rem;
+ justify-content: end;
+ gap: 1.25rem;
+}
+
+.button {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ padding: 1rem 1.4375rem;
+ border-radius: 1rem;
+ gap: 0.5rem;
+ cursor: pointer;
+ border: 1px solid var(--red, #D51F2C);
+ background-color: var(--red, #D51F2C);
+ color: var(--white, #FFF);
+}
\ No newline at end of file
diff --git a/src/modules/WaiterOrdersPage/components/Footer/Footer.tsx b/src/modules/WaiterOrdersPage/components/Footer/Footer.tsx
new file mode 100644
index 0000000..6bbaeef
--- /dev/null
+++ b/src/modules/WaiterOrdersPage/components/Footer/Footer.tsx
@@ -0,0 +1,29 @@
+"use client";
+
+import { MutableRefObject } from "react";
+import { Typography } from "@/components/Typography";
+import cx from "classnames";
+
+import styles from "./Footer.module.css";
+
+interface Props {
+ refreshOrders: () => void;
+ orderDateRef: MutableRefObject;
+}
+
+const Footer = (props: Props) => {
+ return (
+
+
+ Obnovit seznam
+
+
+ );
+};
+
+export default Footer;
diff --git a/src/modules/WaiterOrdersPage/components/Footer/index.tsx b/src/modules/WaiterOrdersPage/components/Footer/index.tsx
new file mode 100644
index 0000000..090a49a
--- /dev/null
+++ b/src/modules/WaiterOrdersPage/components/Footer/index.tsx
@@ -0,0 +1 @@
+export { default as Footer } from "./Footer";
diff --git a/src/modules/WaiterOrdersPage/components/Table/Table.module.css b/src/modules/WaiterOrdersPage/components/Table/Table.module.css
new file mode 100644
index 0000000..55da7da
--- /dev/null
+++ b/src/modules/WaiterOrdersPage/components/Table/Table.module.css
@@ -0,0 +1,13 @@
+.container {
+ width: 100%;
+ max-height: 45rem;
+ display: flex;
+ flex-direction: column;
+ border-radius: 1rem;
+ border: 1px solid var(--Beige, #EEE8DA);
+ overflow-y: scroll;
+}
+
+.container::-webkit-scrollbar {
+ display: none;
+}
\ No newline at end of file
diff --git a/src/modules/WaiterOrdersPage/components/Table/Table.tsx b/src/modules/WaiterOrdersPage/components/Table/Table.tsx
new file mode 100644
index 0000000..27938ef
--- /dev/null
+++ b/src/modules/WaiterOrdersPage/components/Table/Table.tsx
@@ -0,0 +1,19 @@
+import { Row } from "./components/Row";
+import { WaiterOrder } from "../../types/waiterOrder";
+import styles from "./Table.module.css";
+
+interface Props {
+ data: WaiterOrder[];
+}
+
+const Table = (props: Props) => {
+ return (
+
+ {props.data.map((row: WaiterOrder, index: number) => (
+
+ ))}
+
+ );
+};
+
+export default Table;
diff --git a/src/modules/WaiterOrdersPage/components/Table/components/Row/Row.module.css b/src/modules/WaiterOrdersPage/components/Table/components/Row/Row.module.css
new file mode 100644
index 0000000..7eabb4d
--- /dev/null
+++ b/src/modules/WaiterOrdersPage/components/Table/components/Row/Row.module.css
@@ -0,0 +1,10 @@
+.row {
+ display: flex;
+ height: 7.5rem;
+ padding: 2rem 2.5625rem 1.625rem 3rem;
+ gap: 6rem;
+
+ &.beigeBackground {
+ background: #F5F2EB;
+ }
+}
diff --git a/src/modules/WaiterOrdersPage/components/Table/components/Row/Row.tsx b/src/modules/WaiterOrdersPage/components/Table/components/Row/Row.tsx
new file mode 100644
index 0000000..2150bb2
--- /dev/null
+++ b/src/modules/WaiterOrdersPage/components/Table/components/Row/Row.tsx
@@ -0,0 +1,23 @@
+import { WaiterOrder } from "@/modules/WaiterOrdersPage/types/waiterOrder";
+import dayjs from "@/lib/dayjs";
+import cx from "classnames";
+
+import styles from "./Row.module.css";
+
+interface Props {
+ rowData: WaiterOrder;
+ oddRow: boolean;
+}
+const Row = (props: Props) => {
+ return (
+
+
+
{props.rowData.name}
+
{dayjs.unix(props.rowData.date).utc().format("HH:MM")}
+
+
{props.rowData.meal}
+
+ );
+};
+
+export default Row;
diff --git a/src/modules/WaiterOrdersPage/components/Table/components/Row/index.tsx b/src/modules/WaiterOrdersPage/components/Table/components/Row/index.tsx
new file mode 100644
index 0000000..9abd55d
--- /dev/null
+++ b/src/modules/WaiterOrdersPage/components/Table/components/Row/index.tsx
@@ -0,0 +1 @@
+export { default as Row } from "./Row";
diff --git a/src/modules/WaiterOrdersPage/components/Table/index.tsx b/src/modules/WaiterOrdersPage/components/Table/index.tsx
new file mode 100644
index 0000000..6c9ff96
--- /dev/null
+++ b/src/modules/WaiterOrdersPage/components/Table/index.tsx
@@ -0,0 +1 @@
+export { default as Table } from "./Table";
diff --git a/src/modules/WaiterOrdersPage/types/waiterOrder.ts b/src/modules/WaiterOrdersPage/types/waiterOrder.ts
new file mode 100644
index 0000000..cef09bb
--- /dev/null
+++ b/src/modules/WaiterOrdersPage/types/waiterOrder.ts
@@ -0,0 +1,7 @@
+export interface WaiterOrder {
+ orderId: string;
+ date: number;
+ meal: string;
+ name: string;
+ order: number;
+}
diff --git a/src/modules/WaiterOrdersPage/utils/transformWaiterOrders.ts b/src/modules/WaiterOrdersPage/utils/transformWaiterOrders.ts
new file mode 100644
index 0000000..357d837
--- /dev/null
+++ b/src/modules/WaiterOrdersPage/utils/transformWaiterOrders.ts
@@ -0,0 +1,14 @@
+import { WaiterOrder } from "../types/waiterOrder";
+
+const transformWaiterOrders = (waiterOrders: WaiterOrder[]) =>
+ waiterOrders.map((order) => {
+ return {
+ name: order.name,
+ date: order.date,
+ orderId: order.orderId,
+ meal: order.meal,
+ order: order.order,
+ };
+ });
+
+export default transformWaiterOrders;
diff --git a/src/modules/login/components/Footer/Footer.module.css b/src/modules/login/components/Footer/Footer.module.css
new file mode 100644
index 0000000..5c1b191
--- /dev/null
+++ b/src/modules/login/components/Footer/Footer.module.css
@@ -0,0 +1,20 @@
+.container {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 1rem;
+ width: 100%;
+}
+
+.divider {
+ width: 16.5rem;
+ height: 0.0625rem;
+ background: var(--Divider, #CACACA);
+}
+
+.menurooLink {
+ color: var(--red, #D51F2C);
+ text-decoration-line: underline;
+ cursor: pointer;
+ margin-top: 0.3rem;
+}
diff --git a/src/modules/login/components/Footer/Footer.tsx b/src/modules/login/components/Footer/Footer.tsx
new file mode 100644
index 0000000..8bd0658
--- /dev/null
+++ b/src/modules/login/components/Footer/Footer.tsx
@@ -0,0 +1,23 @@
+import Link from "next/link";
+import { Typography } from "@/components/Typography";
+import styles from "./Footer.module.css";
+
+const Footer = () => {
+ return (
+
+
+
+
+ Nevlastníte restauraci?
+
+
+
+ Vraťte se do Menuroo
+
+
+
+
+ );
+};
+
+export default Footer;
diff --git a/src/modules/login/components/Footer/index.tsx b/src/modules/login/components/Footer/index.tsx
new file mode 100644
index 0000000..090a49a
--- /dev/null
+++ b/src/modules/login/components/Footer/index.tsx
@@ -0,0 +1 @@
+export { default as Footer } from "./Footer";
diff --git a/src/modules/login/components/Form/Form.module.css b/src/modules/login/components/Form/Form.module.css
new file mode 100644
index 0000000..0e9b2e2
--- /dev/null
+++ b/src/modules/login/components/Form/Form.module.css
@@ -0,0 +1,35 @@
+.container {
+ display: flex;
+ flex-direction: column;
+ gap: 1.5rem;
+}
+
+.inputsContainer {
+ display: flex;
+ flex-direction: column;
+ gap: 0.5rem;
+}
+
+.loginButton {
+ color: white;
+ padding: 1rem 0.5rem;
+ width: 100%;
+ border-radius: 1rem;
+ background: var(--red, #D51F2C);
+ transition: background 0.15s ease-in-out;
+ cursor: pointer;
+
+ &.buttonDisabled {
+ background: var(--DISABLED, #5A5A5A);
+ cursor: not-allowed;
+ }
+}
+
+.input {
+ background-color: var(--beige-web, #F9F7F2);
+ transition: border 0.15s ease-in-out;
+
+ &.inputError {
+ border: 1px solid var(--red, #D51F2C);
+ }
+}
\ No newline at end of file
diff --git a/src/modules/login/components/Form/Form.tsx b/src/modules/login/components/Form/Form.tsx
new file mode 100644
index 0000000..fd8ba05
--- /dev/null
+++ b/src/modules/login/components/Form/Form.tsx
@@ -0,0 +1,104 @@
+import { useState, useEffect } from "react";
+import { Input } from "@/components/Input";
+import { Typography } from "@/components/Typography";
+import { useLoginContext } from "../../context/LoginContext";
+import cx from "classnames";
+
+import styles from "./Form.module.css";
+
+const Form = () => {
+ const { authenticate, emailRef, passwordRef } = useLoginContext();
+
+ const [emailValid, setEmailValid] = useState(false);
+ const [passwordValid, setPasswordValid] = useState(false);
+ const [buttonDisabled, setButtonDisabled] = useState(true);
+
+ const [showEmailError, setShowEmailError] = useState(false);
+ const [showPasswordError, setShowPasswordError] = useState(false);
+
+ const verifyEmailInput = () => {
+ if (emailRef?.current?.value.length === 0) {
+ setEmailValid(false);
+ setShowEmailError(false);
+ return;
+ }
+
+ const emailRegex = /\S+@\S+\.\S+/;
+
+ if (emailRef?.current && emailRegex.test(emailRef?.current?.value)) {
+ setEmailValid(true);
+ setShowEmailError(false);
+ } else {
+ setEmailValid(false);
+ setShowEmailError(true);
+ }
+ };
+
+ const verifyPasswordInput = () => {
+ if (passwordRef?.current?.value.length === 0) {
+ setPasswordValid(false);
+ setShowPasswordError(false);
+ return;
+ }
+
+ if (passwordRef?.current && passwordRef?.current?.value.length > 0) {
+ setPasswordValid(true);
+ setShowPasswordError(false);
+ } else {
+ setPasswordValid(false);
+ setShowPasswordError(true);
+ }
+ };
+
+ useEffect(() => {
+ verifyEmailInput();
+ verifyPasswordInput();
+ }, []);
+
+ useEffect(() => {
+ if (emailValid && passwordValid) {
+ setButtonDisabled(false);
+ } else {
+ setButtonDisabled(true);
+ }
+ }, [emailValid, passwordValid]);
+
+ return (
+
+ );
+};
+
+export default Form;
diff --git a/src/modules/login/components/Form/index.tsx b/src/modules/login/components/Form/index.tsx
new file mode 100644
index 0000000..e4500b6
--- /dev/null
+++ b/src/modules/login/components/Form/index.tsx
@@ -0,0 +1 @@
+export { default as Form } from "./Form";
diff --git a/src/modules/login/context/LoginContext.tsx b/src/modules/login/context/LoginContext.tsx
new file mode 100644
index 0000000..daec266
--- /dev/null
+++ b/src/modules/login/context/LoginContext.tsx
@@ -0,0 +1,40 @@
+import { createContext, useContext, ReactNode, MutableRefObject } from "react";
+
+interface LoginContextValue {
+ authenticate: () => void;
+ emailRef: MutableRefObject;
+ passwordRef: MutableRefObject;
+}
+
+const LoginContext = createContext({
+ authenticate: () => {},
+ emailRef: { current: null },
+ passwordRef: { current: null },
+});
+
+export const useLoginContext = () => {
+ return useContext(LoginContext);
+};
+
+interface LoginContextProviderProps {
+ value: LoginContextValue;
+ children: ReactNode;
+}
+
+export const LoginContextProvider = (props: LoginContextProviderProps) => {
+ const {
+ value: { authenticate, emailRef, passwordRef },
+ } = props;
+
+ return (
+
+ {props.children}
+
+ );
+};
diff --git a/src/modules/login/screens/LoginPage.module.css b/src/modules/login/screens/LoginPage.module.css
new file mode 100644
index 0000000..ab9f3e4
--- /dev/null
+++ b/src/modules/login/screens/LoginPage.module.css
@@ -0,0 +1,16 @@
+.container {
+ min-height: 100vh;
+ widht: 100%;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+}
+
+.innerContainer {
+ display: flex;
+ flex-direction: column;
+ width: 20.5rem;
+ gap: 2rem;
+}
+
diff --git a/src/modules/login/screens/LoginPage.tsx b/src/modules/login/screens/LoginPage.tsx
new file mode 100644
index 0000000..c17f452
--- /dev/null
+++ b/src/modules/login/screens/LoginPage.tsx
@@ -0,0 +1,68 @@
+"use client";
+
+import React, { useEffect, useMemo, useRef } from "react";
+import { useRouter } from "next/navigation";
+import { useLazyQuery } from "@apollo/client";
+import login from "@/queries/login";
+import { LogoHeader } from "@/components/LogoHeader";
+import { Form } from "../components/Form";
+import { Footer } from "../components/Footer";
+import { LoginContextProvider } from "../context/LoginContext";
+
+import styles from "./LoginPage.module.css";
+
+interface Props {
+ setToken: (token: string) => void;
+}
+
+const LoginPage = (props: Props) => {
+ const emailRef = useRef(null);
+ const passwordRef = useRef(null);
+
+ const router = useRouter();
+
+ const [loginQuery, { data, error }] = useLazyQuery(login, {
+ fetchPolicy: "network-only",
+ });
+
+ const authenticate = () => {
+ if (emailRef.current?.value && passwordRef.current?.value) {
+ loginQuery({
+ variables: {
+ email: emailRef.current.value,
+ password: passwordRef.current.value,
+ },
+ });
+ }
+ };
+
+ useEffect(() => {
+ if (!data?.login) return;
+
+ props.setToken(data.login);
+ router.push("/jidelni-listek");
+ }, [data]);
+
+ const memoizedValue = useMemo(
+ () => ({
+ authenticate,
+ emailRef,
+ passwordRef,
+ }),
+ [authenticate, emailRef, passwordRef]
+ );
+
+ return (
+
+
+
+ );
+};
+
+export default LoginPage;
diff --git a/src/modules/login/screens/index.tsx b/src/modules/login/screens/index.tsx
new file mode 100644
index 0000000..62cd443
--- /dev/null
+++ b/src/modules/login/screens/index.tsx
@@ -0,0 +1 @@
+export { default as LoginPage } from "./LoginPage";
diff --git a/src/modules/menu/screens/Menu.module.css b/src/modules/menu/screens/Menu.module.css
new file mode 100644
index 0000000..e69de29
diff --git a/src/modules/menu/screens/Menu.tsx b/src/modules/menu/screens/Menu.tsx
new file mode 100644
index 0000000..e69de29
diff --git a/src/modules/menu/screens/index.tsx b/src/modules/menu/screens/index.tsx
new file mode 100644
index 0000000..e69de29
diff --git a/src/theme/themeConfig.ts b/src/theme/themeConfig.ts
index aa34f3a..e0cf7c0 100644
--- a/src/theme/themeConfig.ts
+++ b/src/theme/themeConfig.ts
@@ -4,6 +4,7 @@ const theme: ThemeConfig = {
token: {
colorPrimary: "#37D399",
colorText: "#1F2937",
+ fontFamily: "Nunito",
},
};
diff --git a/src/types/LunchOrder.ts b/src/types/LunchOrder.ts
deleted file mode 100644
index 357faca..0000000
--- a/src/types/LunchOrder.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-export interface LunchOrder {
- key: string;
- orderId: number;
- date: number;
- name: string;
- meal: string;
- order: number;
-}
-
-export interface NormalizedLunchOrder {
- key: string;
- orderId: number;
- date: string;
- name: string;
- meal: string;
- order: number;
-}
diff --git a/src/types/MenuInterface.ts b/src/types/MenuInterface.ts
index 4959a65..95d178c 100644
--- a/src/types/MenuInterface.ts
+++ b/src/types/MenuInterface.ts
@@ -6,5 +6,10 @@ export interface MenuInterface {
meal: string;
soup: string;
drink: string;
- date?: number;
+ date: number;
}
+
+export type DayMenu = {
+ date: number;
+ menus: MenuInterface[];
+};
diff --git a/src/utils/getMonthName.ts b/src/utils/getMonthName.ts
new file mode 100644
index 0000000..833f93c
--- /dev/null
+++ b/src/utils/getMonthName.ts
@@ -0,0 +1,22 @@
+// MM-DD-YYYY
+const getMonthName = (date: string) => {
+ const month = new Date(date).getMonth();
+ return isNaN(month)
+ ? null
+ : [
+ "Leden",
+ "Únor",
+ "Březen",
+ "Duben",
+ "Květen",
+ "Červen",
+ "Červenec",
+ "Srpen",
+ "Září",
+ "Říjen",
+ "Listopad",
+ "Prosinec",
+ ][month];
+};
+
+export default getMonthName;
diff --git a/src/utils/getWeekDay.ts b/src/utils/getWeekDay.ts
index 78a1e5b..53ce5e3 100644
--- a/src/utils/getWeekDay.ts
+++ b/src/utils/getWeekDay.ts
@@ -1,3 +1,4 @@
+// MM-DD-YYYY
const getDayOfWeek = (date: string) => {
const dayOfWeek = new Date(date).getDay();
return isNaN(dayOfWeek)
diff --git a/src/utils/isTokenInLocalStorage.ts b/src/utils/isTokenInLocalStorage.ts
deleted file mode 100644
index ef65b9f..0000000
--- a/src/utils/isTokenInLocalStorage.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-const isTokenInLocalStorage = () => {
- if (typeof window === "undefined") {
- return false;
- }
-
- return localStorage.getItem("token");
-};
-
-export default isTokenInLocalStorage;
diff --git a/src/utils/revalidate.ts b/src/utils/revalidate.ts
new file mode 100644
index 0000000..3c2ceba
--- /dev/null
+++ b/src/utils/revalidate.ts
@@ -0,0 +1,9 @@
+"use server";
+
+import { revalidateTag } from "next/cache";
+
+const revalidate = (tag: string) => {
+ revalidateTag(tag);
+};
+
+export default revalidate;
diff --git a/tailwind.config.ts b/tailwind.config.ts
deleted file mode 100644
index 2716bcb..0000000
--- a/tailwind.config.ts
+++ /dev/null
@@ -1,28 +0,0 @@
-import type { Config } from "tailwindcss";
-
-const config: Config = {
- preflight: false,
- important: true,
- content: [
- "./src/pages/**/*.{js,ts,jsx,tsx,mdx}",
- "./src/components/**/*.{js,ts,jsx,tsx,mdx}",
- "./src/app/**/*.{js,ts,jsx,tsx,mdx}",
- ],
- theme: {
- extend: {
- screens: {
- xxl: "1440px",
- },
- backgroundImage: {
- "gradient-radial": "radial-gradient(var(--tw-gradient-stops))",
- "gradient-conic":
- "conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))",
- },
- colors: {
- primary: "#37d399",
- },
- },
- },
- plugins: [],
-};
-export default config;
diff --git a/tsconfig.json b/tsconfig.json
index 1a65918..aae095a 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -2,7 +2,12 @@
"compilerOptions": {
"target": "es5",
"downlevelIteration": true,
- "lib": ["dom", "dom.iterable", "esnext"],
+ "lib": [
+ "es2015",
+ "dom",
+ "dom.iterable",
+ "esnext"
+ ],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
@@ -21,9 +26,18 @@
],
"baseUrl": ".",
"paths": {
- "@/*": ["./src/*"]
+ "@/*": [
+ "./src/*"
+ ]
}
},
- "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
- "exclude": ["node_modules"]
+ "include": [
+ "next-env.d.ts",
+ "**/*.ts",
+ "**/*.tsx",
+ ".next/types/**/*.ts"
+ ],
+ "exclude": [
+ "node_modules"
+ ]
}