From 31034cb81dd2d9cec6021c1173827961b179959f Mon Sep 17 00:00:00 2001 From: sebivh Date: Sun, 21 Sep 2025 17:41:48 +0200 Subject: [PATCH] Fully functional --- global.d.ts | 17 ++ package-lock.json | 326 +++++++++++++++++++++++++++++- package.json | 7 +- src/actions/add-to-cart.tsx | 16 +- src/actions/checkout.tsx | 9 +- src/app/api/order-status/route.ts | 57 ++++++ src/app/globals.css | 23 +-- src/app/layout.tsx | 17 +- src/app/page.tsx | 218 ++++++++++++++++++-- src/app/reader/page.tsx | 7 +- src/components/FlyonuiScript.tsx | 47 +++++ 11 files changed, 693 insertions(+), 51 deletions(-) create mode 100644 global.d.ts create mode 100644 src/app/api/order-status/route.ts create mode 100644 src/components/FlyonuiScript.tsx diff --git a/global.d.ts b/global.d.ts new file mode 100644 index 0000000..fd1a119 --- /dev/null +++ b/global.d.ts @@ -0,0 +1,17 @@ +// global.d.ts +import { IStaticMethods } from "flyonui/flyonui"; + +declare global { + interface Window { + // Optional third-party libraries + _; + $: typeof import("jquery"); + jQuery: typeof import("jquery"); + DataTable; + Dropzone; + + HSStaticMethods: IStaticMethods; + } +} + +export {}; diff --git a/package-lock.json b/package-lock.json index b4352cb..a9552df 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,15 +9,20 @@ "version": "0.1.0", "dependencies": { "@sumup/sdk": "^0.0.4", + "flyonui": "^2.4.0", "next": "15.5.3", "react": "19.1.0", - "react-dom": "19.1.0" + "react-dom": "19.1.0", + "ws": "^8.18.3" }, "devDependencies": { + "@iconify-json/tabler": "^1.2.23", + "@iconify/tailwind4": "^1.0.6", "@tailwindcss/postcss": "^4", "@types/node": "^20", "@types/react": "^19", "@types/react-dom": "^19", + "@types/ws": "^8.18.1", "tailwindcss": "^4", "typescript": "^5" } @@ -35,6 +40,30 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@antfu/install-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@antfu/install-pkg/-/install-pkg-1.1.0.tgz", + "integrity": "sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "package-manager-detector": "^1.3.0", + "tinyexec": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@antfu/utils": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/@antfu/utils/-/utils-8.1.1.tgz", + "integrity": "sha512-Mex9nXf9vR6AhcXmMrlz/HVgYYZpVGJ6YlPgwl7UnaFpnshXs6EK/oa5Gpf3CzENMjkvEx2tQtntGnb7UtSTOQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, "node_modules/@emnapi/runtime": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.5.0.tgz", @@ -45,6 +74,82 @@ "tslib": "^2.4.0" } }, + "node_modules/@floating-ui/core": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.3.tgz", + "integrity": "sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==", + "license": "MIT", + "dependencies": { + "@floating-ui/utils": "^0.2.10" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.4.tgz", + "integrity": "sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==", + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.7.3", + "@floating-ui/utils": "^0.2.10" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.10.tgz", + "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==", + "license": "MIT" + }, + "node_modules/@iconify-json/tabler": { + "version": "1.2.23", + "resolved": "https://registry.npmjs.org/@iconify-json/tabler/-/tabler-1.2.23.tgz", + "integrity": "sha512-Knb8ykgMwB5uSoqrDv1xIdJYM03OP06OXjN6QvGXaTNtdHkW9ciKA+aftz6lwM2jwJA+bsUWeDzLBlPt2uJm4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@iconify/types": "*" + } + }, + "node_modules/@iconify/tailwind4": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@iconify/tailwind4/-/tailwind4-1.0.6.tgz", + "integrity": "sha512-43ZXe+bC7CuE2LCgROdqbQeFYJi/J7L/k1UpSy8KDQlWVsWxPzLSWbWhlJx4uRYLOh1NRyw02YlDOgzBOFNd+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@iconify/types": "^2.0.0", + "@iconify/utils": "^2.2.1" + }, + "funding": { + "url": "https://github.com/sponsors/cyberalien" + }, + "peerDependencies": { + "tailwindcss": ">= 4" + } + }, + "node_modules/@iconify/types": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@iconify/types/-/types-2.0.0.tgz", + "integrity": "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@iconify/utils": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@iconify/utils/-/utils-2.3.0.tgz", + "integrity": "sha512-GmQ78prtwYW6EtzXRU1rY+KwOKfz32PD7iJh6Iyqw68GiKuoZ2A6pRtzWONz5VQJbp50mEjXh/7NkumtrAgRKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@antfu/install-pkg": "^1.0.0", + "@antfu/utils": "^8.1.0", + "@iconify/types": "^2.0.0", + "debug": "^4.4.0", + "globals": "^15.14.0", + "kolorist": "^1.8.0", + "local-pkg": "^1.0.0", + "mlly": "^1.7.4" + } + }, "node_modules/@img/colour": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.0.0.tgz", @@ -994,6 +1099,29 @@ "@types/react": "^19.0.0" } }, + "node_modules/@types/ws": { + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/caniuse-lite": { "version": "1.0.30001743", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001743.tgz", @@ -1030,6 +1158,13 @@ "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==", "license": "MIT" }, + "node_modules/confbox": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.2.tgz", + "integrity": "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==", + "dev": true, + "license": "MIT" + }, "node_modules/csstype": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", @@ -1037,6 +1172,24 @@ "dev": true, "license": "MIT" }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, "node_modules/detect-libc": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.0.tgz", @@ -1061,6 +1214,35 @@ "node": ">=10.13.0" } }, + "node_modules/exsolve": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.7.tgz", + "integrity": "sha512-VO5fQUzZtI6C+vx4w/4BWJpg3s/5l+6pRQEHzFRM8WFi4XffSP1Z+4qi7GbjWbvRQEbdIco5mIMq+zX4rPuLrw==", + "dev": true, + "license": "MIT" + }, + "node_modules/flyonui": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/flyonui/-/flyonui-2.4.0.tgz", + "integrity": "sha512-gXlZLY1/XcywnitWCB4EVbUNU8NSA92RRyi5WGRK5wyQunQEHRW/AvTUyZoiNIxjVC/VRnnO0vkLPsETXsj9RQ==", + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.7.1" + } + }, + "node_modules/globals": { + "version": "15.15.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.15.0.tgz", + "integrity": "sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", @@ -1078,6 +1260,13 @@ "jiti": "lib/jiti-cli.mjs" } }, + "node_modules/kolorist": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/kolorist/-/kolorist-1.8.0.tgz", + "integrity": "sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==", + "dev": true, + "license": "MIT" + }, "node_modules/lightningcss": { "version": "1.30.1", "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.1.tgz", @@ -1317,6 +1506,24 @@ "url": "https://opencollective.com/parcel" } }, + "node_modules/local-pkg": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-1.1.2.tgz", + "integrity": "sha512-arhlxbFRmoQHl33a0Zkle/YWlmNwoyt6QNZEIJcqNbdrsix5Lvc4HyyI3EnwxTYlZYc32EbYrQ8SzEZ7dqgg9A==", + "dev": true, + "license": "MIT", + "dependencies": { + "mlly": "^1.7.4", + "pkg-types": "^2.3.0", + "quansync": "^0.2.11" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, "node_modules/magic-string": { "version": "0.30.19", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.19.tgz", @@ -1366,6 +1573,45 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/mlly": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.0.tgz", + "integrity": "sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.15.0", + "pathe": "^2.0.3", + "pkg-types": "^1.3.1", + "ufo": "^1.6.1" + } + }, + "node_modules/mlly/node_modules/confbox": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz", + "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/mlly/node_modules/pkg-types": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz", + "integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "confbox": "^0.1.8", + "mlly": "^1.7.4", + "pathe": "^2.0.1" + } + }, + "node_modules/ms": { + "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/nanoid": { "version": "3.3.11", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", @@ -1464,12 +1710,38 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/package-manager-detector": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-1.3.0.tgz", + "integrity": "sha512-ZsEbbZORsyHuO00lY1kV3/t72yp6Ysay6Pd17ZAlNGuGwmWDLCJxFpRs0IzfXfj1o4icJOkUEioexFHzyPurSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", "license": "ISC" }, + "node_modules/pkg-types": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.0.tgz", + "integrity": "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==", + "dev": true, + "license": "MIT", + "dependencies": { + "confbox": "^0.2.2", + "exsolve": "^1.0.7", + "pathe": "^2.0.3" + } + }, "node_modules/postcss": { "version": "8.5.6", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", @@ -1499,6 +1771,23 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/quansync": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/quansync/-/quansync-0.2.11.tgz", + "integrity": "sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/antfu" + }, + { + "type": "individual", + "url": "https://github.com/sponsors/sxzz" + } + ], + "license": "MIT" + }, "node_modules/react": { "version": "19.1.0", "resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz", @@ -1653,6 +1942,13 @@ "node": ">=18" } }, + "node_modules/tinyexec": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.1.tgz", + "integrity": "sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw==", + "dev": true, + "license": "MIT" + }, "node_modules/tslib": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", @@ -1673,6 +1969,13 @@ "node": ">=14.17" } }, + "node_modules/ufo": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.1.tgz", + "integrity": "sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==", + "dev": true, + "license": "MIT" + }, "node_modules/undici-types": { "version": "6.21.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", @@ -1680,6 +1983,27 @@ "dev": true, "license": "MIT" }, + "node_modules/ws": { + "version": "8.18.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", + "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/yallist": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", diff --git a/package.json b/package.json index f60e1b1..1870015 100644 --- a/package.json +++ b/package.json @@ -9,15 +9,20 @@ }, "dependencies": { "@sumup/sdk": "^0.0.4", + "flyonui": "^2.4.0", "next": "15.5.3", "react": "19.1.0", - "react-dom": "19.1.0" + "react-dom": "19.1.0", + "ws": "^8.18.3" }, "devDependencies": { + "@iconify-json/tabler": "^1.2.23", + "@iconify/tailwind4": "^1.0.6", "@tailwindcss/postcss": "^4", "@types/node": "^20", "@types/react": "^19", "@types/react-dom": "^19", + "@types/ws": "^8.18.1", "tailwindcss": "^4", "typescript": "^5" } diff --git a/src/actions/add-to-cart.tsx b/src/actions/add-to-cart.tsx index d546e88..4755e62 100644 --- a/src/actions/add-to-cart.tsx +++ b/src/actions/add-to-cart.tsx @@ -19,8 +19,20 @@ const addToCart = async (barcode: number) => { 'GROCY-API-KEY': "VCPlNborGO2t8rs08cvqodalf3AjecRwgexWzkIk221mtshLoM" } }); + const userfields = await request2.json(); - console.log(`Price of product ${data.product.name} is ${userfields.kuelschrankpreis} EUR`); - return {name: data.product.name, price: userfields.kuelschrankpreis}; + + if ( data.product.picture_file_name ) { + const image_fetch = await fetch(`https://development.vonhelmersen.online/api/files/productpictures/${btoa(data.product.picture_file_name)}`, { + method: 'GET', + headers: { + 'accept': "application/octet-stream", + 'GROCY-API-KEY': "VCPlNborGO2t8rs08cvqodalf3AjecRwgexWzkIk221mtshLoM" + }}); + const img_blob = await image_fetch.blob() + return {name: data.product.name, price: userfields.kuelschrankpreis, img_blob: img_blob}; + } else { + return {name: data.product.name, price: userfields.kuelschrankpreis}; + } } export default addToCart; diff --git a/src/actions/checkout.tsx b/src/actions/checkout.tsx index 4a4ea37..5ca3cad 100644 --- a/src/actions/checkout.tsx +++ b/src/actions/checkout.tsx @@ -1,6 +1,7 @@ "use server" const API_KEY = "sup_sk_t6Jf0FwYUAkbjxzvbs6e3BkIePxm0OR3m" +const HOSTNAME = "kasse.fet.at" import SumUp from "@sumup/sdk"; @@ -13,10 +14,12 @@ const checkout = async (total: number) => { const merchantCode = (await client.merchant.getMerchantProfile()).merchant_code || ""; const readerId = (await client.readers.list(merchantCode)).items[0].id || ""; - const respomse = await client.readers.createCheckout(merchantCode, readerId, {total_amount: {value: total * 100, currency: "EUR", minor_unit: 2}}); + const response = await client.readers.createCheckout(merchantCode, readerId, { + total_amount: {value: total * 100, currency: "EUR", minor_unit: 2}, + return_url: `https://${HOSTNAME}/order-status` + }); await new Promise(resolve => setTimeout(resolve, 10000)); - const checkout = await client.transactions.get(merchantCode, {client_transaction_id: respomse.data?.client_transaction_id || ""}); - console.log("Checkout status:", checkout); + return response.data?.client_transaction_id || ""; } export default checkout; diff --git a/src/app/api/order-status/route.ts b/src/app/api/order-status/route.ts new file mode 100644 index 0000000..cd9edad --- /dev/null +++ b/src/app/api/order-status/route.ts @@ -0,0 +1,57 @@ +// app/api/order-status/[id]/route.ts +import { NextRequest, NextResponse } from "next/server"; +import { EventEmitter } from "stream"; + +export const orderEvents = new EventEmitter(); + +export async function GET(req: NextRequest) { + // const orderId = params.id; + const orderId = req.nextUrl.searchParams.get("id"); + + return new Response( + new ReadableStream({ + start(controller) { + const encoder = new TextEncoder(); + + const listener = (data: { id: string; event_type: string }) => { + // TODO!!!! UNCOMMEND THIS + // if (data.orderId != orderId) { + // return; + // } + console.error("THIS SHOULD BE UNCOMMENTED"); + console.log("Sending event:", data); + controller.enqueue(encoder.encode(`data: ${JSON.stringify(data)}\n\n`)); + }; + + // orderEvents.on("update", listener); + orderEvents.addListener("update", listener); + + // cleanup when client disconnects + req.signal.addEventListener("abort", () => { + orderEvents.off("update", listener); + controller.close(); + }); + }, + }), + { + headers: { + "Content-Type": "text/event-stream", + "Cache-Control": "no-cache", + Connection: "keep-alive", + }, + } + ); +} + + +export async function POST(req: NextRequest) { + + const body = await req.json(); + console.log("Webhook received:", body); + const event_type = body.event_type || ""; + const id = body.id || ""; + + orderEvents.emit("update", { id, event_type }); + + return NextResponse.json({ message: 'Webhook received' }); +} diff --git a/src/app/globals.css b/src/app/globals.css index a2dc41e..75ff022 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -1,26 +1,11 @@ @import "tailwindcss"; +@plugin "flyonui"; +@import "flyonui/variants.css"; +@plugin "@iconify/tailwind4"; +@source "./node_modules/flyonui/flyonui.js"; :root { --background: #ffffff; --foreground: #171717; } -@theme inline { - --color-background: var(--background); - --color-foreground: var(--foreground); - --font-sans: var(--font-geist-sans); - --font-mono: var(--font-geist-mono); -} - -@media (prefers-color-scheme: dark) { - :root { - --background: #0a0a0a; - --foreground: #ededed; - } -} - -body { - background: var(--background); - color: var(--foreground); - font-family: Arial, Helvetica, sans-serif; -} diff --git a/src/app/layout.tsx b/src/app/layout.tsx index f7fa87e..1fbe042 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,6 +1,7 @@ import type { Metadata } from "next"; -import { Geist, Geist_Mono } from "next/font/google"; +import { Geist, Geist_Mono, Inter_Tight } from "next/font/google"; import "./globals.css"; +import FlyonuiScript from '../components/FlyonuiScript'; const geistSans = Geist({ variable: "--font-geist-sans", @@ -24,11 +25,15 @@ export default function RootLayout({ }>) { return ( - - {children} - + +
+
+

Baroness

+
+ {children} +
+ + ); } diff --git a/src/app/page.tsx b/src/app/page.tsx index 128bc26..bb3e6b4 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,10 +1,20 @@ "use client" import addToCart from "@/actions/add-to-cart"; import checkout from "@/actions/checkout"; -import { useState } from "react"; +import { useEffect, useState } from "react"; + +const createTableImage = (img_blob: Blob | undefined) => { + if (!img_blob) { + return
?
+ } else { + return product image + } +} + +const quick_products = [ {name: "Cola"}, {name: "Fanta"}, {name: "Wasser"}, {name: "Red Bull"}, {name: "Bier"}, {name: "Wein"} ]; export default function Home() { - const [ cart, setCart ] = useState<{name: string, price: number}[]>([]); + const [ cart, setCart ] = useState<{name: string, price: number, img_blob?: Blob | undefined}[]>([]); const handleSubmit = async (formData: FormData) => { const barcode = formData.get("barcode")? Number(formData.get("barcode")) : 0; addToCart(barcode).then((item) => { @@ -17,25 +27,197 @@ export default function Home() { cart.forEach((item) => { total += (Number(item.price)); }); - checkout(total); - setCart([]); + const client_checkout_id = checkout(total); + setStatus("Initializing"); + window.HSOverlay.open('#transparent-modal'); } + + const [status, setStatus] = useState("NONE"); + + useEffect(() => { + const but = document.getElementById("open-modal"); + but?.addEventListener("click", () => { + window.HSOverlay.open('#failed-modal'); + }); + }, []); + + useEffect(() => { + const es = new EventSource(`/api/order-status/`); + console.log("EventSource created"); + + es.onmessage = (event) => { + const data = JSON.parse(event.data); + setStatus(data.event_type); + console.log("Received event:", data); + + switch(data.event_type) { + case "PENDING": + setStatus("Verarbeiteung..."); + break; + case "PAID": + // Order is completed + setStatus("Erfolgreich bezahlt!"); + window.HSOverlay.close('#transparent-modal') + window.HSOverlay.open('#success-modal'); + setStatus("NONE"); + setCart([]); + break; + case "FAILED": + window.HSOverlay.open('#failed-modal'); + setStatus("NONE"); + break; + default: + // Unknown event type + break; + } + }; + + return () => es.close(); + }, []); + return ( <> -

Barcode:

-
- - -
-

Cart:

- -
- -
+
+
+
+
+ + + + + + + + + + + + + + + +
Scanne den Barcode deines Produkts um es dem Warenkorb hinzuzufügen.
Überprüfe deinen Warenkorb und entferne Produkte, die du nicht kaufen möchtest.
Klicke anschließend auf Bezahlen.
Bezahlen mit Karte am Karten Terminal
+
+
+

Schnellauswahl:

+
+ {quick_products.map((item, index) => ( + + ))} +
+

Barcode:

+
+
+ + + + + +
+ +
+ +
+
+

Cart:

+ + + + + + + + + + + {cart.map((item, index) => ( + + + + + + + ))} + +
BildNamePreis
+
+ { createTableImage(item.img_blob) } +
+
{item.name}{item.price}€
+
+ +
+ +
+
+ + + + + + + ) } diff --git a/src/app/reader/page.tsx b/src/app/reader/page.tsx index d6b2708..c73f4c3 100644 --- a/src/app/reader/page.tsx +++ b/src/app/reader/page.tsx @@ -2,10 +2,15 @@ import getReaderList from "@/actions/getReaderList"; import registerReader from "@/actions/registerReader"; -import { useState } from "react"; +import { useEffect, useState } from "react"; const Page = () => { const [ readers, setReaders ] = useState(); + useEffect(() => { + getReaderList().then((readerList) => { + setReaders(readerList); + }); + }, readers); const handleRegisterReader = async (formData: FormData) => { const readername = formData.get("readername")?.toString() || ""; const pairingcode = formData.get("pairingcode")?.toString() || ""; diff --git a/src/components/FlyonuiScript.tsx b/src/components/FlyonuiScript.tsx new file mode 100644 index 0000000..9dc69a9 --- /dev/null +++ b/src/components/FlyonuiScript.tsx @@ -0,0 +1,47 @@ +// FlyonuiScript.tsx +'use client'; + +import { usePathname } from 'next/navigation'; +import { useEffect } from 'react'; + +// Optional third-party libraries +// import $ from 'jquery'; +// import _ from 'lodash'; +// import noUiSlider from 'nouislider'; +// import 'datatables.net'; +// import 'dropzone/dist/dropzone-min.js'; + +// window.$ = $; +// window._ = _; +// window.jQuery = $; +// window.DataTable = $.fn.dataTable; +// window.noUiSlider = noUiSlider; + +async function loadFlyonUI() { + return import('flyonui/flyonui'); +} + +export default function FlyonuiScript() { + const path = usePathname(); + + useEffect(() => { + const initFlyonUI = async () => { + await loadFlyonUI(); + }; + + initFlyonUI(); + }, []); + + useEffect(() => { + setTimeout(() => { + if ( + window.HSStaticMethods && + typeof window.HSStaticMethods.autoInit === 'function' + ) { + window.HSStaticMethods.autoInit(); + } + }, 100); + }, [path]); + + return null; +}