diff --git a/frontend/package-lock.json b/frontend/package-lock.json index f3c883d..70fe8be 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -23,6 +23,7 @@ "@radix-ui/react-slot": "^1.1.2", "@radix-ui/react-tabs": "^1.1.3", "@radix-ui/react-tooltip": "^1.1.8", + "@react-pdf/renderer": "^4.3.0", "@tailwindcss/vite": "^4.0.15", "@tanstack/react-form": "^1.2.1", "@tanstack/react-query": "^5.69.0", @@ -35,12 +36,14 @@ "dotenv": "^16.4.7", "hono": "^4.7.5", "js-cookie": "^3.0.5", + "jsbarcode": "^3.11.6", "jsonwebtoken": "^9.0.2", "lucide-react": "^0.483.0", "marked": "^15.0.8", "next-themes": "^0.4.6", "npm-check-updates": "^17.1.16", "react": "^19.0.0", + "react-barcode": "^1.6.1", "react-day-picker": "^8.10.1", "react-dom": "^19.0.0", "react-grid-layout": "^1.5.1", @@ -2114,6 +2117,180 @@ "integrity": "sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg==", "license": "MIT" }, + "node_modules/@react-pdf/fns": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@react-pdf/fns/-/fns-3.1.2.tgz", + "integrity": "sha512-qTKGUf0iAMGg2+OsUcp9ffKnKi41RukM/zYIWMDJ4hRVYSr89Q7e3wSDW/Koqx3ea3Uy/z3h2y3wPX6Bdfxk6g==", + "license": "MIT" + }, + "node_modules/@react-pdf/font": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@react-pdf/font/-/font-4.0.2.tgz", + "integrity": "sha512-/dAWu7Y2RD1RxarDZ9SkYPHgBYOhmcDnet4W/qN/m8k+A2Hr3ja54GymSR7GGxWBtxjKtNauVKrTa9LS1n8WUw==", + "license": "MIT", + "dependencies": { + "@react-pdf/pdfkit": "^4.0.3", + "@react-pdf/types": "^2.9.0", + "fontkit": "^2.0.2", + "is-url": "^1.2.4" + } + }, + "node_modules/@react-pdf/image": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@react-pdf/image/-/image-3.0.3.tgz", + "integrity": "sha512-lvP5ryzYM3wpbO9bvqLZYwEr5XBDX9jcaRICvtnoRqdJOo7PRrMnmB4MMScyb+Xw10mGeIubZAAomNAG5ONQZQ==", + "license": "MIT", + "dependencies": { + "@react-pdf/png-js": "^3.0.0", + "jay-peg": "^1.1.1" + } + }, + "node_modules/@react-pdf/layout": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@react-pdf/layout/-/layout-4.4.0.tgz", + "integrity": "sha512-Aq+Cc6JYausWLoks2FvHe3PwK9cTuvksB2uJ0AnkKJEUtQbvCq8eCRb1bjbbwIji9OzFRTTzZij7LzkpKHjIeA==", + "license": "MIT", + "dependencies": { + "@react-pdf/fns": "3.1.2", + "@react-pdf/image": "^3.0.3", + "@react-pdf/primitives": "^4.1.1", + "@react-pdf/stylesheet": "^6.1.0", + "@react-pdf/textkit": "^6.0.0", + "@react-pdf/types": "^2.9.0", + "emoji-regex": "^10.3.0", + "queue": "^6.0.1", + "yoga-layout": "^3.2.1" + } + }, + "node_modules/@react-pdf/pdfkit": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@react-pdf/pdfkit/-/pdfkit-4.0.3.tgz", + "integrity": "sha512-k+Lsuq8vTwWsCqTp+CCB4+2N+sOTFrzwGA7aw3H9ix/PDWR9QksbmNg0YkzGbLAPI6CeawmiLHcf4trZ5ecLPQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.20.13", + "@react-pdf/png-js": "^3.0.0", + "browserify-zlib": "^0.2.0", + "crypto-js": "^4.2.0", + "fontkit": "^2.0.2", + "jay-peg": "^1.1.1", + "linebreak": "^1.1.0", + "vite-compatible-readable-stream": "^3.6.1" + } + }, + "node_modules/@react-pdf/png-js": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@react-pdf/png-js/-/png-js-3.0.0.tgz", + "integrity": "sha512-eSJnEItZ37WPt6Qv5pncQDxLJRK15eaRwPT+gZoujP548CodenOVp49GST8XJvKMFt9YqIBzGBV/j9AgrOQzVA==", + "license": "MIT", + "dependencies": { + "browserify-zlib": "^0.2.0" + } + }, + "node_modules/@react-pdf/primitives": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@react-pdf/primitives/-/primitives-4.1.1.tgz", + "integrity": "sha512-IuhxYls1luJb7NUWy6q5avb1XrNaVj9bTNI40U9qGRuS6n7Hje/8H8Qi99Z9UKFV74bBP3DOf3L1wV2qZVgVrQ==", + "license": "MIT" + }, + "node_modules/@react-pdf/reconciler": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@react-pdf/reconciler/-/reconciler-1.1.4.tgz", + "integrity": "sha512-oTQDiR/t4Z/Guxac88IavpU2UgN7eR0RMI9DRKvKnvPz2DUasGjXfChAdMqDNmJJxxV26mMy9xQOUV2UU5/okg==", + "license": "MIT", + "dependencies": { + "object-assign": "^4.1.1", + "scheduler": "0.25.0-rc-603e6108-20241029" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/@react-pdf/reconciler/node_modules/scheduler": { + "version": "0.25.0-rc-603e6108-20241029", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.25.0-rc-603e6108-20241029.tgz", + "integrity": "sha512-pFwF6H1XrSdYYNLfOcGlM28/j8CGLu8IvdrxqhjWULe2bPcKiKW4CV+OWqR/9fT52mywx65l7ysNkjLKBda7eA==", + "license": "MIT" + }, + "node_modules/@react-pdf/render": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@react-pdf/render/-/render-4.3.0.tgz", + "integrity": "sha512-MdWfWaqO6d7SZD75TZ2z5L35V+cHpyA43YNRlJNG0RJ7/MeVGDQv12y/BXOJgonZKkeEGdzM3EpAt9/g4E22WA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.20.13", + "@react-pdf/fns": "3.1.2", + "@react-pdf/primitives": "^4.1.1", + "@react-pdf/textkit": "^6.0.0", + "@react-pdf/types": "^2.9.0", + "abs-svg-path": "^0.1.1", + "color-string": "^1.9.1", + "normalize-svg-path": "^1.1.0", + "parse-svg-path": "^0.1.2", + "svg-arc-to-cubic-bezier": "^3.2.0" + } + }, + "node_modules/@react-pdf/renderer": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@react-pdf/renderer/-/renderer-4.3.0.tgz", + "integrity": "sha512-28gpA69fU9ZQrDzmd5xMJa1bDf8t0PT3ApUKBl2PUpoE/x4JlvCB5X66nMXrfFrgF2EZrA72zWQAkvbg7TE8zw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.20.13", + "@react-pdf/fns": "3.1.2", + "@react-pdf/font": "^4.0.2", + "@react-pdf/layout": "^4.4.0", + "@react-pdf/pdfkit": "^4.0.3", + "@react-pdf/primitives": "^4.1.1", + "@react-pdf/reconciler": "^1.1.4", + "@react-pdf/render": "^4.3.0", + "@react-pdf/types": "^2.9.0", + "events": "^3.3.0", + "object-assign": "^4.1.1", + "prop-types": "^15.6.2", + "queue": "^6.0.1" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/@react-pdf/stylesheet": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@react-pdf/stylesheet/-/stylesheet-6.1.0.tgz", + "integrity": "sha512-BGZ2sYNUp38VJUegjva/jsri3iiRGnVNjWI+G9dTwAvLNOmwFvSJzqaCsEnqQ/DW5mrTBk/577FhDY7pv6AidA==", + "license": "MIT", + "dependencies": { + "@react-pdf/fns": "3.1.2", + "@react-pdf/types": "^2.9.0", + "color-string": "^1.9.1", + "hsl-to-hex": "^1.0.0", + "media-engine": "^1.0.3", + "postcss-value-parser": "^4.1.0" + } + }, + "node_modules/@react-pdf/textkit": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@react-pdf/textkit/-/textkit-6.0.0.tgz", + "integrity": "sha512-fDt19KWaJRK/n2AaFoVm31hgGmpygmTV7LsHGJNGZkgzXcFyLsx+XUl63DTDPH3iqxj3xUX128t104GtOz8tTw==", + "license": "MIT", + "dependencies": { + "@react-pdf/fns": "3.1.2", + "bidi-js": "^1.0.2", + "hyphen": "^1.6.4", + "unicode-properties": "^1.4.1" + } + }, + "node_modules/@react-pdf/types": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/@react-pdf/types/-/types-2.9.0.tgz", + "integrity": "sha512-ckj80vZLlvl9oYrQ4tovEaqKWP3O06Eb1D48/jQWbdwz1Yh7Y9v1cEmwlP8ET+a1Whp8xfdM0xduMexkuPANCQ==", + "license": "MIT", + "dependencies": { + "@react-pdf/font": "^4.0.2", + "@react-pdf/primitives": "^4.1.1", + "@react-pdf/stylesheet": "^6.1.0" + } + }, "node_modules/@remix-run/node": { "version": "2.16.3", "resolved": "https://registry.npmjs.org/@remix-run/node/-/node-2.16.3.tgz", @@ -2719,6 +2896,15 @@ "dev": true, "license": "Apache-2.0" }, + "node_modules/@swc/helpers": { + "version": "0.5.17", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.17.tgz", + "integrity": "sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.8.0" + } + }, "node_modules/@swc/types": { "version": "0.1.19", "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.19.tgz", @@ -3741,6 +3927,12 @@ "node": ">=6.5" } }, + "node_modules/abs-svg-path": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/abs-svg-path/-/abs-svg-path-0.1.1.tgz", + "integrity": "sha512-d8XPSGjfyzlXC3Xx891DJRyZfqk5JU0BJrDQcsWomFIV1/BIzPW5HDH5iDdWpqWaav0YVIEzT1RHTwWr0FFshA==", + "license": "MIT" + }, "node_modules/acorn": { "version": "8.14.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", @@ -3875,6 +4067,35 @@ "dev": true, "license": "MIT" }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "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/bidi-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/bidi-js/-/bidi-js-1.0.3.tgz", + "integrity": "sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==", + "license": "MIT", + "dependencies": { + "require-from-string": "^2.0.2" + } + }, "node_modules/binary-extensions": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", @@ -3912,6 +4133,24 @@ "node": ">=8" } }, + "node_modules/brotli": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/brotli/-/brotli-1.3.3.tgz", + "integrity": "sha512-oTKjJdShmDuGW94SyyaoQvAjf30dZaHnjJ8uAF+u2/vGJkJbJPJAT1gDiOJP5v1Zb6f9KEyW/1HpuaWIXtGHPg==", + "license": "MIT", + "dependencies": { + "base64-js": "^1.1.2" + } + }, + "node_modules/browserify-zlib": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", + "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", + "license": "MIT", + "dependencies": { + "pako": "~1.0.5" + } + }, "node_modules/browserslist": { "version": "4.24.4", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.4.tgz", @@ -4102,6 +4341,15 @@ "url": "https://polar.sh/cva" } }, + "node_modules/clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==", + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, "node_modules/clsx": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", @@ -4128,9 +4376,18 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, "license": "MIT" }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "license": "MIT", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -4178,6 +4435,12 @@ "node": ">= 8" } }, + "node_modules/crypto-js": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz", + "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==", + "license": "MIT" + }, "node_modules/csstype": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", @@ -4402,6 +4665,12 @@ "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==", "license": "MIT" }, + "node_modules/dfa": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/dfa/-/dfa-1.2.0.tgz", + "integrity": "sha512-ED3jP8saaweFTjeGX8HQPjeC1YYyZs98jGNZx6IiBvxW7JG5v492kamAQB3m2wop07CvU/RQmzcKr6bgcC5D/Q==", + "license": "MIT" + }, "node_modules/diff": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/diff/-/diff-7.0.0.tgz", @@ -4464,6 +4733,12 @@ "dev": true, "license": "ISC" }, + "node_modules/emoji-regex": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", + "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==", + "license": "MIT" + }, "node_modules/enhanced-resolve": { "version": "5.18.1", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.1.tgz", @@ -4764,11 +5039,19 @@ "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", "license": "MIT" }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true, "license": "MIT" }, "node_modules/fast-equals": { @@ -4895,6 +5178,23 @@ "dev": true, "license": "ISC" }, + "node_modules/fontkit": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/fontkit/-/fontkit-2.0.4.tgz", + "integrity": "sha512-syetQadaUEDNdxdugga9CpEYVaQIxOwk7GlwZWWZ19//qW4zE5bknOKeMBDYAASwnpaSHKJITRLMF9m1fp3s6g==", + "license": "MIT", + "dependencies": { + "@swc/helpers": "^0.5.12", + "brotli": "^1.3.2", + "clone": "^2.1.2", + "dfa": "^1.2.0", + "fast-deep-equal": "^3.1.3", + "restructure": "^3.0.0", + "tiny-inflate": "^1.0.3", + "unicode-properties": "^1.4.0", + "unicode-trie": "^2.0.0" + } + }, "node_modules/for-each": { "version": "0.3.5", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", @@ -5134,6 +5434,27 @@ "node": ">=16.9.0" } }, + "node_modules/hsl-to-hex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/hsl-to-hex/-/hsl-to-hex-1.0.0.tgz", + "integrity": "sha512-K6GVpucS5wFf44X0h2bLVRDsycgJmf9FF2elg+CrqD8GcFU8c6vYhgXn8NjUkFCwj+xDFb70qgLbTUm6sxwPmA==", + "license": "MIT", + "dependencies": { + "hsl-to-rgb-for-reals": "^1.1.0" + } + }, + "node_modules/hsl-to-rgb-for-reals": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/hsl-to-rgb-for-reals/-/hsl-to-rgb-for-reals-1.1.1.tgz", + "integrity": "sha512-LgOWAkrN0rFaQpfdWBQlv/VhkOxb5AsBjk6NQVx4yEzWS923T07X0M1Y0VNko2H52HeSpZrZNNMJ0aFqsdVzQg==", + "license": "ISC" + }, + "node_modules/hyphen": { + "version": "1.10.6", + "resolved": "https://registry.npmjs.org/hyphen/-/hyphen-1.10.6.tgz", + "integrity": "sha512-fXHXcGFTXOvZTSkPJuGOQf5Lv5T/R2itiiCVPg9LxAje5D00O0pP83yJShFq5V89Ly//Gt6acj7z8pbBr34stw==", + "license": "ISC" + }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -5202,6 +5523,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", + "license": "MIT" + }, "node_modules/is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", @@ -5311,6 +5638,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-url": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz", + "integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==", + "license": "MIT" + }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -5318,6 +5651,15 @@ "dev": true, "license": "ISC" }, + "node_modules/jay-peg": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/jay-peg/-/jay-peg-1.1.1.tgz", + "integrity": "sha512-D62KEuBxz/ip2gQKOEhk/mx14o7eiFRaU+VNNSP4MOiIkwb/D6B3G1Mfas7C/Fit8EsSV2/IWjZElx/Gs6A4ww==", + "license": "MIT", + "dependencies": { + "restructure": "^3.0.0" + } + }, "node_modules/jiti": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.4.2.tgz", @@ -5355,6 +5697,12 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/jsbarcode": { + "version": "3.11.6", + "resolved": "https://registry.npmjs.org/jsbarcode/-/jsbarcode-3.11.6.tgz", + "integrity": "sha512-G5TKGyKY1zJo0ZQKFM1IIMfy0nF2rs92BLlCz+cU4/TazIc4ZH+X1GYeDRt7TKjrYqmPfTjwTBkU/QnQlsYiuA==", + "license": "MIT" + }, "node_modules/jsesc": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", @@ -5696,6 +6044,25 @@ "url": "https://opencollective.com/parcel" } }, + "node_modules/linebreak": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/linebreak/-/linebreak-1.1.0.tgz", + "integrity": "sha512-MHp03UImeVhB7XZtjd0E4n6+3xr5Dq/9xI/5FptGk5FrbDR3zagPa2DS6U8ks/3HjbKWG9Q1M2ufOzxV2qLYSQ==", + "license": "MIT", + "dependencies": { + "base64-js": "0.0.8", + "unicode-trie": "^2.0.0" + } + }, + "node_modules/linebreak/node_modules/base64-js": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-0.0.8.tgz", + "integrity": "sha512-3XSA2cR/h/73EzlXXdU6YNycmYI7+kicTxks4eJg2g39biHR84slg2+des+p7iHYhbRg/udIS4TD53WabcOUkw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -5819,6 +6186,12 @@ "node": ">= 0.4" } }, + "node_modules/media-engine": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/media-engine/-/media-engine-1.0.3.tgz", + "integrity": "sha512-aa5tG6sDoK+k70B9iEX1NeyfT8ObCKhNDs6lJVpwF6r8vhUfuKMslIcirq6HIUYuuUYLefcEQOn9bSBOvawtwg==", + "license": "MIT" + }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -5924,6 +6297,15 @@ "node": ">=0.10.0" } }, + "node_modules/normalize-svg-path": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/normalize-svg-path/-/normalize-svg-path-1.1.0.tgz", + "integrity": "sha512-r9KHKG2UUeB5LoTouwDzBy2VxXlHsiM6fyLQvnJa0S5hrhzqElH/CH7TUGhT1fVvIYBIKf3OpY4YJ4CK+iaqHg==", + "license": "MIT", + "dependencies": { + "svg-arc-to-cubic-bezier": "^3.0.0" + } + }, "node_modules/npm-check-updates": { "version": "17.1.16", "resolved": "https://registry.npmjs.org/npm-check-updates/-/npm-check-updates-17.1.16.tgz", @@ -5997,6 +6379,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "license": "(MIT AND Zlib)" + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -6010,6 +6398,12 @@ "node": ">=6" } }, + "node_modules/parse-svg-path": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/parse-svg-path/-/parse-svg-path-0.1.2.tgz", + "integrity": "sha512-JyPSBnkTJ0AI8GGJLfMXvKq42cj5c006fnLz6fXy6zfoVjJizi8BNTpu8on8ziI1cKy9d9DGNuY17Ce7wuejpQ==", + "license": "MIT" + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -6088,6 +6482,12 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "license": "MIT" + }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -6135,6 +6535,15 @@ "node": ">=6" } }, + "node_modules/queue": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz", + "integrity": "sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==", + "license": "MIT", + "dependencies": { + "inherits": "~2.0.3" + } + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -6165,6 +6574,19 @@ "node": ">=0.10.0" } }, + "node_modules/react-barcode": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/react-barcode/-/react-barcode-1.6.1.tgz", + "integrity": "sha512-pc4ftnO5syHa/UjCruEeRsomlhoxKSugIgTA8T4dH0fvc89UMHL+/1Sp25IAphqG44pJkE5hMXhv89iS09jQyw==", + "license": "ISC", + "dependencies": { + "jsbarcode": "^3.8.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": "16 - 19" + } + }, "node_modules/react-day-picker": { "version": "8.10.1", "resolved": "https://registry.npmjs.org/react-day-picker/-/react-day-picker-8.10.1.tgz", @@ -6443,6 +6865,15 @@ "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", "license": "MIT" }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/resize-observer-polyfill": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz", @@ -6469,6 +6900,12 @@ "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" } }, + "node_modules/restructure": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/restructure/-/restructure-3.0.2.tgz", + "integrity": "sha512-gSfoiOEA0VPE6Tukkrr7I0RBdE0s7H1eFCDBk05l1KIQT1UIKNc5JZy6jdyW6eYH3aR3g5b3PuL77rq0hvwtAw==", + "license": "MIT" + }, "node_modules/reusify": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", @@ -6667,6 +7104,15 @@ "node": ">=8" } }, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, "node_modules/solid-js": { "version": "1.9.5", "resolved": "https://registry.npmjs.org/solid-js/-/solid-js-1.9.5.tgz", @@ -6733,6 +7179,15 @@ "integrity": "sha512-QzQxpoacatkreL6jsxnVb7X5R/pGw9OUv2qWTYWnmLpg4NdN31snPy/f3TdQE1ZUXaThRvj1Zw4/OGg0ZkaLMA==", "license": "MIT" }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -6759,6 +7214,12 @@ "node": ">=8" } }, + "node_modules/svg-arc-to-cubic-bezier": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/svg-arc-to-cubic-bezier/-/svg-arc-to-cubic-bezier-3.2.0.tgz", + "integrity": "sha512-djbJ/vZKZO+gPoSDThGNpKDO+o+bAeA4XQKovvkNCqnIS2t+S4qnLAGQhyyrulhCFRl1WWzAp0wUDV8PpTVU3g==", + "license": "ISC" + }, "node_modules/tailwind-merge": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.0.2.tgz", @@ -6793,6 +7254,12 @@ "node": ">=6" } }, + "node_modules/tiny-inflate": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz", + "integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==", + "license": "MIT" + }, "node_modules/tiny-invariant": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", @@ -6922,6 +7389,32 @@ "node": ">=18.17" } }, + "node_modules/unicode-properties": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/unicode-properties/-/unicode-properties-1.4.1.tgz", + "integrity": "sha512-CLjCCLQ6UuMxWnbIylkisbRj31qxHPAurvena/0iwSVbQ2G1VY5/HjV0IRabOEbDHlzZlRdCrD4NhB0JtU40Pg==", + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.0", + "unicode-trie": "^2.0.0" + } + }, + "node_modules/unicode-trie": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-trie/-/unicode-trie-2.0.0.tgz", + "integrity": "sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==", + "license": "MIT", + "dependencies": { + "pako": "^0.2.5", + "tiny-inflate": "^1.0.0" + } + }, + "node_modules/unicode-trie/node_modules/pako": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", + "integrity": "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==", + "license": "MIT" + }, "node_modules/unplugin": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-2.2.0.tgz", @@ -7042,6 +7535,12 @@ "which-typed-array": "^1.1.2" } }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, "node_modules/victory-vendor": { "version": "36.9.2", "resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-36.9.2.tgz", @@ -7136,6 +7635,20 @@ } } }, + "node_modules/vite-compatible-readable-stream": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/vite-compatible-readable-stream/-/vite-compatible-readable-stream-3.6.1.tgz", + "integrity": "sha512-t20zYkrSf868+j/p31cRIGN28Phrjm3nRSLR2fyc2tiWi4cZGVdv68yNlwnIINTkMTmPoMiSlc0OadaO7DXZaQ==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/web-encoding": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/web-encoding/-/web-encoding-1.1.5.tgz", @@ -7231,6 +7744,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/yoga-layout": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/yoga-layout/-/yoga-layout-3.2.1.tgz", + "integrity": "sha512-0LPOt3AxKqMdFBZA3HBAt/t/8vIKq7VaQYbuA8WxCgung+p9TVyKRYdpvCb80HcdTN2NkbIKbhNwKUfm3tQywQ==", + "license": "MIT" + }, "node_modules/zod": { "version": "3.24.2", "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.2.tgz", diff --git a/frontend/package.json b/frontend/package.json index dafe2de..f929d7b 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -27,6 +27,7 @@ "@radix-ui/react-slot": "^1.1.2", "@radix-ui/react-tabs": "^1.1.3", "@radix-ui/react-tooltip": "^1.1.8", + "@react-pdf/renderer": "^4.3.0", "@tailwindcss/vite": "^4.0.15", "@tanstack/react-form": "^1.2.1", "@tanstack/react-query": "^5.69.0", @@ -39,12 +40,14 @@ "dotenv": "^16.4.7", "hono": "^4.7.5", "js-cookie": "^3.0.5", + "jsbarcode": "^3.11.6", "jsonwebtoken": "^9.0.2", "lucide-react": "^0.483.0", "marked": "^15.0.8", "next-themes": "^0.4.6", "npm-check-updates": "^17.1.16", "react": "^19.0.0", + "react-barcode": "^1.6.1", "react-day-picker": "^8.10.1", "react-dom": "^19.0.0", "react-grid-layout": "^1.5.1", diff --git a/frontend/src/components/layout/side-components/logistics.tsx b/frontend/src/components/layout/side-components/logistics.tsx index 7a551d4..6b4c308 100644 --- a/frontend/src/components/layout/side-components/logistics.tsx +++ b/frontend/src/components/layout/side-components/logistics.tsx @@ -1,4 +1,4 @@ -import { Cylinder, Package, Truck } from "lucide-react"; +import { Barcode, Cylinder, Package, Truck } from "lucide-react"; import { SidebarGroup, SidebarGroupContent, @@ -15,6 +15,7 @@ const iconMap: any = { Package: Package, Truck: Truck, Cylinder: Cylinder, + Barcode: Barcode, }; export function LogisticsSideBar({ diff --git a/frontend/src/components/logistics/barcodeGenerator/BGPage.tsx b/frontend/src/components/logistics/barcodeGenerator/BGPage.tsx new file mode 100644 index 0000000..d8f0003 --- /dev/null +++ b/frontend/src/components/logistics/barcodeGenerator/BGPage.tsx @@ -0,0 +1,150 @@ +import { LstCard } from "@/components/extendedUI/LstCard"; +import { CardContent, CardFooter, CardHeader } from "@/components/ui/card"; +import { Checkbox } from "@/components/ui/checkbox"; +import { Collapsible, CollapsibleContent } from "@/components/ui/collapsible"; +import { getLanes } from "@/utils/querys/logistics/getWarehouseLanes"; +import { CollapsibleTrigger } from "@radix-ui/react-collapsible"; +import { useQuery } from "@tanstack/react-query"; +import { useState } from "react"; +import Barcode from "react-barcode"; +import { BarcodePDFExport } from "./BarcodeExport"; +import { BulkBarcodePDFExport } from "./BulkExport"; + +export default function BGPage() { + const { data, isError, isLoading } = useQuery(getLanes()); + const [checked, setChecked] = useState([]); + + if (isLoading) return
Loading Data
; + + if (isError) + return
There was an error getting the warehouse lane data.
; + + /** + * get the warehouse names only + */ + + const warhouses = new Map(); + + data?.forEach((item: any) => { + // if the warhouse is not already included add it to the map + if (!warhouses.has(item.warehouseId)) { + warhouses.set(item.warehouseId, item.warehouseDescription); + } + }); + + // convert the map to an array + const warehouseArray = Array.from(warhouses).map(([wid, wname]) => ({ + warehouseId: wid, + warehouseDescription: wname, + })); + + //console.log(warehouseArray); + + // handle the onchange + const changeBox = (d: any) => { + setChecked((prev: any) => { + if (prev.includes(d)) { + return prev.filter((name: any) => name !== d); + } else { + return [...prev, d]; + } + }); + }; + + return ( +
+
+ + Warehouse Barcodes + + {warehouseArray.map((i: any) => { + const lanes = data?.filter( + (wid: any) => wid.warehouseId === i.warehouseId + ); + return ( +
+ + + {i.warehouseDescription} + + +
+ {lanes?.map((l: any) => { + return ( +
+ + changeBox(l) + } + /> + +
+ ); + })} +
+
+
+
+ ); + })} +
+
+
+ {checked.length > 0 && ( +
+ + Current selected lanes + + {checked.map((c: any) => { + return ( +
+
+ +

+ Lane: {c.laneDescription} +

+
+
+ +
+
+ ); + })} +
+ +
+ {checked.length > 1 && ( +
+ +
+ )} +
+
+
+
+ )} +
+ ); +} diff --git a/frontend/src/components/logistics/barcodeGenerator/BarcodeExport.tsx b/frontend/src/components/logistics/barcodeGenerator/BarcodeExport.tsx new file mode 100644 index 0000000..da12d8d --- /dev/null +++ b/frontend/src/components/logistics/barcodeGenerator/BarcodeExport.tsx @@ -0,0 +1,100 @@ +import { Button } from "@/components/ui/button"; +import { + pdf, + Page, + Text, + View, + Document, + StyleSheet, + Image, +} from "@react-pdf/renderer"; +import JsBarcode from "jsbarcode"; + +export const BarcodePDFExport = ({ + barcodeValue, + data, +}: { + barcodeValue: any; + data: any; +}) => { + const generatePDF = () => { + //const barcodeValue = data; // Barcode value + const canvas = document.createElement("canvas"); + + // Generate barcode on the canvas + JsBarcode(canvas, barcodeValue, { + format: "CODE128", + displayValue: false, + }); + + // Convert canvas to base64 image data + const barcodeImage = canvas.toDataURL("image/png"); + + // Define the document styles using @react-pdf/renderer + const styles = StyleSheet.create({ + page: { + padding: 30, + }, + centerContent: { + display: "flex", + justifyContent: "center", // Center horizontally + alignItems: "center", // Center vertically + flexDirection: "column", // Stack items (barcode and description) vertically + height: "75%", // Ensure the container takes full page height + textAlign: "center", + }, + section: { + marginBottom: 10, + textAlign: "center", + }, + barcode: { + width: 800, // Width of the barcode + height: 200, // Height of the barcode + marginBottom: 10, + }, + description: { + fontSize: 28, + fontWeight: "bold", + marginTop: 10, + marginBottom: 20, // Ensure there's space below the text + }, + }); + + // Create the document + const MyDocument = ( + + + + + + + + + + Lane: {data.laneDescription} + + + + + + ); + + // Generate the PDF and trigger download + pdf(MyDocument) + .toBlob() + .then((blob) => { + const link = document.createElement("a"); + link.href = URL.createObjectURL(blob); + link.download = `${data.warehouseDescription}-${data.laneDescription}.pdf`; + link.click(); + }); + }; + + return ( +
+ +
+ ); +}; diff --git a/frontend/src/components/logistics/barcodeGenerator/BulkExport.tsx b/frontend/src/components/logistics/barcodeGenerator/BulkExport.tsx new file mode 100644 index 0000000..ee7c600 --- /dev/null +++ b/frontend/src/components/logistics/barcodeGenerator/BulkExport.tsx @@ -0,0 +1,127 @@ +import { Button } from "@/components/ui/button"; +import { + pdf, + Page, + Text, + View, + Document, + StyleSheet, + Image, +} from "@react-pdf/renderer"; +import JsBarcode from "jsbarcode"; + +export const BulkBarcodePDFExport = ({ data }: { data: any }) => { + const createBarcode = (barcodeValue: any) => { + //const barcodeValue = data; // Barcode value + const canvas = document.createElement("canvas"); + + // Generate barcode on the canvas + JsBarcode(canvas, barcodeValue, { + format: "CODE128", + displayValue: false, + }); + + // Convert canvas to base64 image data + const barcodeImage = canvas.toDataURL("image/png"); + + return barcodeImage; + }; + const generatePDF = () => { + // Define the document styles using @react-pdf/renderer + const styles = StyleSheet.create({ + page: { + padding: 30, + }, + centerContent: { + display: "flex", + justifyContent: "flex-start", // Center horizontally + alignItems: "center", // Center vertically + flexDirection: "row", // Stack items (barcode and description) vertically + //height: "5%", // Ensure the container takes full page height + textAlign: "center", + }, + section: { + marginBottom: 10, + textAlign: "center", + }, + barcode: { + width: 275, // Width of the barcode + height: 75, // Height of the barcode + marginBottom: 10, + }, + description: { + fontSize: 14, + fontWeight: "bold", + marginTop: 10, + marginBottom: 20, // Ensure there's space below the text + }, + + headerText: { + fontSize: 28, + fontWeight: "bold", + marginTop: 10, + marginBottom: 20, // Ensure there's space below the text + display: "flex", + justifyContent: "center", + //height: "15%", // Ensure the container takes full page height + textAlign: "center", + }, + + horizontalLine: { + borderBottom: "#000000", + borderBottomWidth: 1, + }, + }); + + // Create the document + const MyDocument = ( + + + + Multi Lane export. + + + + {data.map((i: any, index: any) => { + return ( + + + + + + + + Lane: {i.laneDescription} + + + + ); + })} + + + ); + + // Generate the PDF and trigger download + pdf(MyDocument) + .toBlob() + .then((blob) => { + const link = document.createElement("a"); + link.href = URL.createObjectURL(blob); + link.download = `MultipleBarcodes.pdf`; + link.click(); + }); + }; + + return ( +
+ +
+ ); +}; diff --git a/frontend/src/routeTree.gen.ts b/frontend/src/routeTree.gen.ts index 812a552..df9be59 100644 --- a/frontend/src/routeTree.gen.ts +++ b/frontend/src/routeTree.gen.ts @@ -35,6 +35,7 @@ import { Route as logisticsOpenOrdersIndexImport } from './routes/(logistics)/op import { Route as logisticsMaterialHelperIndexImport } from './routes/(logistics)/materialHelper/index' import { Route as logisticsHelperCommandsIndexImport } from './routes/(logistics)/helperCommands/index' import { Route as logisticsDmIndexImport } from './routes/(logistics)/dm/index' +import { Route as logisticsBarcodegenIndexImport } from './routes/(logistics)/barcodegen/index' import { Route as EomArticleAvImport } from './routes/_eom/article/$av' import { Route as logisticsSiloAdjustmentsHistImport } from './routes/(logistics)/siloAdjustments/$hist' import { Route as logisticsMaterialHelperSiloLinkIndexImport } from './routes/(logistics)/materialHelper/siloLink/index' @@ -187,6 +188,12 @@ const logisticsDmIndexRoute = logisticsDmIndexImport.update({ getParentRoute: () => rootRoute, } as any) +const logisticsBarcodegenIndexRoute = logisticsBarcodegenIndexImport.update({ + id: '/(logistics)/barcodegen/', + path: '/barcodegen/', + getParentRoute: () => rootRoute, +} as any) + const EomArticleAvRoute = EomArticleAvImport.update({ id: '/article/$av', path: '/article/$av', @@ -365,6 +372,13 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof EomArticleAvImport parentRoute: typeof EomImport } + '/(logistics)/barcodegen/': { + id: '/(logistics)/barcodegen/' + path: '/barcodegen' + fullPath: '/barcodegen' + preLoaderRoute: typeof logisticsBarcodegenIndexImport + parentRoute: typeof rootRoute + } '/(logistics)/dm/': { id: '/(logistics)/dm/' path: '/dm' @@ -494,6 +508,7 @@ export interface FileRoutesByFullPath { '/ocp': typeof OcpIndexRoute '/siloAdjustments/$hist': typeof logisticsSiloAdjustmentsHistRoute '/article/$av': typeof EomArticleAvRoute + '/barcodegen': typeof logisticsBarcodegenIndexRoute '/dm': typeof logisticsDmIndexRoute '/helperCommands': typeof logisticsHelperCommandsIndexRoute '/materialHelper': typeof logisticsMaterialHelperIndexRoute @@ -524,6 +539,7 @@ export interface FileRoutesByTo { '/ocp': typeof OcpIndexRoute '/siloAdjustments/$hist': typeof logisticsSiloAdjustmentsHistRoute '/article/$av': typeof EomArticleAvRoute + '/barcodegen': typeof logisticsBarcodegenIndexRoute '/dm': typeof logisticsDmIndexRoute '/helperCommands': typeof logisticsHelperCommandsIndexRoute '/materialHelper': typeof logisticsMaterialHelperIndexRoute @@ -557,6 +573,7 @@ export interface FileRoutesById { '/ocp/': typeof OcpIndexRoute '/(logistics)/siloAdjustments/$hist': typeof logisticsSiloAdjustmentsHistRoute '/_eom/article/$av': typeof EomArticleAvRoute + '/(logistics)/barcodegen/': typeof logisticsBarcodegenIndexRoute '/(logistics)/dm/': typeof logisticsDmIndexRoute '/(logistics)/helperCommands/': typeof logisticsHelperCommandsIndexRoute '/(logistics)/materialHelper/': typeof logisticsMaterialHelperIndexRoute @@ -589,6 +606,7 @@ export interface FileRouteTypes { | '/ocp' | '/siloAdjustments/$hist' | '/article/$av' + | '/barcodegen' | '/dm' | '/helperCommands' | '/materialHelper' @@ -618,6 +636,7 @@ export interface FileRouteTypes { | '/ocp' | '/siloAdjustments/$hist' | '/article/$av' + | '/barcodegen' | '/dm' | '/helperCommands' | '/materialHelper' @@ -649,6 +668,7 @@ export interface FileRouteTypes { | '/ocp/' | '/(logistics)/siloAdjustments/$hist' | '/_eom/article/$av' + | '/(logistics)/barcodegen/' | '/(logistics)/dm/' | '/(logistics)/helperCommands/' | '/(logistics)/materialHelper/' @@ -673,6 +693,7 @@ export interface RootRouteChildren { userPasswordChangeRoute: typeof userPasswordChangeRoute OcpIndexRoute: typeof OcpIndexRoute logisticsSiloAdjustmentsHistRoute: typeof logisticsSiloAdjustmentsHistRoute + logisticsBarcodegenIndexRoute: typeof logisticsBarcodegenIndexRoute logisticsDmIndexRoute: typeof logisticsDmIndexRoute logisticsHelperCommandsIndexRoute: typeof logisticsHelperCommandsIndexRoute logisticsMaterialHelperIndexRoute: typeof logisticsMaterialHelperIndexRoute @@ -696,6 +717,7 @@ const rootRouteChildren: RootRouteChildren = { userPasswordChangeRoute: userPasswordChangeRoute, OcpIndexRoute: OcpIndexRoute, logisticsSiloAdjustmentsHistRoute: logisticsSiloAdjustmentsHistRoute, + logisticsBarcodegenIndexRoute: logisticsBarcodegenIndexRoute, logisticsDmIndexRoute: logisticsDmIndexRoute, logisticsHelperCommandsIndexRoute: logisticsHelperCommandsIndexRoute, logisticsMaterialHelperIndexRoute: logisticsMaterialHelperIndexRoute, @@ -731,6 +753,7 @@ export const routeTree = rootRoute "/(user)/passwordChange", "/ocp/", "/(logistics)/siloAdjustments/$hist", + "/(logistics)/barcodegen/", "/(logistics)/dm/", "/(logistics)/helperCommands/", "/(logistics)/materialHelper/", @@ -826,6 +849,9 @@ export const routeTree = rootRoute "filePath": "_eom/article/$av.tsx", "parent": "/_eom" }, + "/(logistics)/barcodegen/": { + "filePath": "(logistics)/barcodegen/index.tsx" + }, "/(logistics)/dm/": { "filePath": "(logistics)/dm/index.tsx" }, diff --git a/frontend/src/routes/(logistics)/barcodegen/index.tsx b/frontend/src/routes/(logistics)/barcodegen/index.tsx new file mode 100644 index 0000000..7efb739 --- /dev/null +++ b/frontend/src/routes/(logistics)/barcodegen/index.tsx @@ -0,0 +1,14 @@ +import BGPage from "@/components/logistics/barcodeGenerator/BGPage"; +import { createFileRoute } from "@tanstack/react-router"; + +export const Route = createFileRoute("/(logistics)/barcodegen/")({ + component: RouteComponent, +}); + +function RouteComponent() { + return ( +
+ +
+ ); +} diff --git a/frontend/src/utils/querys/logistics/getWarehouseLanes.tsx b/frontend/src/utils/querys/logistics/getWarehouseLanes.tsx new file mode 100644 index 0000000..2671950 --- /dev/null +++ b/frontend/src/utils/querys/logistics/getWarehouseLanes.tsx @@ -0,0 +1,20 @@ +import { queryOptions } from "@tanstack/react-query"; +import axios from "axios"; + +export function getLanes() { + return queryOptions({ + queryKey: ["getLanes"], + queryFn: () => fetch(), + //enabled: + staleTime: 1000, + refetchInterval: 60 * 1000, + refetchOnWindowFocus: true, + }); +} + +const fetch = async () => { + const { data } = await axios.get(`/api/logistics/getactivelanes`); + // // if we are not localhost ignore the devDir setting. + // //const url: string = window.location.host.split(":")[0]; + return data.data ?? []; +}; diff --git a/server/services/logistics/controller/warehouse/activeWarehouseLanes.ts b/server/services/logistics/controller/warehouse/activeWarehouseLanes.ts new file mode 100644 index 0000000..4db3066 --- /dev/null +++ b/server/services/logistics/controller/warehouse/activeWarehouseLanes.ts @@ -0,0 +1,24 @@ +import { tryCatch } from "../../../../globalUtils/tryCatch.js"; +import { query } from "../../../sqlServer/prodSqlServer.js"; +import { activeWarehouseLanes } from "../../../sqlServer/querys/warehouse/activeWarehouseLanes.js"; + +export const getActiveWarehouseLanes = async () => { + const { data, error } = await tryCatch( + query(activeWarehouseLanes, "Get active warehouse lanes") + ); + + if (error) { + return { + success: false, + message: "Error getting active warehouse lanes", + data: error, + }; + } + const lanes: any = data as any; + + return { + success: true, + message: "Current active warehouse lanes.", + data: lanes.data, + }; +}; diff --git a/server/services/logistics/logisticsService.ts b/server/services/logistics/logisticsService.ts index 7f5f6c4..c4dc6af 100644 --- a/server/services/logistics/logisticsService.ts +++ b/server/services/logistics/logisticsService.ts @@ -17,6 +17,8 @@ import standardForcasttemplate from "./route/dm/getStandardForecastTemplate.js"; import postForecast from "./route/dm/forecastIn.js"; import outbound from "./route/getOutbound.js"; import { runHistoricalData } from "./controller/eom/historicalInv.js"; +import intervalChecks from "./route/getActiveLogistics.js"; +import getActiveLanes from "./route/getActiveLanes.js"; const app = new OpenAPIHono(); @@ -34,6 +36,7 @@ const routes = [ //warehouse getPPOO, getcyclecount, + getActiveLanes, //DM postBulkOrders, standardTemplate, @@ -41,6 +44,7 @@ const routes = [ standardForcasttemplate, // outbound deliveries outbound, + intervalChecks, ] as const; // app.route("/server", modules); diff --git a/server/services/logistics/route/getActiveLanes.ts b/server/services/logistics/route/getActiveLanes.ts new file mode 100644 index 0000000..10e6c79 --- /dev/null +++ b/server/services/logistics/route/getActiveLanes.ts @@ -0,0 +1,57 @@ +import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi"; +import { responses } from "../../../globalUtils/routeDefs/responses.js"; +import { tryCatch } from "../../../globalUtils/tryCatch.js"; +import { getCycleCountCheck } from "../controller/warehouse/cycleCountChecks/getCycleCountCheck.js"; +import { getPPOO } from "../controller/warehouse/ppoo/getPPOO.js"; +import { apiHit } from "../../../globalUtils/apiHits.js"; +import { getActiveWarehouseLanes } from "../controller/warehouse/activeWarehouseLanes.js"; + +const app = new OpenAPIHono(); + +// const Body = z +// .object({ +// age: z.number().optional().openapi({ example: 90 }), +// //email: z.string().optional().openapi({example: "s.smith@example.com"}), +// type: z.string().optional().openapi({ example: "fg" }), +// }) +// .openapi("User"); +app.openapi( + createRoute({ + tags: ["logistics"], + summary: "Returns current active lanes", + method: "get", + path: "/getactivelanes", + // request: { + // body: { + // content: { + // "application/json": { schema: Body }, + // }, + // }, + // }, + // description: + // "Provided a running number and lot number you can consume material.", + responses: responses(), + }), + async (c: any) => { + apiHit(c, { endpoint: "/getactivelanes" }); + + const { data: lanes, error } = await tryCatch( + getActiveWarehouseLanes() + ); + + if (error) { + return c.json({ + success: false, + message: "Error getting lane data.", + data: error, + }); + } + + return c.json({ + success: lanes.success, + message: lanes.message, + data: lanes.data, + }); + } +); +export default app; diff --git a/server/services/logistics/route/getActiveLogistics.ts b/server/services/logistics/route/getActiveLogistics.ts new file mode 100644 index 0000000..1a15d46 --- /dev/null +++ b/server/services/logistics/route/getActiveLogistics.ts @@ -0,0 +1,32 @@ +// an external way to creating logs +import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi"; +import { responses } from "../../../globalUtils/routeDefs/responses.js"; + +import { apiHit } from "../../../globalUtils/apiHits.js"; +import { getAllLogisticsJobs } from "../utils/logisticsIntervals.js"; + +const app = new OpenAPIHono({ strict: false }); + +app.openapi( + createRoute({ + tags: ["logistics"], + summary: "Returns current active logistics intervals.", + method: "get", + path: "/activelogistics", + //middleware: authMiddleware, + responses: responses(), + }), + async (c) => { + apiHit(c, { endpoint: "/activelogistics" }); + const jobs = getAllLogisticsJobs(); + return c.json({ + success: true, + message: + jobs.length === 0 + ? "There are no active logistics intervals Currently." + : "Current Active logistics intervals", + data: jobs, + }); + } +); +export default app; diff --git a/server/services/server/utils/subModuleCheck.ts b/server/services/server/utils/subModuleCheck.ts index 1db42dc..021708d 100644 --- a/server/services/server/utils/subModuleCheck.ts +++ b/server/services/server/utils/subModuleCheck.ts @@ -75,6 +75,23 @@ const newSubModules = [ active: false, subSubModule: [], }, + { + name: "Barcodes", + moduleName: "logistics", + description: "Barcodes, lanes and scanable", + link: "/barcodegen", + icon: "Barcode", + roles: [ + "viewer", + "technician", + "supervisor", + "manager", + "admin", + "systemAdmin", + ], + active: true, + subSubModule: [], + }, // admin module { diff --git a/server/services/sqlServer/querys/warehouse/activeWarehouseLanes.ts b/server/services/sqlServer/querys/warehouse/activeWarehouseLanes.ts new file mode 100644 index 0000000..ae7e1df --- /dev/null +++ b/server/services/sqlServer/querys/warehouse/activeWarehouseLanes.ts @@ -0,0 +1,15 @@ +export const activeWarehouseLanes = ` +select +w.IdWarenLager as warehouseId, +w.Bezeichnung as warehouseDescription, +IdLagerAbteilung as laneId, +b.Bezeichnung as laneDescription +--,* +from [AlplaPROD_test1].[dbo].[T_LagerAbteilungen] (nolock) b + +left join +AlplaPROD_test1.dbo.T_WarenLager (nolock) as w +on b.IdWarenLager = w.IdWarenLager + +where b.aktiv = 1 and w.idwarenlager not in (5,6) +`;