From f7fdc8f69fb723fadc65ccc97e35b7d9c8d15c72 Mon Sep 17 00:00:00 2001 From: Anshika Rai Date: Fri, 22 May 2026 17:25:20 +0530 Subject: [PATCH 1/3] feat(orders): Live Kitchen Display System (KDS) View (#175) --- RestroHub-FrontEnd/package-lock.json | 359 ++++++++++++------ RestroHub-FrontEnd/package.json | 4 +- .../src/components/admin/Sidebar.jsx | 2 + .../src/components/admin/kds/KanbanBoard.jsx | 88 +++++ .../admin/kds/KitchenDisplaySystem.jsx | 180 +++++++++ .../src/components/admin/kds/OrderCard.jsx | 108 ++++++ .../src/routes/ProtectedRoute.jsx | 37 +- RestroHub-FrontEnd/src/routes/index.jsx | 2 + .../qrmenu/order/builder/OrderDirector.java | 7 +- .../order/controller/OrderController.java | 6 +- .../service/OrderNotificationService.java | 7 +- .../order/service/impl/OrderServiceImpl.java | 9 +- 12 files changed, 668 insertions(+), 141 deletions(-) create mode 100644 RestroHub-FrontEnd/src/components/admin/kds/KanbanBoard.jsx create mode 100644 RestroHub-FrontEnd/src/components/admin/kds/KitchenDisplaySystem.jsx create mode 100644 RestroHub-FrontEnd/src/components/admin/kds/OrderCard.jsx diff --git a/RestroHub-FrontEnd/package-lock.json b/RestroHub-FrontEnd/package-lock.json index f9ad811..526c58b 100644 --- a/RestroHub-FrontEnd/package-lock.json +++ b/RestroHub-FrontEnd/package-lock.json @@ -13,6 +13,7 @@ "@react-oauth/google": "^0.13.5", "@react-three/drei": "^9.122.0", "@react-three/fiber": "^8.18.0", + "@stomp/stompjs": "^7.3.0", "axios": "^1.13.4", "formik": "^2.4.9", "framer-motion": "^12.33.0", @@ -23,8 +24,9 @@ "react-hot-toast": "^2.6.0", "react-icons": "^5.5.0", "react-qr-code": "^2.0.18", - "react-router-dom": "^7.13.0", + "react-router-dom": "^6.30.1", "recharts": "^3.7.0", + "sockjs-client": "^1.6.1", "three": "^0.182.0", "yup": "^1.7.1" }, @@ -32,7 +34,7 @@ "@tailwindcss/forms": "^0.5.11", "@types/react": "^18.2.0", "@types/react-dom": "^18.2.0", - "@vitejs/plugin-react": "^4.0.0", + "@vitejs/plugin-react": "^5.0.0", "autoprefixer": "^10.4.24", "eslint": "^9.39.2", "eslint-plugin-react": "^7.32.0", @@ -58,13 +60,13 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", - "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", + "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" }, @@ -73,9 +75,9 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.5.tgz", - "integrity": "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==", + "version": "7.29.3", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.3.tgz", + "integrity": "sha512-LIVqM46zQWZhj17qA8wb4nW/ixr2y1Nw+r1etiAWgRM6U1IqP+LNhL1yg440jYZR72jCWcWbLWzIosH+uP1fqg==", "dev": true, "license": "MIT", "engines": { @@ -83,22 +85,22 @@ } }, "node_modules/@babel/core": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz", - "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", + "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", "dev": true, "license": "MIT", "peer": true, "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.5", - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-module-transforms": "^7.28.3", - "@babel/helpers": "^7.28.4", - "@babel/parser": "^7.28.5", - "@babel/template": "^7.27.2", - "@babel/traverse": "^7.28.5", - "@babel/types": "^7.28.5", + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helpers": "^7.28.6", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.29.0", + "@babel/types": "^7.29.0", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", @@ -115,14 +117,14 @@ } }, "node_modules/@babel/generator": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.5.tgz", - "integrity": "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==", + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", + "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/parser": "^7.28.5", - "@babel/types": "^7.28.5", + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" @@ -132,13 +134,13 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", - "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", + "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.27.2", + "@babel/compat-data": "^7.28.6", "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", @@ -159,29 +161,29 @@ } }, "node_modules/@babel/helper-module-imports": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", - "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", + "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/traverse": "^7.27.1", - "@babel/types": "^7.27.1" + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", - "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", + "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1", - "@babel/traverse": "^7.28.3" + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -231,27 +233,27 @@ } }, "node_modules/@babel/helpers": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", - "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.2.tgz", + "integrity": "sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/template": "^7.27.2", - "@babel/types": "^7.28.4" + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz", - "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", + "version": "7.29.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.3.tgz", + "integrity": "sha512-b3ctpQwp+PROvU/cttc4OYl4MzfJUWy6FZg+PMXfzmt/+39iHVF0sDfqay8TQM3JA2EUOyKcFZt75jWriQijsA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.28.5" + "@babel/types": "^7.29.0" }, "bin": { "parser": "bin/babel-parser.js" @@ -301,33 +303,33 @@ } }, "node_modules/@babel/template": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", - "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", + "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/parser": "^7.27.2", - "@babel/types": "^7.27.1" + "@babel/code-frame": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.5.tgz", - "integrity": "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", + "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.5", + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.28.5", - "@babel/template": "^7.27.2", - "@babel/types": "^7.28.5", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0", "debug": "^4.3.1" }, "engines": { @@ -335,9 +337,9 @@ } }, "node_modules/@babel/types": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz", - "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", "dev": true, "license": "MIT", "dependencies": { @@ -1478,10 +1480,19 @@ "url": "https://opencollective.com/immer" } }, + "node_modules/@remix-run/router": { + "version": "1.23.2", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.23.2.tgz", + "integrity": "sha512-Ic6m2U/rMjTkhERIa/0ZtXJP17QUi2CbWE7cqx4J58M8aA3QTfW+2UlQ4psvTX9IO1RfNVhK3pcpdjej7L+t2w==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/@rolldown/pluginutils": { - "version": "1.0.0-beta.27", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", - "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==", + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.3.tgz", + "integrity": "sha512-eybk3TjzzzV97Dlj5c+XrBFW57eTNhzod66y9HrBlzJ6NsCrWCp/2kaPS3K9wJmurBC0Tdw4yPjXKZqlznim3Q==", "dev": true, "license": "MIT" }, @@ -1847,6 +1858,12 @@ "integrity": "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==", "license": "MIT" }, + "node_modules/@stomp/stompjs": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/@stomp/stompjs/-/stompjs-7.3.0.tgz", + "integrity": "sha512-nKMLoFfJhrQAqkvvKd1vLq/cVBGCMwPRCD0LqW7UT1fecRx9C3GoKEIR2CYwVuErGeZu8w0kFkl2rlhPlqHVgQ==", + "license": "Apache-2.0" + }, "node_modules/@swc/helpers": { "version": "0.5.18", "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.18.tgz", @@ -2128,24 +2145,24 @@ } }, "node_modules/@vitejs/plugin-react": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz", - "integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.2.0.tgz", + "integrity": "sha512-YmKkfhOAi3wsB1PhJq5Scj3GXMn3WvtQ/JC0xoopuHoXSdmtdStOpFrYaT1kie2YgFBcIe64ROzMYRjCrYOdYw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/core": "^7.28.0", + "@babel/core": "^7.29.0", "@babel/plugin-transform-react-jsx-self": "^7.27.1", "@babel/plugin-transform-react-jsx-source": "^7.27.1", - "@rolldown/pluginutils": "1.0.0-beta.27", + "@rolldown/pluginutils": "1.0.0-rc.3", "@types/babel__core": "^7.20.5", - "react-refresh": "^0.17.0" + "react-refresh": "^0.18.0" }, "engines": { - "node": "^14.18.0 || >=16.0.0" + "node": "^20.19.0 || >=22.12.0" }, "peerDependencies": { - "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" } }, "node_modules/@webgpu/types": { @@ -2857,19 +2874,6 @@ "dev": true, "license": "MIT" }, - "node_modules/cookie": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz", - "integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, "node_modules/cross-env": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", @@ -3760,6 +3764,15 @@ "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", "license": "MIT" }, + "node_modules/eventsource": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-2.0.2.tgz", + "integrity": "sha512-IzUmBGPR3+oUG9dUeXynyNmf91/3zUSJg1lCktzKw47OXuhco54U3r9B7O4XX+Rb1Itm9OZ2b0RkTs10bICOxA==", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -3821,6 +3834,18 @@ "reusify": "^1.0.4" } }, + "node_modules/faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "license": "Apache-2.0", + "dependencies": { + "websocket-driver": ">=0.5.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/fdir": { "version": "6.5.0", "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", @@ -4468,6 +4493,12 @@ "react-is": "^16.7.0" } }, + "node_modules/http-parser-js": { + "version": "0.5.10", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.10.tgz", + "integrity": "sha512-Pysuw9XpUq5dVc/2SMHpuTY01RFl8fttgcyunjL7eEMhGM3cI4eOmiCycJDVCo/7O7ClfQD3SaI6ftDzqOXYMA==", + "license": "MIT" + }, "node_modules/ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", @@ -4540,6 +4571,12 @@ "node": ">=0.8.19" } }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, "node_modules/internal-slot": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", @@ -5418,7 +5455,6 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, "license": "MIT" }, "node_modules/mz": { @@ -6088,6 +6124,12 @@ "integrity": "sha512-c4iYnWb+k2E+vYpRimHqSu575b1/wKl4XFeJGpFmrJQz5I88v9aY2czh7s0w36srfCM1sXgC/xpoJz5dJfq+OQ==", "license": "MIT" }, + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "license": "MIT" + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -6246,9 +6288,9 @@ } }, "node_modules/react-refresh": { - "version": "0.17.0", - "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", - "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==", + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.18.0.tgz", + "integrity": "sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==", "dev": true, "license": "MIT", "engines": { @@ -6256,41 +6298,35 @@ } }, "node_modules/react-router": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.13.0.tgz", - "integrity": "sha512-PZgus8ETambRT17BUm/LL8lX3Of+oiLaPuVTRH3l1eLvSPpKO3AvhAEb5N7ihAFZQrYDqkvvWfFh9p0z9VsjLw==", + "version": "6.30.3", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.30.3.tgz", + "integrity": "sha512-XRnlbKMTmktBkjCLE8/XcZFlnHvr2Ltdr1eJX4idL55/9BbORzyZEaIkBFDhFGCEWBBItsVrDxwx3gnisMitdw==", "license": "MIT", "dependencies": { - "cookie": "^1.0.1", - "set-cookie-parser": "^2.6.0" + "@remix-run/router": "1.23.2" }, "engines": { - "node": ">=20.0.0" + "node": ">=14.0.0" }, "peerDependencies": { - "react": ">=18", - "react-dom": ">=18" - }, - "peerDependenciesMeta": { - "react-dom": { - "optional": true - } + "react": ">=16.8" } }, "node_modules/react-router-dom": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.13.0.tgz", - "integrity": "sha512-5CO/l5Yahi2SKC6rGZ+HDEjpjkGaG/ncEP7eWFTvFxbHP8yeeI0PxTDjimtpXYlR3b3i9/WIL4VJttPrESIf2g==", + "version": "6.30.3", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.30.3.tgz", + "integrity": "sha512-pxPcv1AczD4vso7G4Z3TKcvlxK7g7TNt3/FNGMhfqyntocvYKj+GCatfigGDjbLozC4baguJ0ReCigoDJXb0ag==", "license": "MIT", "dependencies": { - "react-router": "7.13.0" + "@remix-run/router": "1.23.2", + "react-router": "6.30.3" }, "engines": { - "node": ">=20.0.0" + "node": ">=14.0.0" }, "peerDependencies": { - "react": ">=18", - "react-dom": ">=18" + "react": ">=16.8", + "react-dom": ">=16.8" } }, "node_modules/react-use-measure": { @@ -6441,6 +6477,12 @@ "node": ">=0.10.0" } }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "license": "MIT" + }, "node_modules/reselect": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.1.1.tgz", @@ -6575,6 +6617,26 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, "node_modules/safe-push-apply": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", @@ -6629,12 +6691,6 @@ "semver": "bin/semver.js" } }, - "node_modules/set-cookie-parser": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz", - "integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==", - "license": "MIT" - }, "node_modules/set-function-length": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", @@ -6791,6 +6847,34 @@ "node": ">=8" } }, + "node_modules/sockjs-client": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.6.1.tgz", + "integrity": "sha512-2g0tjOR+fRs0amxENLi/q5TiJTqY+WXFOzb5UwXndlK6TO3U/mirZznpx6w34HVMoc3g7cY24yC/ZMIYnDlfkw==", + "license": "MIT", + "dependencies": { + "debug": "^3.2.7", + "eventsource": "^2.0.2", + "faye-websocket": "^0.11.4", + "inherits": "^2.0.4", + "url-parse": "^1.5.10" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://tidelift.com/funding/github/npm/sockjs-client" + } + }, + "node_modules/sockjs-client/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -7479,6 +7563,16 @@ "punycode": "^2.1.0" } }, + "node_modules/url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "license": "MIT", + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, "node_modules/use-sync-external-store": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", @@ -7611,6 +7705,29 @@ "resolved": "https://registry.npmjs.org/webgl-sdf-generator/-/webgl-sdf-generator-1.1.1.tgz", "integrity": "sha512-9Z0JcMTFxeE+b2x1LJTdnaT8rT8aEp7MVxkNwoycNmJWwPdzoXzMh0BjJSh/AEFP+KPYZUli814h8bJZFIZ2jA==" }, + "node_modules/websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "license": "Apache-2.0", + "dependencies": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", diff --git a/RestroHub-FrontEnd/package.json b/RestroHub-FrontEnd/package.json index 146b3dd..2e2945c 100644 --- a/RestroHub-FrontEnd/package.json +++ b/RestroHub-FrontEnd/package.json @@ -17,6 +17,7 @@ "@react-oauth/google": "^0.13.5", "@react-three/drei": "^9.122.0", "@react-three/fiber": "^8.18.0", + "@stomp/stompjs": "^7.3.0", "axios": "^1.13.4", "formik": "^2.4.9", "framer-motion": "^12.33.0", @@ -29,6 +30,7 @@ "react-qr-code": "^2.0.18", "react-router-dom": "^6.30.1", "recharts": "^3.7.0", + "sockjs-client": "^1.6.1", "three": "^0.182.0", "yup": "^1.7.1" }, @@ -56,4 +58,4 @@ ], "author": "", "license": "MIT" -} \ No newline at end of file +} diff --git a/RestroHub-FrontEnd/src/components/admin/Sidebar.jsx b/RestroHub-FrontEnd/src/components/admin/Sidebar.jsx index 61861b7..1953e8f 100644 --- a/RestroHub-FrontEnd/src/components/admin/Sidebar.jsx +++ b/RestroHub-FrontEnd/src/components/admin/Sidebar.jsx @@ -14,6 +14,7 @@ import { QrCode, ChevronsLeft, ChevronsRight, + ChefHat, } from 'lucide-react'; import { useAdminTheme } from '@context/AdminThemeContext'; @@ -61,6 +62,7 @@ const Sidebar = ({ open, setOpen, collapsed, setCollapsed }) => { label: 'Menu', items: [ { type: 'link', name: 'Dashboard', path: '/admin/dashboard', icon: LayoutDashboard }, + { type: 'link', name: 'Kitchen Display', path: '/admin/kds', icon: ChefHat }, { type: 'link', name: 'Menus', path: '/admin/menus', icon: UtensilsCrossed }, { type: 'link', name: 'Orders', path: '/admin/orders', icon: ShoppingCart }, ], diff --git a/RestroHub-FrontEnd/src/components/admin/kds/KanbanBoard.jsx b/RestroHub-FrontEnd/src/components/admin/kds/KanbanBoard.jsx new file mode 100644 index 0000000..f3c572f --- /dev/null +++ b/RestroHub-FrontEnd/src/components/admin/kds/KanbanBoard.jsx @@ -0,0 +1,88 @@ +import React from 'react'; +import OrderCard from './OrderCard'; + +const KanbanBoard = ({ orders, onStatusUpdate }) => { + // Group orders by status + const pendingOrders = orders.filter(o => o.status === 'PENDING' || o.status === 'CONFIRMED'); + const preparingOrders = orders.filter(o => o.status === 'PREPARING'); + const readyOrders = orders.filter(o => o.status === 'READY'); + + return ( +
+ {/* Pending Column */} +
+
+

Pending

+ + {pendingOrders.length} + +
+
+ {pendingOrders.map(order => ( + + ))} + {pendingOrders.length === 0 && ( +
+ No pending orders +
+ )} +
+
+ + {/* Preparing Column */} +
+
+

Preparing

+ + {preparingOrders.length} + +
+
+ {preparingOrders.map(order => ( + + ))} + {preparingOrders.length === 0 && ( +
+ No orders preparing +
+ )} +
+
+ + {/* Ready Column */} +
+
+

Ready

+ + {readyOrders.length} + +
+
+ {readyOrders.map(order => ( + + ))} + {readyOrders.length === 0 && ( +
+ No orders ready +
+ )} +
+
+ + +
+ ); +}; + +export default KanbanBoard; diff --git a/RestroHub-FrontEnd/src/components/admin/kds/KitchenDisplaySystem.jsx b/RestroHub-FrontEnd/src/components/admin/kds/KitchenDisplaySystem.jsx new file mode 100644 index 0000000..ccb8a5c --- /dev/null +++ b/RestroHub-FrontEnd/src/components/admin/kds/KitchenDisplaySystem.jsx @@ -0,0 +1,180 @@ +import React, { useState, useEffect, useRef } from 'react'; +import { Stomp } from '@stomp/stompjs'; +import SockJS from 'sockjs-client'; +import api from '@services/common/api'; +import KanbanBoard from './KanbanBoard'; +import { toast } from 'react-hot-toast'; + +const KitchenDisplaySystem = () => { + const [orders, setOrders] = useState([]); + const [loading, setLoading] = useState(true); + const [isConnected, setIsConnected] = useState(false); + const stompClientRef = useRef(null); + const audioContextRef = useRef(null); + + // The selected branch ID could be fetched from context or local storage, assuming branch ID 1 for now if not available + // In a real scenario, this would come from the auth token or selected context + const branchId = localStorage.getItem("selectedBranchId") || 1; + + // Initialize Web Audio API for chime + useEffect(() => { + try { + const AudioContext = window.AudioContext || window.webkitAudioContext; + audioContextRef.current = new AudioContext(); + } catch (e) { + console.warn("Web Audio API not supported", e); + } + return () => { + if (audioContextRef.current && audioContextRef.current.state !== 'closed') { + audioContextRef.current.close(); + } + }; + }, []); + + const playChime = () => { + if (!audioContextRef.current) return; + + // Resume context if suspended (browser autoplay policy) + if (audioContextRef.current.state === 'suspended') { + audioContextRef.current.resume(); + } + + try { + const oscillator = audioContextRef.current.createOscillator(); + const gainNode = audioContextRef.current.createGain(); + + oscillator.type = 'sine'; + oscillator.frequency.setValueAtTime(587.33, audioContextRef.current.currentTime); // D5 + oscillator.frequency.exponentialRampToValueAtTime(880.00, audioContextRef.current.currentTime + 0.1); // A5 + + gainNode.gain.setValueAtTime(0, audioContextRef.current.currentTime); + gainNode.gain.linearRampToValueAtTime(0.3, audioContextRef.current.currentTime + 0.05); + gainNode.gain.exponentialRampToValueAtTime(0.01, audioContextRef.current.currentTime + 1); + + oscillator.connect(gainNode); + gainNode.connect(audioContextRef.current.destination); + + oscillator.start(audioContextRef.current.currentTime); + oscillator.stop(audioContextRef.current.currentTime + 1); + } catch (e) { + console.error("Audio playback failed", e); + } + }; + + const fetchActiveOrders = async () => { + try { + setLoading(true); + const response = await api.get(`/api/v1/secure/orders/branch/${branchId}/active`); + setOrders(response.data || []); + } catch (error) { + console.error("Error fetching orders:", error); + toast.error("Failed to load active orders"); + } finally { + setLoading(false); + } + }; + + useEffect(() => { + fetchActiveOrders(); + + // Connect WebSocket + const connectWebSocket = () => { + const wsUrl = import.meta.env.VITE_WS_URL || "http://localhost:8181/ws"; + const socket = new SockJS(wsUrl); + const client = Stomp.over(socket); + + // Disable debug logging in production + client.debug = () => {}; + + client.connect({}, (frame) => { + setIsConnected(true); + console.log('Connected to KDS WebSocket'); + + client.subscribe(`/topic/orders/branch/${branchId}`, (message) => { + if (message.body) { + const notification = JSON.parse(message.body); + handleOrderNotification(notification); + } + }); + }, (error) => { + console.error('WebSocket error:', error); + setIsConnected(false); + // Attempt to reconnect after 5 seconds + setTimeout(connectWebSocket, 5000); + }); + + stompClientRef.current = client; + }; + + connectWebSocket(); + + return () => { + if (stompClientRef.current) { + stompClientRef.current.disconnect(); + } + }; + }, [branchId]); + + const handleOrderNotification = (notification) => { + const { type, order } = notification; + + if (type === 'NEW_ORDER') { + playChime(); + toast.success(`New order #${order.orderId} received!`, { icon: '🔔' }); + setOrders(prev => { + // Prevent duplicates + if (prev.some(o => o.orderId === order.orderId)) return prev; + return [order, ...prev]; + }); + } else if (type === 'STATUS_UPDATE') { + setOrders(prev => prev.map(o => o.orderId === order.orderId ? order : o)); + } + }; + + const handleStatusUpdate = (orderId, newStatus) => { + // Optimistic update + setOrders(prev => prev.map(o => + o.orderId === orderId ? { ...o, status: newStatus } : o + )); + + // In a real application, if the API call fails (handled in OrderCard), + // it would call a rollback function here or re-fetch. + // For simplicity, we assume success or rely on the WebSocket broadcast to correct it. + }; + + return ( +
+
+
+

Kitchen Display System

+
+
+ + {isConnected ? 'Live Sync Active' : 'Disconnected - Reconnecting...'} + +
+
+
+ +
+
+ +
+ {loading ? ( +
+
+
+ ) : ( + + )} +
+
+ ); +}; + +export default KitchenDisplaySystem; diff --git a/RestroHub-FrontEnd/src/components/admin/kds/OrderCard.jsx b/RestroHub-FrontEnd/src/components/admin/kds/OrderCard.jsx new file mode 100644 index 0000000..a6c251e --- /dev/null +++ b/RestroHub-FrontEnd/src/components/admin/kds/OrderCard.jsx @@ -0,0 +1,108 @@ +import React, { useState, useEffect } from 'react'; +import { Clock, ChefHat, CheckCircle, AlertCircle } from 'lucide-react'; +import api from '@services/common/api'; + +const OrderCard = ({ order, onStatusUpdate }) => { + const [elapsedMinutes, setElapsedMinutes] = useState(0); + const [isUpdating, setIsUpdating] = useState(false); + + useEffect(() => { + const calculateElapsed = () => { + const createdTime = new Date(order.createdAt).getTime(); + const now = new Date().getTime(); + setElapsedMinutes(Math.floor((now - createdTime) / 60000)); + }; + + calculateElapsed(); + const interval = setInterval(calculateElapsed, 60000); // Update every minute + return () => clearInterval(interval); + }, [order.createdAt]); + + const handleUpdateStatus = async (newStatus) => { + setIsUpdating(true); + try { + await api.patch(`/api/v1/secure/orders/${order.orderId}/status`, { status: newStatus }); + onStatusUpdate(order.orderId, newStatus); + } catch (error) { + console.error('Failed to update order status', error); + // Let the parent component handle error toasts if needed + } finally { + setIsUpdating(false); + } + }; + + // Urgency logic + const isUrgent = elapsedMinutes >= 20 && order.status !== 'READY'; + const isWarning = elapsedMinutes >= 15 && elapsedMinutes < 20 && order.status !== 'READY'; + + let borderColor = 'border-gray-200'; + let bgColor = 'bg-white'; + if (isUrgent) { + borderColor = 'border-red-500 animate-pulse'; + bgColor = 'bg-red-50'; + } else if (isWarning) { + borderColor = 'border-amber-400'; + bgColor = 'bg-amber-50'; + } + + return ( +
+
+
+

+ Table {order.tableNumber || 'N/A'} +

+

#{order.orderId}

+
+
+ {isUrgent ? : } + {elapsedMinutes}m +
+
+ +
+ {order.items?.map((item) => ( +
+
+ {item.quantity}x + {item.foodName} + {item.specialRequest && ( +

Note: {item.specialRequest}

+ )} +
+
+ ))} + {order.specialInstructions && ( +
+ Order Note: {order.specialInstructions} +
+ )} +
+ +
+ {(order.status === 'PENDING' || order.status === 'CONFIRMED') && ( + + )} + {order.status === 'PREPARING' && ( + + )} +
+
+ ); +}; + +export default OrderCard; diff --git a/RestroHub-FrontEnd/src/routes/ProtectedRoute.jsx b/RestroHub-FrontEnd/src/routes/ProtectedRoute.jsx index 165e712..7231b08 100644 --- a/RestroHub-FrontEnd/src/routes/ProtectedRoute.jsx +++ b/RestroHub-FrontEnd/src/routes/ProtectedRoute.jsx @@ -1,12 +1,45 @@ -import { Navigate } from "react-router-dom"; +import { Navigate, useLocation } from "react-router-dom"; const ProtectedRoute = ({ children }) => { + const location = useLocation(); const accessToken = localStorage.getItem("accessToken"); - + if (!accessToken) { return ; } + // Role-based access control + let roles = []; + try { + const rolesStr = localStorage.getItem("roles"); + if (rolesStr) roles = JSON.parse(rolesStr); + } catch (e) { + console.error("Failed to parse roles"); + } + + const hasRole = (roleToCheck) => { + if (!Array.isArray(roles)) return false; + return roles.some(r => { + const roleName = typeof r === 'string' ? r : r.authority || r.name; + return roleName === roleToCheck || roleName === `ROLE_${roleToCheck}`; + }); + }; + + const isAdmin = hasRole("ADMIN"); + const isManager = hasRole("MANAGER"); + const isStaff = hasRole("STAFF"); + + // If user is Manager or Staff but NOT Admin, restrict access to KDS and Orders + if (!isAdmin && (isManager || isStaff)) { + const allowedPaths = ["/admin/kds", "/admin/orders", "/admin/profile"]; + const isAllowed = allowedPaths.some(p => location.pathname.startsWith(p)); + + // Redirect away from dashboard or unauthorized routes to KDS + if (!isAllowed || location.pathname === "/admin" || location.pathname === "/admin/dashboard") { + return ; + } + } + return children; }; diff --git a/RestroHub-FrontEnd/src/routes/index.jsx b/RestroHub-FrontEnd/src/routes/index.jsx index 51e0bdd..d2bc05a 100644 --- a/RestroHub-FrontEnd/src/routes/index.jsx +++ b/RestroHub-FrontEnd/src/routes/index.jsx @@ -25,6 +25,7 @@ import Tables from '@components/admin/store/tables/Tables'; import Website from '@components/admin/marketing/website/Website'; import QRDisplay from '@components/admin/marketing/qr/QRDisplay'; import UPILinks from '@components/admin/upi/UPILinks'; +import KitchenDisplaySystem from '@components/admin/kds/KitchenDisplaySystem'; import Profile from '@components/admin/profile/Profile'; const AppRoutes = () => { @@ -61,6 +62,7 @@ const AppRoutes = () => { } /> } /> } /> + } /> } /> diff --git a/RestroHub/src/main/java/com/restroly/qrmenu/order/builder/OrderDirector.java b/RestroHub/src/main/java/com/restroly/qrmenu/order/builder/OrderDirector.java index 2185dfa..1b37631 100644 --- a/RestroHub/src/main/java/com/restroly/qrmenu/order/builder/OrderDirector.java +++ b/RestroHub/src/main/java/com/restroly/qrmenu/order/builder/OrderDirector.java @@ -21,11 +21,8 @@ @Slf4j public class OrderDirector { -// -// private final OrderBuilder orderBuilder; -// private final OrderItemBuilder orderItemBuilder; - private final OrderBuilder orderBuilder = null; - private final OrderItemBuilder orderItemBuilder = new OrderItemBuilder(); + private final OrderBuilder orderBuilder; + private final OrderItemBuilder orderItemBuilder; /** * Build a standard dine-in order diff --git a/RestroHub/src/main/java/com/restroly/qrmenu/order/controller/OrderController.java b/RestroHub/src/main/java/com/restroly/qrmenu/order/controller/OrderController.java index 5792a30..6e0a352 100644 --- a/RestroHub/src/main/java/com/restroly/qrmenu/order/controller/OrderController.java +++ b/RestroHub/src/main/java/com/restroly/qrmenu/order/controller/OrderController.java @@ -28,12 +28,10 @@ @RestController @RequestMapping(SECURE_API_VERSION+"/orders") @CrossOrigin(origins = "*") +@RequiredArgsConstructor public class OrderController { - @Autowired - private final OrderService orderService = null; - -//private final OrderService orderService; + private final OrderService orderService; @PostMapping public ResponseEntity createOrder(@Valid @RequestBody CreateOrderRequest request) { OrderResponse response = orderService.createOrder(request); diff --git a/RestroHub/src/main/java/com/restroly/qrmenu/order/service/OrderNotificationService.java b/RestroHub/src/main/java/com/restroly/qrmenu/order/service/OrderNotificationService.java index b618b83..43b43ff 100644 --- a/RestroHub/src/main/java/com/restroly/qrmenu/order/service/OrderNotificationService.java +++ b/RestroHub/src/main/java/com/restroly/qrmenu/order/service/OrderNotificationService.java @@ -13,11 +13,8 @@ //@Slf4j public class OrderNotificationService { -// private final SimpMessagingTemplate messagingTemplate; -// private final OrderMapper orderMapper; - - private final SimpMessagingTemplate messagingTemplate = null; - private final OrderMapper orderMapper = new OrderMapper(); + private final SimpMessagingTemplate messagingTemplate; + private final OrderMapper orderMapper; public void notifyNewOrder(Order order) { OrderResponse response = orderMapper.toResponse(order); diff --git a/RestroHub/src/main/java/com/restroly/qrmenu/order/service/impl/OrderServiceImpl.java b/RestroHub/src/main/java/com/restroly/qrmenu/order/service/impl/OrderServiceImpl.java index a8560cb..bbae1a3 100644 --- a/RestroHub/src/main/java/com/restroly/qrmenu/order/service/impl/OrderServiceImpl.java +++ b/RestroHub/src/main/java/com/restroly/qrmenu/order/service/impl/OrderServiceImpl.java @@ -43,9 +43,12 @@ public class OrderServiceImpl implements OrderService { @Autowired private FoodRepository foodRepository; - private final OrderDirector orderDirector = new OrderDirector(); - private final OrderMapper orderMapper = new OrderMapper(); - private final OrderNotificationService notificationService = new OrderNotificationService(); + @Autowired + private OrderDirector orderDirector; + @Autowired + private OrderMapper orderMapper; + @Autowired + private OrderNotificationService notificationService; @Override public OrderResponse createOrder(CreateOrderRequest request) { From 725be2ef96ceccfebfda35754d0f499c555f4959 Mon Sep 17 00:00:00 2001 From: ANSHIKA Date: Sat, 23 May 2026 19:10:35 +0530 Subject: [PATCH 2/3] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .../src/components/admin/kds/KitchenDisplaySystem.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RestroHub-FrontEnd/src/components/admin/kds/KitchenDisplaySystem.jsx b/RestroHub-FrontEnd/src/components/admin/kds/KitchenDisplaySystem.jsx index ccb8a5c..2efe4b6 100644 --- a/RestroHub-FrontEnd/src/components/admin/kds/KitchenDisplaySystem.jsx +++ b/RestroHub-FrontEnd/src/components/admin/kds/KitchenDisplaySystem.jsx @@ -64,7 +64,7 @@ const KitchenDisplaySystem = () => { const fetchActiveOrders = async () => { try { setLoading(true); - const response = await api.get(`/api/v1/secure/orders/branch/${branchId}/active`); + const response = await api.get(`/secure/api/v1/orders/branch/${branchId}/active`); setOrders(response.data || []); } catch (error) { console.error("Error fetching orders:", error); From 7c412d8c37728111d45f8064cdc986045a7600ad Mon Sep 17 00:00:00 2001 From: Anshika Rai Date: Tue, 26 May 2026 10:20:41 +0530 Subject: [PATCH 3/3] fix: add missing PaymentService to OrderController --- .../com/restroly/qrmenu/order/controller/OrderController.java | 1 + 1 file changed, 1 insertion(+) diff --git a/RestroHub/src/main/java/com/restroly/qrmenu/order/controller/OrderController.java b/RestroHub/src/main/java/com/restroly/qrmenu/order/controller/OrderController.java index 9265c0b..4d2fdfb 100644 --- a/RestroHub/src/main/java/com/restroly/qrmenu/order/controller/OrderController.java +++ b/RestroHub/src/main/java/com/restroly/qrmenu/order/controller/OrderController.java @@ -33,6 +33,7 @@ public class OrderController { private final OrderService orderService; + private final PaymentService paymentService; @PostMapping public ResponseEntity createOrder(@Valid @RequestBody CreateOrderRequest request) { OrderResponse response = orderService.createOrder(request);