pull/32/head
suvodip ghosh 2025-04-22 13:46:38 +00:00
parent 10a2c0c2c3
commit 5a32c1a7d2
18 changed files with 2026 additions and 58 deletions

439
package-lock.json generated
View File

@ -14,6 +14,7 @@
"@radix-ui/react-select": "^2.1.6",
"@radix-ui/react-tabs": "^1.1.3",
"@radix-ui/react-toast": "^1.2.6",
"@react-pdf/renderer": "^4.3.0",
"@shadcn/ui": "^0.0.4",
"@types/date-fns": "^2.5.3",
"@types/react": "^19.0.12",
@ -2812,6 +2813,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/@rollup/pluginutils": {
"version": "5.1.4",
"resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.4.tgz",
@ -3175,6 +3350,15 @@
"integrity": "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==",
"license": "MIT"
},
"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/@types/babel__core": {
"version": "7.20.5",
"resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
@ -3775,6 +3959,12 @@
"license": "(Unlicense OR Apache-2.0)",
"optional": true
},
"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.1",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz",
@ -4206,6 +4396,15 @@
"url": "https://github.com/sponsors/wooorm"
}
},
"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",
@ -4299,12 +4498,30 @@
"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/browser-or-node": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/browser-or-node/-/browser-or-node-2.1.1.tgz",
"integrity": "sha512-8CVjaLJGuSKMVTxJ2DpBl5XnlNDiT4cQFeuCJJrvJmts9YrTZDizTX7PjC2s6W4x+MBGZeEY6dGMrF04/6Hgqg==",
"license": "MIT"
},
"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",
@ -4682,7 +4899,6 @@
"resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz",
"integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==",
"license": "MIT",
"optional": true,
"dependencies": {
"color-name": "^1.0.0",
"simple-swizzle": "^0.2.2"
@ -4757,6 +4973,12 @@
"uncrypto": "^0.1.3"
}
},
"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/css-selector-parser": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/css-selector-parser/-/css-selector-parser-3.1.2.tgz",
@ -4956,6 +5178,12 @@
"url": "https://github.com/sponsors/wooorm"
}
},
"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/didyoumean": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz",
@ -5198,6 +5426,15 @@
"integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==",
"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/execa": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/execa/-/execa-7.2.0.tgz",
@ -5227,6 +5464,12 @@
"integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
"license": "MIT"
},
"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==",
"license": "MIT"
},
"node_modules/fast-glob": {
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz",
@ -5349,6 +5592,32 @@
"node": ">=8"
}
},
"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/fontkit/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/for-each": {
"version": "0.3.5",
"resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz",
@ -6186,6 +6455,21 @@
"url": "https://opencollective.com/unified"
}
},
"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/html-escaper": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-3.0.3.tgz",
@ -6227,6 +6511,12 @@
"node": ">=14.18.0"
}
},
"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/ieee754": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
@ -6331,8 +6621,7 @@
"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",
"optional": true
"license": "MIT"
},
"node_modules/is-binary-path": {
"version": "2.1.0",
@ -6587,6 +6876,12 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"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/is-wsl": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz",
@ -6623,6 +6918,15 @@
"@pkgjs/parseargs": "^0.11.0"
}
},
"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": "1.21.7",
"resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz",
@ -6707,6 +7011,25 @@
"url": "https://github.com/sponsors/antonk52"
}
},
"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/lines-and-columns": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
@ -9301,6 +9624,12 @@
"integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==",
"license": "MIT"
},
"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/merge-stream": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
@ -11358,6 +11687,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/not": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/not/-/not-0.1.0.tgz",
@ -11535,6 +11873,12 @@
"integrity": "sha512-Y8f9qUlBzW8qauJjd/eu6jlpJZsuPJm2ZAV0cDVd420o4EdpH5RPdoCv+60/TdJflGatr4sDfpAL6ArWZbM5tA==",
"license": "MIT"
},
"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/parse-entities": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.2.tgz",
@ -11584,6 +11928,12 @@
"integrity": "sha512-twN+njEipszzlMJd4ONUYgSfZPDxgHhT9Ahed5uTigpQn90FggW4SA/AIPq/6a149fTbE9qBEcSwE3FAEp6wQQ==",
"license": "ISC"
},
"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/parse5": {
"version": "7.2.1",
"resolved": "https://registry.npmjs.org/parse5/-/parse5-7.2.1.tgz",
@ -11909,6 +12259,15 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"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",
@ -13880,6 +14239,15 @@
"url": "https://opencollective.com/unified"
}
},
"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/resolve": {
"version": "1.22.10",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz",
@ -13940,6 +14308,12 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"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/retext": {
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/retext/-/retext-9.0.0.tgz",
@ -14295,7 +14669,6 @@
"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",
"optional": true,
"dependencies": {
"is-arrayish": "^0.3.1"
}
@ -14600,6 +14973,12 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"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",
@ -14686,6 +15065,12 @@
"readable-stream": "3"
}
},
"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/tinyexec": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz",
@ -14828,6 +15213,32 @@
"integrity": "sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==",
"license": "MIT"
},
"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/unified": {
"version": "11.0.5",
"resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz",
@ -15474,6 +15885,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/vitefu": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/vitefu/-/vitefu-1.0.6.tgz",
@ -15777,6 +16202,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",

View File

@ -16,6 +16,7 @@
"@radix-ui/react-select": "^2.1.6",
"@radix-ui/react-tabs": "^1.1.3",
"@radix-ui/react-toast": "^1.2.6",
"@react-pdf/renderer": "^4.3.0",
"@shadcn/ui": "^0.0.4",
"@types/date-fns": "^2.5.3",
"@types/react": "^19.0.12",

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -8,6 +8,7 @@ import { Eye, EyeOff, Loader2 } from "lucide-react";
import { Separator } from "./ui/separator";
import { Label } from "./ui/label";
import { useIsLoggedIn } from '../lib/isLoggedIn';
import Loader from "./ui/loader";
interface AuthStatus {
message: string;
isError: boolean;
@ -17,6 +18,7 @@ interface UserRecord {
id: string;
email: string;
name?: string;
type?: string;
avatar?: string;
[key: string]: any;
}
@ -43,6 +45,7 @@ const LoginPage = () => {
id: string;
email: string;
name: string;
type: string;
avatar: string;
};
}
@ -54,6 +57,10 @@ const LoginPage = () => {
try {
const authData = await pb.collection("users").authWithPassword(email, password);
if (!authData?.token || !authData?.record) {
throw new Error("Authentication failed: No token or user record received");
}
const avatarUrl = authData.record.avatar ? pb.files.getUrl(authData.record, authData.record.avatar) : '';
const authResponse: AuthResponse = {
@ -62,17 +69,18 @@ const LoginPage = () => {
query: 'new',
id: authData.record.id,
email: authData.record.email,
name: authData.record.name || '',
name: authData.record.name || authData.record.email.split('@')[0], // Fallback name
type: authData.record.type || 'user',
avatar: authData.record.avatar || ''
}
};
await syncSessionWithBackend(authResponse, avatarUrl);
window.location.href = '/profile';
} catch (error) {
} catch (error: any) {
console.error("Login failed:", error);
setStatus({
message: "Login failed. Please check your credentials.",
message: error.message || "Login failed. Please check your credentials.",
isError: true
});
} finally {
@ -99,6 +107,7 @@ const LoginPage = () => {
id: authData.record.id,
email: authData.record.email || '',
name: authData.record.name || '',
type: authData.record.type || '',
avatar: authData.record.avatar || ''
}
};
@ -120,13 +129,14 @@ const LoginPage = () => {
try {
const response = await fetch('https://host-api.cs1.hz.siliconpin.com/v1/users/?query=login', {
method: 'POST',
credentials: 'include', // Important for cookies
credentials: 'include',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
query: 'new',
accessToken: authData.token,
email: authData.record.email,
name: authData.record.name,
type: authData.record.type,
avatar: avatarUrl,
isAuthenticated: true,
id: authData.record.id
@ -134,20 +144,22 @@ const LoginPage = () => {
});
if (!response.ok) {
throw new Error('Failed to sync session');
const errorData = await response.json().catch(() => ({}));
throw new Error(errorData.message || `HTTP error! status: ${response.status}`);
}
const data = await response.json();
console.log('Session synced with backend:', data);
} catch (error) {
return data;
} catch (error: any) {
console.error('Error syncing session:', error);
throw error; // Re-throw the error if you want calling functions to handle it
throw new Error(`Session sync failed: ${error.message}`);
}
};
const { isLoggedIn, loading, error } = useIsLoggedIn();
// console.log(isLoggedIn)
if(loading){
return <p>Loading...</p>
return <Loader />
}
if(isLoggedIn){
return (

View File

@ -0,0 +1,422 @@
import React, { useEffect, useState } from "react";
import { useIsLoggedIn } from '../../lib/isLoggedIn';
import Loader from "../../components/ui/loader";
import { PDFDownloadLink, PDFViewer } from '@react-pdf/renderer';
import InvoicePDF from "../../lib/InvoicePDF"; // We'll create this component next
export default function AllSellingList() {
const { isLoggedIn, loading, error, sessionData } = useIsLoggedIn();
const [billingData, setBillingData] = useState([]);
const [dataLoading, setDataLoading] = useState(true);
const [apiError, setApiError] = useState(null);
const [selectedItem, setSelectedItem] = useState(null);
const [showModal, setShowModal] = useState(false);
const [editMode, setEditMode] = useState(false);
const [formData, setFormData] = useState({
service: '',
tenure: 'monthly',
amount: '',
user: '',
status: 'pending'
});
const INVOICE_API_URL = 'https://host-api.cs1.hz.siliconpin.com/v1/users/';
useEffect(() => {
if (isLoggedIn && sessionData?.user_type === 'admin') {
fetchBillingData();
}
}, [isLoggedIn, sessionData]);
const fetchBillingData = async () => {
try {
const res = await fetch(`${INVOICE_API_URL}?query=all-selling-list`, {
method: 'GET',
credentials: 'include',
headers: {
'Content-Type': 'application/json'
}
});
if (!res.ok) throw new Error(`HTTP error! status: ${res.status}`);
const data = await res.json();
setBillingData(data.data || []);
} catch (err) {
setApiError(err.message);
} finally {
setDataLoading(false);
}
};
const handleViewItem = (item) => {
setSelectedItem(item);
setShowModal(true);
setEditMode(false);
};
const handleEditItem = (item) => {
setSelectedItem(item);
setFormData({
service: item.service,
tenure: item.tenure,
amount: item.amount,
user: item.user,
status: item.status
});
setEditMode(true);
setShowModal(true);
};
const handleDeleteItem = async (id) => {
if (!window.confirm('Are you sure you want to delete this billing record?')) return;
try {
const res = await fetch(`${INVOICE_API_URL}?query=delete-billing&id=${id}`, {
method: 'DELETE',
credentials: 'include',
headers: {
'Content-Type': 'application/json'
}
});
if (!res.ok) throw new Error(`HTTP error! status: ${res.status}`);
fetchBillingData();
} catch (err) {
setApiError(err.message);
}
};
const handleCreateNew = () => {
setSelectedItem(null);
setFormData({
service: '',
tenure: 'monthly',
amount: '',
user: '',
status: 'pending'
});
setEditMode(true);
setShowModal(true);
};
const handleSubmit = async (e) => {
e.preventDefault();
try {
const url = selectedItem
? `${INVOICE_API_URL}?query=update-billing&id=${selectedItem.id}`
: `${INVOICE_API_URL}?query=create-billing`;
const method = selectedItem ? 'PUT' : 'POST';
const res = await fetch(url, {
method,
credentials: 'include',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(formData)
});
if (!res.ok) throw new Error(`HTTP error! status: ${res.status}`);
fetchBillingData();
setShowModal(false);
} catch (err) {
setApiError(err.message);
}
};
const handleInputChange = (e) => {
const { name, value } = e.target;
setFormData(prev => ({
...prev,
[name]: value
}));
};
const closeModal = () => {
setShowModal(false);
setSelectedItem(null);
setEditMode(false);
};
const getStatusColor = (status) => {
switch (status) {
case 'completed': return 'bg-green-100 text-green-800';
case 'pending': return 'bg-yellow-100 text-yellow-800';
case 'failed': return 'bg-red-100 text-red-800';
default: return 'bg-gray-100 text-gray-800';
}
};
const formatDate = (dateString) => {
if (!dateString) return 'N/A';
const options = { year: 'numeric', month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' };
return new Date(dateString).toLocaleDateString(undefined, options);
};
const formatCurrency = (amount) => {
if (!amount) return '$0.00';
return new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD'
}).format(parseFloat(amount));
};
if (loading || dataLoading) return <Loader />;
if (error || apiError) return <p>Error: {error?.message || apiError}</p>;
if (!isLoggedIn || sessionData?.user_type !== 'admin') {
return <p className="text-center mt-8">You are not authorized to view this page. <a href="/" className="text-[#6d9e37]">Click Here</a> to go to the homepage.</p>;
}
return (
<section className="container mx-auto px-4 py-8">
<div className="flex justify-between items-center mb-6">
<h1 className="text-2xl font-bold">Billing Management</h1>
<button
onClick={handleCreateNew}
className="px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700"
>
Create New
</button>
</div>
<div className="bg-white rounded-lg shadow overflow-hidden">
<div className="overflow-x-auto">
<table className="min-w-full divide-y divide-gray-200">
<thead className="bg-gray-50">
<tr>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Billing ID</th>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Service</th>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">User</th>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Amount</th>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Status</th>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Created At</th>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Actions</th>
</tr>
</thead>
<tbody className="bg-white divide-y divide-gray-200">
{billingData.map((item) => (
<tr key={item.id} className="hover:bg-gray-50">
<td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">
{item.billing_id}
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
{item.service}
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
{item.user}
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-900 font-medium">
{formatCurrency(item.amount)}
</td>
<td className="px-6 py-4 whitespace-nowrap">
<span className={`px-2 inline-flex text-xs leading-5 font-semibold rounded-full ${getStatusColor(item.status)}`}>
{item.status.charAt(0).toUpperCase() + item.status.slice(1)}
</span>
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
{formatDate(item.created_at)}
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm font-medium">
<button
onClick={() => handleViewItem(item)}
className="text-indigo-600 hover:text-indigo-900 mr-2"
>
View
</button>
<button
onClick={() => handleEditItem(item)}
className="text-yellow-600 hover:text-yellow-900 mr-2"
>
Edit
</button>
<button
onClick={() => handleDeleteItem(item.id)}
className="text-red-600 hover:text-red-900 mr-2"
>
Delete
</button>
<PDFDownloadLink
document={<InvoicePDF data={item} />}
fileName={`invoice_${item.billing_id}.pdf`}
className="text-green-600 hover:text-green-900"
>
{({ loading }) => (loading ? 'Preparing...' : 'PDF')}
</PDFDownloadLink>
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
{/* Modal for View/Edit */}
{showModal && (
<div className="fixed inset-0 bg-gray-600 bg-opacity-50 flex items-center justify-center p-4 z-50">
<div className="bg-white rounded-lg shadow-xl max-w-2xl w-full max-h-[90vh] overflow-y-auto">
<div className="p-6">
<div className="flex justify-between items-start">
<h2 className="text-xl font-bold mb-4">
{editMode ? (selectedItem ? 'Edit Billing' : 'Create New Billing') : 'Billing Details'}
</h2>
<button
onClick={closeModal}
className="text-gray-500 hover:text-gray-700"
>
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
{editMode ? (
<form onSubmit={handleSubmit}>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">Service</label>
<input
type="text"
name="service"
value={formData.service}
onChange={handleInputChange}
className="w-full px-3 py-2 border border-gray-300 rounded-md"
required
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">Tenure</label>
<select
name="tenure"
value={formData.tenure}
onChange={handleInputChange}
className="w-full px-3 py-2 border border-gray-300 rounded-md"
>
<option value="monthly">Monthly</option>
<option value="yearly">Yearly</option>
<option value="one-time">One-time</option>
</select>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">Amount</label>
<input
type="number"
name="amount"
value={formData.amount}
onChange={handleInputChange}
className="w-full px-3 py-2 border border-gray-300 rounded-md"
step="0.01"
min="0"
required
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">User Email</label>
<input
type="email"
name="user"
value={formData.user}
onChange={handleInputChange}
className="w-full px-3 py-2 border border-gray-300 rounded-md"
required
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">Status</label>
<select
name="status"
value={formData.status}
onChange={handleInputChange}
className="w-full px-3 py-2 border border-gray-300 rounded-md"
>
<option value="pending">Pending</option>
<option value="completed">Completed</option>
<option value="failed">Failed</option>
</select>
</div>
</div>
<div className="mt-6 flex justify-end space-x-4">
<button
type="submit"
className="px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700"
>
{selectedItem ? 'Update' : 'Create'}
</button>
<button
type="button"
onClick={closeModal}
className="px-4 py-2 bg-gray-200 text-gray-800 rounded hover:bg-gray-300"
>
Cancel
</button>
</div>
</form>
) : (
<>
<div className="grid grid-cols-2 gap-4 mb-6">
<div>
<h3 className="font-semibold text-gray-700">Billing ID</h3>
<p>{selectedItem.billing_id}</p>
</div>
<div>
<h3 className="font-semibold text-gray-700">Service</h3>
<p>{selectedItem.service}</p>
</div>
<div>
<h3 className="font-semibold text-gray-700">User</h3>
<p>{selectedItem.user}</p>
</div>
<div>
<h3 className="font-semibold text-gray-700">Tenure</h3>
<p>{selectedItem.tenure}</p>
</div>
<div>
<h3 className="font-semibold text-gray-700">Amount</h3>
<p>{formatCurrency(selectedItem.amount)}</p>
</div>
<div>
<h3 className="font-semibold text-gray-700">Status</h3>
<span className={`px-2 inline-flex text-xs leading-5 font-semibold rounded-full ${getStatusColor(selectedItem.status)}`}>
{selectedItem.status.charAt(0).toUpperCase() + selectedItem.status.slice(1)}
</span>
</div>
<div>
<h3 className="font-semibold text-gray-700">Created At</h3>
<p>{formatDate(selectedItem.created_at)}</p>
</div>
<div>
<h3 className="font-semibold text-gray-700">Updated At</h3>
<p>{formatDate(selectedItem.updated_at)}</p>
</div>
</div>
<div className="mt-6 flex justify-end space-x-4">
<PDFDownloadLink
document={<InvoicePDF data={selectedItem} />}
fileName={`invoice_${selectedItem.billing_id}.pdf`}
className="px-4 py-2 bg-green-600 text-white rounded hover:bg-green-700"
>
{({ loading }) => (loading ? 'Preparing PDF...' : 'Download PDF')}
</PDFDownloadLink>
<button
onClick={() => handleEditItem(selectedItem)}
className="px-4 py-2 bg-yellow-600 text-white rounded hover:bg-yellow-700"
>
Edit
</button>
<button
onClick={closeModal}
className="px-4 py-2 bg-gray-200 text-gray-800 rounded hover:bg-gray-300"
>
Close
</button>
</div>
</>
)}
</div>
</div>
</div>
)}
</section>
);
}

View File

@ -1,7 +1,7 @@
import React, { useEffect, useState } from "react";
import TopicItems from "./TopicItem";
import { useIsLoggedIn } from '../lib/isLoggedIn';
import Loader from "./ui/loader";
const topicPageDesc = 'Cutting-edge discussions on tech, digital services, news, and digital freedom. Stay informed on AI, cybersecurity, privacy, and the future of innovation.';
export default function TopicCreation(props) {
@ -38,7 +38,7 @@ export default function TopicCreation(props) {
}, []);
if (authLoading || loading) {
return <div className="loading-indicator">Loading...</div>;
return <Loader />;
}
if (authError || error) {

View File

@ -11,7 +11,11 @@ export default function TopicDetail(props) {
return (
<div className="container mx-auto px-4 py-12">
<article className="max-w-4xl mx-auto">
{
props.topic.img && (
<img src={props.topic.img} alt={props.topic.title} className="w-full h-96 object-cover rounded-lg mb-8" />
)
}
<h1 className="text-4xl font-bold text-[#6d9e37] mb-4">{props.topic.title}</h1>
<div className="font-light mb-8 text-justify prose max-w-none" dangerouslySetInnerHTML={{ __html: marked.parse(props.topic.content || '') }}></div>
</article>

View File

@ -7,7 +7,7 @@ import { Button } from './ui/button';
import { Separator } from './ui/separator';
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from './ui/dialog';
import { CustomTabs } from './ui/tabs';
import Loader from "./ui/loader";
const TOPIC_API_URL = 'https://host-api.cs1.hz.siliconpin.com/v1/topics/';
const MINIO_UPLOAD_URL = 'https://your-minio-api-endpoint/upload';
@ -269,10 +269,7 @@ export default function EditTopic (){
// Loading state
if (isLoading) {
return (
<div className="container mx-auto px-4 py-8 text-center">
<div className="animate-spin rounded-full h-12 w-12 border-t-2 border-b-2 border-[#6d9e37] mx-auto"></div>
<p className="mt-4 text-gray-600">Topic Loading...</p>
</div>
<Loader />
);
}
@ -280,10 +277,10 @@ export default function EditTopic (){
if (success) {
return (
<div className="container mx-auto px-4 text-center py-8">
<h3 className="text-xl font-semibold text-green-600 mb-4">Topic has been successfully updated!</h3>
<h3 className="text-xl font-semibold mb-4">Topic has been successfully updated!</h3>
<p className="mb-4">You are being automatically redirected to the topic page...</p>
<div className="flex justify-center gap-4">
<Button onClick={() => navigate(`/topic/${formData.slug}`)}>Preview this Topic</Button>
<Button onClick={() => window.location.href = `/topic/${formData.slug}`}>Preview this Topic</Button>
</div>
</div>
);

View File

@ -1,11 +1,13 @@
import React from "react";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "./ui/card";
import { Button } from "./ui/button";
import { Input } from "./ui/input";
import { useIsLoggedIn } from '../lib/isLoggedIn';
import { Pencil, Trash2 } from "lucide-react"; // Import icons for better visual
import { Pencil, Trash2, Search } from "lucide-react";
import { marked } from 'marked';
export default function TopicItems(props) {
const { isLoggedIn, loading, error, sessionData } = useIsLoggedIn();
const [localSearchTerm, setLocalSearchTerm] = React.useState(props.searchTerm || '');
if (loading) {
return <div className="loading-indicator">Loading...</div>;
@ -15,11 +17,33 @@ export default function TopicItems(props) {
return <div className="error-message">Error loading authentication status</div>;
}
const handleSearchChange = (e) => {
setLocalSearchTerm(e.target.value);
};
const handleSubmit = (e) => {
e.preventDefault();
props.onSearch(e);
};
return (
<section className="container mx-auto px-4">
<div className="py-8 text-center">
<h2 className="text-3xl sm:text-4xl font-bold text-[#6d9e37] mb-3 sm:mb-4">{props.title}</h2>
<p className="text-lg sm:text-xl max-w-3xl mx-auto text-neutral-300">{props.description}</p>
<form onSubmit={handleSubmit} className="flex gap-2 max-w-xl mx-auto mt-4">
<Input
type="text"
name="search"
placeholder="Search Topic..."
value={localSearchTerm}
onChange={handleSearchChange}
/>
<Button type="submit">
<Search className="h-4 w-4 mr-2" />
Search
</Button>
</form>
</div>
{
props.topics.length > 0 ? (
@ -28,17 +52,13 @@ export default function TopicItems(props) {
props.topics.map((topic) => (
<a href={`/topic/${topic.slug}`} key={topic.id} className="hover:scale-[1.02] transition-transform duration-200 ">
<Card className="h-full flex flex-col group relative">
<div className="relative">
<img src={topic.img} alt={topic.title} className="aspect-video object-cover rounded-t-lg relative" loading="lazy" />
<div className="">
<img src={topic.img ? topic.img : '/assets/images/thumb-place.jpg'} alt={topic.title} className="aspect-video object-cover rounded-t-lg" loading="lazy" />
</div>
<CardContent className="flex-1 p-6">
<CardTitle className="mb-2 line-clamp-1">{topic.title}</CardTitle>
<CardDescription className="line-clamp-3 mb-4">
{topic.description}
<CardDescription className="line-clamp-4 mb-4" dangerouslySetInnerHTML={{ __html: marked.parse(topic.content || '') }}>
</CardDescription>
{
// console.log('props.mytopic', props.mytopic)
}
{isLoggedIn && sessionData.user_email === topic.user && props.mytopic === true && (
<div className="flex justify-end gap-2 mt-4 opacity-0 group-hover:opacity-100 transition-opacity duration-200">
<Button variant="outline" size="sm" className="gap-1"

View File

@ -0,0 +1,232 @@
import React, { useState, useEffect } from "react";
import TopicItems from "./TopicItem";
import { useIsLoggedIn } from '../lib/isLoggedIn';
import { Button } from "./ui/button";
const topicPageDesc = 'Cutting-edge discussions on tech, digital services, news, and digital freedom. Stay informed on AI, cybersecurity, privacy, and the future of innovation.';
export default function TopicCreation() {
const { isLoggedIn, loading: authLoading, error: authError } = useIsLoggedIn();
const [topics, setTopics] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
const [pagination, setPagination] = useState({
current_page: 1,
last_page: 1,
per_page: 10,
total: 0
});
// Get current page from URL or default to 1
const getCurrentPage = () => {
const params = new URLSearchParams(window.location.search);
const page = parseInt(params.get('page')) || 1;
return Math.max(1, Math.min(page, pagination.last_page));
};
// Fetch topics data with abort controller
const fetchTopics = async (page) => {
setLoading(true);
try {
const response = await fetch(
`https://host-api.cs1.hz.siliconpin.com/v1/topics/?query=get-all-topics&page=${page}`,
{
method: 'GET',
credentials: 'include'
}
);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
setTopics(data.data || []);
setPagination(prev => ({
...data.pagination,
current_page: Math.min(data.pagination.current_page, data.pagination.last_page)
}));
} catch (err) {
setError(err.message);
console.error('Fetch error:', err);
} finally {
setLoading(false);
}
};
// Handle page change
const handlePageChange = (newPage) => {
const validatedPage = Math.max(1, Math.min(newPage, pagination.last_page));
window.history.pushState({}, '', `?page=${validatedPage}`);
fetchTopics(validatedPage);
window.scrollTo({ top: 0, behavior: 'smooth' });
};
// Initial load and URL change handling
useEffect(() => {
fetchTopics(getCurrentPage());
const handlePopState = () => {
fetchTopics(getCurrentPage());
};
window.addEventListener('popstate', handlePopState);
return () => {
window.removeEventListener('popstate', handlePopState);
};
}, []);
if (authLoading) {
return <div className="flex justify-center items-center h-64">
<div className="animate-spin rounded-full h-12 w-12 border-t-2 border-b-2 border-blue-500"></div>
</div>;
}
if (authError) {
return <div className="error-message p-4 bg-red-100 text-red-700 rounded">Error loading authentication status</div>;
}
return (
<>
{isLoggedIn && (
<div className="container mx-auto flex justify-end gap-x-4 mb-4">
<a href="/topic/new" className="create-new-link">Create New</a>
<a href="/topic/my-topic">My Topics</a>
</div>
)}
{loading && !topics.length ? (
<div className="flex justify-center items-center h-64">
<div className="animate-spin rounded-full h-12 w-12 border-t-2 border-b-2 border-blue-500"></div>
</div>
) : error ? (
<div className="error-message p-4 bg-red-100 text-red-700 rounded">Error loading topics: {error}</div>
) : (
<>
<TopicItems topics={topics} title="SoliconPin Topics" description={topicPageDesc} />
{pagination.last_page > 1 && (
<div className="flex flex-col justify-between items-center mt-8 gap-4">
<div className="text-sm text-gray-600">
Showing {(pagination.current_page - 1) * pagination.per_page + 1}-
{Math.min(pagination.current_page * pagination.per_page, pagination.total)} of {pagination.total} topics
</div>
<div className="flex items-center gap-2">
{
pagination.current_page > 1 && (
<>
<Button
size="sm"
variant="outline"
onClick={() => handlePageChange(1)}
disabled={pagination.current_page <= 1}
className="hidden sm:inline-flex"
>
First
</Button>
<Button
size="sm"
variant="outline"
onClick={() => handlePageChange(pagination.current_page - 1)}
disabled={pagination.current_page <= 1}
>
Previous
</Button>
</>
)
}
<div className="flex items-center gap-1">
{generatePageNumbers(pagination.current_page, pagination.last_page).map((page, i) => (
page === '...' ? (
<span key={i} className="px-2">...</span>
) : (
<Button
key={i}
variant={page === pagination.current_page ? "default" : "outline"}
onClick={() => handlePageChange(page)}
className="min-w-10"
>
{page}
</Button>
)
))}
</div>
<Button
size="sm"
variant="outline"
onClick={() => handlePageChange(pagination.current_page + 1)}
disabled={pagination.current_page >= pagination.last_page}
>
Next
</Button>
<Button
size="sm"
variant="outline"
onClick={() => handlePageChange(pagination.last_page)}
disabled={pagination.current_page >= pagination.last_page}
className="hidden sm:inline-flex"
>
Last
</Button>
</div>
</div>
)}
</>
)}
</>
);
}
// Helper function to generate smart page numbers
function generatePageNumbers(currentPage, lastPage) {
const pages = [];
const maxVisible = 5; // Maximum visible page numbers
if (lastPage <= maxVisible) {
for (let i = 1; i <= lastPage; i++) {
pages.push(i);
}
} else {
// Always show first page
pages.push(1);
// Calculate start and end of middle pages
let start = Math.max(2, currentPage - 1);
let end = Math.min(lastPage - 1, currentPage + 1);
// Adjust if we're at the beginning
if (currentPage <= 3) {
end = maxVisible - 2;
}
// Adjust if we're at the end
if (currentPage >= lastPage - 2) {
start = lastPage - (maxVisible - 2);
}
// Add ellipsis if needed
if (start > 2) {
pages.push('...');
}
// Add middle pages
for (let i = start; i <= end; i++) {
pages.push(i);
}
// Add ellipsis if needed
if (end < lastPage - 1) {
pages.push('...');
}
// Always show last page
pages.push(lastPage);
}
return pages;
}

View File

@ -1,29 +1,262 @@
import React from "react";
import React, { useState, useEffect } from "react";
import TopicItems from "./TopicItem";
import { useIsLoggedIn } from '../lib/isLoggedIn';
import { Button } from "./ui/button";
import Loader from "./ui/loader";
const topicPageDesc = 'Cutting-edge discussions on tech, digital services, news, and digital freedom. Stay informed on AI, cybersecurity, privacy, and the future of innovation.';
export default function TopicCreation(props) {
const { isLoggedIn, loading, error } = useIsLoggedIn();
export default function TopicCreation() {
const { isLoggedIn, loading: authLoading, error: authError } = useIsLoggedIn();
const [topics, setTopics] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
const [searchTerm, setSearchTerm] = useState('');
const [pagination, setPagination] = useState({
current_page: 1,
last_page: 1,
per_page: 10,
total: 0
});
if (loading) {
return <div className="loading-indicator">Loading...</div>;
// Get current page from URL or default to 1
const getCurrentPage = () => {
const params = new URLSearchParams(window.location.search);
const page = parseInt(params.get('page')) || 1;
return Math.max(1, Math.min(page, pagination.last_page));
};
// Fetch topics data
const fetchTopics = async (page, search = '') => {
setLoading(true);
try {
let url = `https://host-api.cs1.hz.siliconpin.com/v1/topics/?query=get-all-topics&page=${page}`;
if (search) {
url += `&search=${encodeURIComponent(search)}`;
}
if (error) {
return <div className="error-message">Error loading authentication status</div>;
const response = await fetch(url, {
method: 'GET',
credentials: 'include'
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
setTopics(data.data || []);
setPagination(prev => ({
...data.pagination,
current_page: Math.min(data.pagination.current_page, data.pagination.last_page)
}));
setSearchTerm(data.search_term || '');
} catch (err) {
setError(err.message);
console.error('Fetch error:', err);
} finally {
setLoading(false);
}
};
// Handle page change
const handlePageChange = (newPage) => {
const validatedPage = Math.max(1, Math.min(newPage, pagination.last_page));
const params = new URLSearchParams(window.location.search);
params.set('page', validatedPage);
window.history.pushState({}, '', `?${params.toString()}`);
fetchTopics(validatedPage, searchTerm);
window.scrollTo({ top: 0, behavior: 'smooth' });
};
// Handle search
const handleSearch = (e) => {
e.preventDefault();
const newSearchTerm = e.target.elements.search.value.trim();
setSearchTerm(newSearchTerm);
// Reset to page 1 when searching
const params = new URLSearchParams(window.location.search);
params.set('page', 1);
if (newSearchTerm) {
params.set('search', newSearchTerm);
} else {
params.delete('search');
}
window.history.pushState({}, '', `?${params.toString()}`);
fetchTopics(1, newSearchTerm);
};
// Initial load and URL change handling
useEffect(() => {
const params = new URLSearchParams(window.location.search);
const initialSearch = params.get('search') || '';
setSearchTerm(initialSearch);
fetchTopics(getCurrentPage(), initialSearch);
const handlePopState = () => {
const newParams = new URLSearchParams(window.location.search);
const newSearch = newParams.get('search') || '';
setSearchTerm(newSearch);
fetchTopics(getCurrentPage(), newSearch);
};
window.addEventListener('popstate', handlePopState);
return () => {
window.removeEventListener('popstate', handlePopState);
};
}, []);
// ... (keep existing authLoading and authError checks)
return (
<>
{isLoggedIn && (
<div className="container mx-auto flex justify-end gap-x-4">
<div className="container mx-auto flex justify-end gap-x-4 mb-4">
<a href="/topic/new" className="create-new-link">Create New</a>
<a href="/topic/my-topic">My Topics</a>
</div>
)}
<TopicItems topics={props.topics} title="SoliconPin Topics" description={topicPageDesc} />
{loading && !topics.length ? (
<Loader />
) : error ? (
<div className="error-message p-4 bg-red-100 text-red-700 rounded">Error loading topics: {error}</div>
) : (
<>
<TopicItems
topics={topics}
title="SoliconPin Topics"
description={topicPageDesc}
onSearch={handleSearch}
searchTerm={searchTerm}
/>
{pagination.last_page > 1 && (
<div className="flex flex-col justify-between items-center mt-8 gap-4">
<div className="text-sm text-gray-600">
Showing {(pagination.current_page - 1) * pagination.per_page + 1}-
{Math.min(pagination.current_page * pagination.per_page, pagination.total)} of {pagination.total} topics
{searchTerm && (
<span className="ml-2">matching "{searchTerm}"</span>
)}
</div>
<div className="flex items-center gap-2">
{
pagination.current_page > 1 && (
<>
<Button
size="sm"
variant="outline"
onClick={() => handlePageChange(1)}
disabled={pagination.current_page <= 1}
className="hidden sm:inline-flex"
>
First
</Button>
<Button
size="sm"
variant="outline"
onClick={() => handlePageChange(pagination.current_page - 1)}
disabled={pagination.current_page <= 1}
>
Previous
</Button>
</>
)
}
<div className="flex items-center gap-1">
{generatePageNumbers(pagination.current_page, pagination.last_page).map((page, i) => (
page === '...' ? (
<span key={i} className="px-2">...</span>
) : (
<Button
key={i}
variant={page === pagination.current_page ? "default" : "outline"}
onClick={() => handlePageChange(page)}
className="min-w-10"
>
{page}
</Button>
)
))}
</div>
<Button
size="sm"
variant="outline"
onClick={() => handlePageChange(pagination.current_page + 1)}
disabled={pagination.current_page >= pagination.last_page}
>
Next
</Button>
<Button
size="sm"
variant="outline"
onClick={() => handlePageChange(pagination.last_page)}
disabled={pagination.current_page >= pagination.last_page}
className="hidden sm:inline-flex"
>
Last
</Button>
</div>
</div>
)}
</>
)}
</>
);
}
// Helper function to generate smart page numbers
function generatePageNumbers(currentPage, lastPage) {
const pages = [];
const maxVisible = 5; // Maximum visible page numbers
if (lastPage <= maxVisible) {
for (let i = 1; i <= lastPage; i++) {
pages.push(i);
}
} else {
// Always show first page
pages.push(1);
// Calculate start and end of middle pages
let start = Math.max(2, currentPage - 1);
let end = Math.min(lastPage - 1, currentPage + 1);
// Adjust if we're at the beginning
if (currentPage <= 3) {
end = maxVisible - 2;
}
// Adjust if we're at the end
if (currentPage >= lastPage - 2) {
start = lastPage - (maxVisible - 2);
}
// Add ellipsis if needed
if (start > 2) {
pages.push('...');
}
// Add middle pages
for (let i = start; i <= end; i++) {
pages.push(i);
}
// Add ellipsis if needed
if (end < lastPage - 1) {
pages.push('...');
}
// Always show last page
pages.push(lastPage);
}
return pages;
}

View File

@ -9,7 +9,7 @@ import { Textarea } from "./ui/textarea";
import React, { useState, useEffect } from 'react';
import UpdateAvatar from './UpdateAvatar';
import {localizeTime} from "../lib/localizeTime";
import Loader from "./ui/loader";
interface SessionData {
[key: string]: any;
}
@ -95,7 +95,7 @@ export default function ProfilePage() {
}
if (!userData) {
return (<div>Loading profile data...</div>);
return (<Loader />);
}
return (
<div className="space-y-6 container mx-auto">

View File

@ -0,0 +1,80 @@
import React, { useEffect } from 'react';
const Loader = () => {
// CSS styles object
const styles = {
container: {
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
height: '100vh',
width: '100%',
},
loader: {
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
marginBottom: '16px',
},
dot: {
width: '12px',
height: '12px',
margin: '0 4px',
backgroundColor: '#6d9e37',
borderRadius: '50%',
display: 'inline-block',
animation: 'bounce 1.4s infinite ease-in-out both',
},
dot1: {
animationDelay: '-0.32s',
},
dot2: {
animationDelay: '-0.16s',
},
text: {
color: '#6d9e37',
fontSize: '1rem',
fontWeight: '500',
},
// Keyframes as a string to be injected
keyframes: `
@keyframes bounce {
0%, 80%, 100% {
transform: scale(0);
}
40% {
transform: scale(1.0);
}
}
`,
};
useEffect(() => {
// Only run on client-side where document is available
if (typeof document !== 'undefined') {
const styleSheet = document.styleSheets[0];
try {
styleSheet.insertRule(styles.keyframes, styleSheet.cssRules.length);
} catch (e) {
// Fallback for browsers that might not support this
const styleElement = document.createElement('style');
styleElement.innerHTML = styles.keyframes;
document.head.appendChild(styleElement);
}
}
}, []); // Empty dependency array means this runs once on mount
return (
<div style={styles.container}>
<div style={styles.loader}>
<div style={{ ...styles.dot, ...styles.dot1 }}></div>
<div style={{ ...styles.dot, ...styles.dot2 }}></div>
<div style={styles.dot}></div>
</div>
<p style={styles.text}>Loading...</p>
</div>
);
};
export default Loader;

187
src/lib/InvoicePDF.jsx Normal file
View File

@ -0,0 +1,187 @@
import React from 'react';
import { Page, Text, View, Document, StyleSheet } from '@react-pdf/renderer';
// Create styles
const styles = StyleSheet.create({
page: {
flexDirection: 'column',
backgroundColor: '#FFFFFF',
padding: 40
},
header: {
flexDirection: 'row',
justifyContent: 'space-between',
marginBottom: 20,
borderBottomWidth: 2,
borderBottomColor: '#6d9e37',
paddingBottom: 10
},
title: {
fontSize: 24,
fontWeight: 'bold',
color: '#6d9e37'
},
section: {
marginBottom: 20
},
row: {
flexDirection: 'row',
justifyContent: 'space-between',
marginBottom: 5
},
label: {
fontSize: 12,
fontWeight: 'bold'
},
value: {
fontSize: 12
},
divider: {
borderBottomWidth: 1,
borderBottomColor: '#EEEEEE',
marginVertical: 10
},
tableHeader: {
flexDirection: 'row',
backgroundColor: '#F5F5F5',
padding: 5,
marginBottom: 5
},
tableRow: {
flexDirection: 'row',
padding: 5,
borderBottomWidth: 1,
borderBottomColor: '#EEEEEE'
},
col1: {
width: '40%'
},
col2: {
width: '30%',
textAlign: 'right'
},
col3: {
width: '30%',
textAlign: 'right'
},
total: {
flexDirection: 'row',
justifyContent: 'flex-end',
marginTop: 10
},
totalText: {
fontSize: 14,
fontWeight: 'bold'
},
footer: {
position: 'absolute',
bottom: 30,
left: 40,
right: 40,
textAlign: 'center',
fontSize: 10,
color: '#999999'
},
status: {
padding: 3,
borderRadius: 3,
fontSize: 10,
fontWeight: 'bold'
}
});
const InvoicePDF = ({ data }) => {
const statusColor = data.status === 'completed' ? '#10B981' : '#EF4444';
return (
<Document>
<Page size="A4" style={styles.page}>
{/* Header */}
<View style={styles.header}>
<View>
<Text style={styles.title}>INVOICE</Text>
<Text style={styles.label}>Invoice #: {data.billing_id}</Text>
<Text style={styles.label}>Date: {new Date(data.created_at).toLocaleDateString()}</Text>
</View>
<View>
<Text style={styles.label}>Your Company</Text>
<Text style={styles.value}>123 Business Street</Text>
<Text style={styles.value}>City, Country</Text>
<Text style={styles.value}>contact@yourcompany.com</Text>
</View>
</View>
{/* Bill To */}
<View style={styles.section}>
<View style={styles.row}>
<View>
<Text style={styles.label}>BILL TO:</Text>
<Text style={styles.value}>{data.user}</Text>
</View>
<View>
<Text style={styles.label}>STATUS:</Text>
<Text style={[styles.value, { color: statusColor }]}>
{data.status.toUpperCase()}
</Text>
</View>
</View>
</View>
<View style={styles.divider} />
{/* Items Table */}
<View style={styles.section}>
<View style={styles.tableHeader}>
<Text style={styles.col1}>DESCRIPTION</Text>
<Text style={styles.col2}>TENURE</Text>
<Text style={styles.col3}>AMOUNT</Text>
</View>
<View style={styles.tableRow}>
<Text style={styles.col1}>{data.service}</Text>
<Text style={styles.col2}>{data.tenure}</Text>
<Text style={styles.col3}>
{new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD'
}).format(parseFloat(data.amount))}
</Text>
</View>
</View>
<View style={styles.divider} />
{/* Total */}
<View style={styles.total}>
<View style={{width: '30%'}}>
<View style={styles.row}>
<Text style={styles.label}>SUBTOTAL:</Text>
<Text style={styles.value}>
{new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD'
}).format(parseFloat(data.amount))}
</Text>
</View>
<View style={styles.row}>
<Text style={styles.label}>TOTAL:</Text>
<Text style={styles.totalText}>
{new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD'
}).format(parseFloat(data.amount))}
</Text>
</View>
</View>
</View>
{/* Footer */}
<View style={styles.footer}>
<Text>Thank you for your business!</Text>
<Text>Please make payments payable to Your Company</Text>
</View>
</Page>
</Document>
);
};
export default InvoicePDF;

View File

@ -0,0 +1,7 @@
---
import Layout from "../../layouts/Layout.astro";
import AllSellingList from "../../components/Manager/AllSellingList"
---
<Layout title="All Selling List | SiliconPin" >
<AllSellingList client:load />
</Layout>

View File

@ -19,7 +19,7 @@ try {
const data = await response.json();
topic = data.data[0]; // Assuming single result
console.log('Single Topic:', topic);
// console.log('Single Topic:', topic);
} catch (error) {
console.error('Error fetching single topic:', error);
}
@ -28,7 +28,7 @@ export async function getStaticPaths() {
const TOPIC_API_URL = 'https://host-api.cs1.hz.siliconpin.com/v1/topics/';
try {
const response = await fetch(`${TOPIC_API_URL}?query=get-all-topics`, {
const response = await fetch(`${TOPIC_API_URL}?query=get-all-topics-for-slug`, {
method: 'GET',
credentials: 'include',
});

View File

@ -6,7 +6,7 @@ const TOPIC_API_URL = 'https://host-api.cs1.hz.siliconpin.com/v1/topics/';
let topics = [];
try {
const response = await fetch(`${TOPIC_API_URL}?query=get-all-topics`, {
const response = await fetch(`${TOPIC_API_URL}?query=get-all-topics-for-slug`, {
method: 'GET',
credentials: 'include',
});
@ -16,13 +16,13 @@ try {
}
const data = await response.json();
// console.log('Topic Data', data)
topics = data.data || [];
// console.log('Topic Data', data);
} catch (error) {
console.error('An error occurred', error);
}
---
<Layout title="Topics">
<TopicsList client:load topics={topics} />
<TopicsList client:load />
</Layout>

356
yarn.lock
View File

@ -213,7 +213,7 @@
dependencies:
"@babel/helper-plugin-utils" "^7.25.9"
"@babel/runtime@^7.14.6", "@babel/runtime@^7.17.2":
"@babel/runtime@^7.14.6", "@babel/runtime@^7.17.2", "@babel/runtime@^7.20.13":
version "7.27.0"
resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.0.tgz"
integrity sha512-VtPOkrdPHZsKc/clNqyi9WUA8TINkZ4cGk63UUE3u4pmB2k+ZMQRDuIOagv8UVd6j7k0T3+RRIb7beKTebNbcw==
@ -650,6 +650,144 @@
resolved "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.0.tgz"
integrity sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg==
"@react-pdf/fns@3.1.2":
version "3.1.2"
resolved "https://registry.npmjs.org/@react-pdf/fns/-/fns-3.1.2.tgz"
integrity sha512-qTKGUf0iAMGg2+OsUcp9ffKnKi41RukM/zYIWMDJ4hRVYSr89Q7e3wSDW/Koqx3ea3Uy/z3h2y3wPX6Bdfxk6g==
"@react-pdf/font@^4.0.2":
version "4.0.2"
resolved "https://registry.npmjs.org/@react-pdf/font/-/font-4.0.2.tgz"
integrity sha512-/dAWu7Y2RD1RxarDZ9SkYPHgBYOhmcDnet4W/qN/m8k+A2Hr3ja54GymSR7GGxWBtxjKtNauVKrTa9LS1n8WUw==
dependencies:
"@react-pdf/pdfkit" "^4.0.3"
"@react-pdf/types" "^2.9.0"
fontkit "^2.0.2"
is-url "^1.2.4"
"@react-pdf/image@^3.0.3":
version "3.0.3"
resolved "https://registry.npmjs.org/@react-pdf/image/-/image-3.0.3.tgz"
integrity sha512-lvP5ryzYM3wpbO9bvqLZYwEr5XBDX9jcaRICvtnoRqdJOo7PRrMnmB4MMScyb+Xw10mGeIubZAAomNAG5ONQZQ==
dependencies:
"@react-pdf/png-js" "^3.0.0"
jay-peg "^1.1.1"
"@react-pdf/layout@^4.4.0":
version "4.4.0"
resolved "https://registry.npmjs.org/@react-pdf/layout/-/layout-4.4.0.tgz"
integrity sha512-Aq+Cc6JYausWLoks2FvHe3PwK9cTuvksB2uJ0AnkKJEUtQbvCq8eCRb1bjbbwIji9OzFRTTzZij7LzkpKHjIeA==
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"
"@react-pdf/pdfkit@^4.0.3":
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==
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"
"@react-pdf/png-js@^3.0.0":
version "3.0.0"
resolved "https://registry.npmjs.org/@react-pdf/png-js/-/png-js-3.0.0.tgz"
integrity sha512-eSJnEItZ37WPt6Qv5pncQDxLJRK15eaRwPT+gZoujP548CodenOVp49GST8XJvKMFt9YqIBzGBV/j9AgrOQzVA==
dependencies:
browserify-zlib "^0.2.0"
"@react-pdf/primitives@^4.1.1":
version "4.1.1"
resolved "https://registry.npmjs.org/@react-pdf/primitives/-/primitives-4.1.1.tgz"
integrity sha512-IuhxYls1luJb7NUWy6q5avb1XrNaVj9bTNI40U9qGRuS6n7Hje/8H8Qi99Z9UKFV74bBP3DOf3L1wV2qZVgVrQ==
"@react-pdf/reconciler@^1.1.4":
version "1.1.4"
resolved "https://registry.npmjs.org/@react-pdf/reconciler/-/reconciler-1.1.4.tgz"
integrity sha512-oTQDiR/t4Z/Guxac88IavpU2UgN7eR0RMI9DRKvKnvPz2DUasGjXfChAdMqDNmJJxxV26mMy9xQOUV2UU5/okg==
dependencies:
object-assign "^4.1.1"
scheduler "0.25.0-rc-603e6108-20241029"
"@react-pdf/render@^4.3.0":
version "4.3.0"
resolved "https://registry.npmjs.org/@react-pdf/render/-/render-4.3.0.tgz"
integrity sha512-MdWfWaqO6d7SZD75TZ2z5L35V+cHpyA43YNRlJNG0RJ7/MeVGDQv12y/BXOJgonZKkeEGdzM3EpAt9/g4E22WA==
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"
"@react-pdf/renderer@^4.3.0":
version "4.3.0"
resolved "https://registry.npmjs.org/@react-pdf/renderer/-/renderer-4.3.0.tgz"
integrity sha512-28gpA69fU9ZQrDzmd5xMJa1bDf8t0PT3ApUKBl2PUpoE/x4JlvCB5X66nMXrfFrgF2EZrA72zWQAkvbg7TE8zw==
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"
"@react-pdf/stylesheet@^6.1.0":
version "6.1.0"
resolved "https://registry.npmjs.org/@react-pdf/stylesheet/-/stylesheet-6.1.0.tgz"
integrity sha512-BGZ2sYNUp38VJUegjva/jsri3iiRGnVNjWI+G9dTwAvLNOmwFvSJzqaCsEnqQ/DW5mrTBk/577FhDY7pv6AidA==
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"
"@react-pdf/textkit@^6.0.0":
version "6.0.0"
resolved "https://registry.npmjs.org/@react-pdf/textkit/-/textkit-6.0.0.tgz"
integrity sha512-fDt19KWaJRK/n2AaFoVm31hgGmpygmTV7LsHGJNGZkgzXcFyLsx+XUl63DTDPH3iqxj3xUX128t104GtOz8tTw==
dependencies:
"@react-pdf/fns" "3.1.2"
bidi-js "^1.0.2"
hyphen "^1.6.4"
unicode-properties "^1.4.1"
"@react-pdf/types@^2.9.0":
version "2.9.0"
resolved "https://registry.npmjs.org/@react-pdf/types/-/types-2.9.0.tgz"
integrity sha512-ckj80vZLlvl9oYrQ4tovEaqKWP3O06Eb1D48/jQWbdwz1Yh7Y9v1cEmwlP8ET+a1Whp8xfdM0xduMexkuPANCQ==
dependencies:
"@react-pdf/font" "^4.0.2"
"@react-pdf/primitives" "^4.1.1"
"@react-pdf/stylesheet" "^6.1.0"
"@rollup/pluginutils@^5.1.4":
version "5.1.4"
resolved "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.4.tgz"
@ -739,6 +877,13 @@
resolved "https://registry.npmjs.org/@shikijs/vscode-textmate/-/vscode-textmate-10.0.2.tgz"
integrity sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==
"@swc/helpers@^0.5.12":
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==
dependencies:
tslib "^2.8.0"
"@types/babel__core@^7.20.5":
version "7.20.5"
resolved "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz"
@ -951,6 +1096,11 @@
resolved "https://registry.npmjs.org/@zxing/text-encoding/-/text-encoding-0.9.0.tgz"
integrity sha512-U/4aVJ2mxI0aDNI8Uq0wEhMgY+u4CNtEb0om3+y3+niDAsoTCOB33UF0sxpzqzdqXLqmvc+vZyAt4O8pPdfkwA==
abs-svg-path@^0.1.1:
version "0.1.1"
resolved "https://registry.npmjs.org/abs-svg-path/-/abs-svg-path-0.1.1.tgz"
integrity sha512-d8XPSGjfyzlXC3Xx891DJRyZfqk5JU0BJrDQcsWomFIV1/BIzPW5HDH5iDdWpqWaav0YVIEzT1RHTwWr0FFshA==
acorn@^8.14.1:
version "8.14.1"
resolved "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz"
@ -1135,16 +1285,28 @@ base-64@^1.0.0:
resolved "https://registry.npmjs.org/base-64/-/base-64-1.0.0.tgz"
integrity sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg==
base64-js@^1.3.1:
base64-js@^1.1.2, base64-js@^1.3.0, base64-js@^1.3.1:
version "1.5.1"
resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz"
integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
base64-js@0.0.8:
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==
bcp-47-match@^2.0.0:
version "2.0.3"
resolved "https://registry.npmjs.org/bcp-47-match/-/bcp-47-match-2.0.3.tgz"
integrity sha512-JtTezzbAibu8G0R9op9zb3vcWZd9JF6M0xOYGPn0fNCd7wOpRB1mU2mH9T8gaBGbAAyIIVgB2G7xG0GP98zMAQ==
bidi-js@^1.0.2:
version "1.0.3"
resolved "https://registry.npmjs.org/bidi-js/-/bidi-js-1.0.3.tgz"
integrity sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==
dependencies:
require-from-string "^2.0.2"
binary-extensions@^2.0.0:
version "2.3.0"
resolved "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz"
@ -1199,11 +1361,25 @@ braces@^3.0.3, braces@~3.0.2:
dependencies:
fill-range "^7.1.1"
brotli@^1.3.2:
version "1.3.3"
resolved "https://registry.npmjs.org/brotli/-/brotli-1.3.3.tgz"
integrity sha512-oTKjJdShmDuGW94SyyaoQvAjf30dZaHnjJ8uAF+u2/vGJkJbJPJAT1gDiOJP5v1Zb6f9KEyW/1HpuaWIXtGHPg==
dependencies:
base64-js "^1.1.2"
browser-or-node@^2.1.1:
version "2.1.1"
resolved "https://registry.npmjs.org/browser-or-node/-/browser-or-node-2.1.1.tgz"
integrity sha512-8CVjaLJGuSKMVTxJ2DpBl5XnlNDiT4cQFeuCJJrvJmts9YrTZDizTX7PjC2s6W4x+MBGZeEY6dGMrF04/6Hgqg==
browserify-zlib@^0.2.0:
version "0.2.0"
resolved "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz"
integrity sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==
dependencies:
pako "~1.0.5"
browserslist@^4.24.0, browserslist@^4.24.4, "browserslist@>= 4.21.0":
version "4.24.4"
resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.24.4.tgz"
@ -1359,6 +1535,11 @@ clone@^1.0.2:
resolved "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz"
integrity sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==
clone@^2.1.2:
version "2.1.2"
resolved "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz"
integrity sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==
clsx@^2.1.1:
version "2.1.1"
resolved "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz"
@ -1388,7 +1569,7 @@ color-name@^1.0.0, color-name@~1.1.4:
resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz"
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
color-string@^1.9.0:
color-string@^1.9.0, color-string@^1.9.1:
version "1.9.1"
resolved "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz"
integrity sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==
@ -1460,6 +1641,11 @@ crossws@^0.3.3:
dependencies:
uncrypto "^0.1.3"
crypto-js@^4.2.0:
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==
css-selector-parser@^1.0.0:
version "1.4.1"
resolved "https://registry.npmjs.org/css-selector-parser/-/css-selector-parser-1.4.1.tgz"
@ -1569,6 +1755,11 @@ devlop@^1.0.0, devlop@^1.1.0:
dependencies:
dequal "^2.0.0"
dfa@^1.2.0:
version "1.2.0"
resolved "https://registry.npmjs.org/dfa/-/dfa-1.2.0.tgz"
integrity sha512-ED3jP8saaweFTjeGX8HQPjeC1YYyZs98jGNZx6IiBvxW7JG5v492kamAQB3m2wop07CvU/RQmzcKr6bgcC5D/Q==
didyoumean@^1.2.2:
version "1.2.2"
resolved "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz"
@ -1734,6 +1925,11 @@ eventemitter3@^5.0.1:
resolved "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz"
integrity sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==
events@^3.3.0:
version "3.3.0"
resolved "https://registry.npmjs.org/events/-/events-3.3.0.tgz"
integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==
execa@^7.0.0:
version "7.2.0"
resolved "https://registry.npmjs.org/execa/-/execa-7.2.0.tgz"
@ -1754,6 +1950,11 @@ extend@^3.0.0:
resolved "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz"
integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
fast-deep-equal@^3.1.3:
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==
fast-glob@^3.3.2:
version "3.3.3"
resolved "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz"
@ -1809,6 +2010,21 @@ flattie@^1.1.1:
resolved "https://registry.npmjs.org/flattie/-/flattie-1.1.1.tgz"
integrity sha512-9UbaD6XdAL97+k/n+N7JwX46K/M6Zc6KcFYskrYL8wbBV/Uyk0CTAMY0VT+qiK5PM7AIc9aTWYtq65U7T+aCNQ==
fontkit@^2.0.2:
version "2.0.4"
resolved "https://registry.npmjs.org/fontkit/-/fontkit-2.0.4.tgz"
integrity sha512-syetQadaUEDNdxdugga9CpEYVaQIxOwk7GlwZWWZ19//qW4zE5bknOKeMBDYAASwnpaSHKJITRLMF9m1fp3s6g==
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"
for-each@^0.3.5:
version "0.3.5"
resolved "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz"
@ -2312,6 +2528,18 @@ hastscript@^9.0.0:
property-information "^7.0.0"
space-separated-tokens "^2.0.0"
hsl-to-hex@^1.0.0:
version "1.0.0"
resolved "https://registry.npmjs.org/hsl-to-hex/-/hsl-to-hex-1.0.0.tgz"
integrity sha512-K6GVpucS5wFf44X0h2bLVRDsycgJmf9FF2elg+CrqD8GcFU8c6vYhgXn8NjUkFCwj+xDFb70qgLbTUm6sxwPmA==
dependencies:
hsl-to-rgb-for-reals "^1.1.0"
hsl-to-rgb-for-reals@^1.1.0:
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==
html-escaper@3.0.3:
version "3.0.3"
resolved "https://registry.npmjs.org/html-escaper/-/html-escaper-3.0.3.tgz"
@ -2342,6 +2570,11 @@ human-signals@^4.3.0:
resolved "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz"
integrity sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==
hyphen@^1.6.4:
version "1.10.6"
resolved "https://registry.npmjs.org/hyphen/-/hyphen-1.10.6.tgz"
integrity sha512-fXHXcGFTXOvZTSkPJuGOQf5Lv5T/R2itiiCVPg9LxAje5D00O0pP83yJShFq5V89Ly//Gt6acj7z8pbBr34stw==
ieee754@^1.2.1:
version "1.2.1"
resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz"
@ -2352,7 +2585,7 @@ import-meta-resolve@^4.1.0:
resolved "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz"
integrity sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw==
inherits@^2.0.3, inherits@^2.0.4:
inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3:
version "2.0.4"
resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz"
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
@ -2518,6 +2751,11 @@ is-unicode-supported@^1.1.0:
resolved "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz"
integrity sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==
is-url@^1.2.4:
version "1.2.4"
resolved "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz"
integrity sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==
is-wsl@^3.1.0:
version "3.1.0"
resolved "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz"
@ -2539,6 +2777,13 @@ jackspeak@^3.1.2:
optionalDependencies:
"@pkgjs/parseargs" "^0.11.0"
jay-peg@^1.1.1:
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==
dependencies:
restructure "^3.0.0"
jiti@^1.21.6, jiti@>=1.21.0:
version "1.21.7"
resolved "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz"
@ -2590,6 +2835,14 @@ lilconfig@^3.0.0, lilconfig@^3.1.3:
resolved "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz"
integrity sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==
linebreak@^1.1.0:
version "1.1.0"
resolved "https://registry.npmjs.org/linebreak/-/linebreak-1.1.0.tgz"
integrity sha512-MHp03UImeVhB7XZtjd0E4n6+3xr5Dq/9xI/5FptGk5FrbDR3zagPa2DS6U8ks/3HjbKWG9Q1M2ufOzxV2qLYSQ==
dependencies:
base64-js "0.0.8"
unicode-trie "^2.0.0"
lines-and-columns@^1.1.6:
version "1.2.4"
resolved "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz"
@ -3005,6 +3258,11 @@ mdast-util-to-string@^4.0.0:
dependencies:
"@types/mdast" "^4.0.0"
media-engine@^1.0.3:
version "1.0.3"
resolved "https://registry.npmjs.org/media-engine/-/media-engine-1.0.3.tgz"
integrity sha512-aa5tG6sDoK+k70B9iEX1NeyfT8ObCKhNDs6lJVpwF6r8vhUfuKMslIcirq6HIUYuuUYLefcEQOn9bSBOvawtwg==
merge-stream@^2.0.0:
version "2.0.0"
resolved "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz"
@ -3712,6 +3970,13 @@ normalize-range@^0.1.2:
resolved "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz"
integrity sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==
normalize-svg-path@^1.1.0:
version "1.1.0"
resolved "https://registry.npmjs.org/normalize-svg-path/-/normalize-svg-path-1.1.0.tgz"
integrity sha512-r9KHKG2UUeB5LoTouwDzBy2VxXlHsiM6fyLQvnJa0S5hrhzqElH/CH7TUGhT1fVvIYBIKf3OpY4YJ4CK+iaqHg==
dependencies:
svg-arc-to-cubic-bezier "^3.0.0"
not@^0.1.0:
version "0.1.0"
resolved "https://registry.npmjs.org/not/-/not-0.1.0.tgz"
@ -3818,6 +4083,16 @@ package-manager-detector@^1.0.0:
resolved "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-1.1.0.tgz"
integrity sha512-Y8f9qUlBzW8qauJjd/eu6jlpJZsuPJm2ZAV0cDVd420o4EdpH5RPdoCv+60/TdJflGatr4sDfpAL6ArWZbM5tA==
pako@^0.2.5:
version "0.2.9"
resolved "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz"
integrity sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==
pako@~1.0.5:
version "1.0.11"
resolved "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz"
integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==
parse-entities@^4.0.0:
version "4.0.2"
resolved "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.2.tgz"
@ -3848,6 +4123,11 @@ parse-numeric-range@^1.3.0:
resolved "https://registry.npmjs.org/parse-numeric-range/-/parse-numeric-range-1.3.0.tgz"
integrity sha512-twN+njEipszzlMJd4ONUYgSfZPDxgHhT9Ahed5uTigpQn90FggW4SA/AIPq/6a149fTbE9qBEcSwE3FAEp6wQQ==
parse-svg-path@^0.1.2:
version "0.1.2"
resolved "https://registry.npmjs.org/parse-svg-path/-/parse-svg-path-0.1.2.tgz"
integrity sha512-JyPSBnkTJ0AI8GGJLfMXvKq42cj5c006fnLz6fXy6zfoVjJizi8BNTpu8on8ziI1cKy9d9DGNuY17Ce7wuejpQ==
parse5@^6.0.0:
version "6.0.1"
resolved "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz"
@ -3967,7 +4247,7 @@ postcss-selector-parser@^6.1.1, postcss-selector-parser@^6.1.2:
cssesc "^3.0.0"
util-deprecate "^1.0.2"
postcss-value-parser@^4.0.0, postcss-value-parser@^4.2.0:
postcss-value-parser@^4.0.0, postcss-value-parser@^4.1.0, postcss-value-parser@^4.2.0:
version "4.2.0"
resolved "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz"
integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==
@ -3994,7 +4274,7 @@ prompts@^2.4.2:
kleur "^3.0.3"
sisteransi "^1.0.5"
prop-types@^15.0.0, prop-types@^15.8.1:
prop-types@^15.0.0, prop-types@^15.6.2, prop-types@^15.8.1:
version "15.8.1"
resolved "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz"
integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
@ -4033,6 +4313,13 @@ queue-microtask@^1.2.2:
resolved "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz"
integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==
queue@^6.0.1:
version "6.0.2"
resolved "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz"
integrity sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==
dependencies:
inherits "~2.0.3"
radix3@^1.1.2:
version "1.1.2"
resolved "https://registry.npmjs.org/radix3/-/radix3-1.1.2.tgz"
@ -4463,6 +4750,11 @@ remark-stringify@^11.0.0:
mdast-util-to-markdown "^2.0.0"
unified "^11.0.0"
require-from-string@^2.0.2:
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==
resolve@^1.1.7, resolve@^1.22.8:
version "1.22.10"
resolved "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz"
@ -4480,6 +4772,11 @@ restore-cursor@^4.0.0:
onetime "^5.1.0"
signal-exit "^3.0.2"
restructure@^3.0.0:
version "3.0.2"
resolved "https://registry.npmjs.org/restructure/-/restructure-3.0.2.tgz"
integrity sha512-gSfoiOEA0VPE6Tukkrr7I0RBdE0s7H1eFCDBk05l1KIQT1UIKNc5JZy6jdyW6eYH3aR3g5b3PuL77rq0hvwtAw==
retext-latin@^4.0.0:
version "4.0.0"
resolved "https://registry.npmjs.org/retext-latin/-/retext-latin-4.0.0.tgz"
@ -4588,6 +4885,11 @@ scheduler@^0.25.0:
resolved "https://registry.npmjs.org/scheduler/-/scheduler-0.25.0.tgz"
integrity sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==
scheduler@0.25.0-rc-603e6108-20241029:
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==
semver@^6.3.1:
version "6.3.1"
resolved "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz"
@ -4871,6 +5173,11 @@ supports-preserve-symlinks-flag@^1.0.0:
resolved "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz"
integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
svg-arc-to-cubic-bezier@^3.0.0, svg-arc-to-cubic-bezier@^3.2.0:
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==
tailwind-merge@^3.0.2:
version "3.0.2"
resolved "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.0.2.tgz"
@ -4930,6 +5237,11 @@ through2@^4.0.2:
dependencies:
readable-stream "3"
tiny-inflate@^1.0.0, tiny-inflate@^1.0.3:
version "1.0.3"
resolved "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz"
integrity sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==
tinyexec@^0.3.2:
version "0.3.2"
resolved "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz"
@ -4970,7 +5282,7 @@ tsconfck@^3.1.5:
resolved "https://registry.npmjs.org/tsconfck/-/tsconfck-3.1.5.tgz"
integrity sha512-CLDfGgUp7XPswWnezWwsCRxNmgQjhYq3VXHM0/XIRxhVrKw0M1if9agzryh1QS3nxjCROvV+xWxoJO1YctzzWg==
tslib@^2.0.0, tslib@^2.1.0:
tslib@^2.0.0, tslib@^2.1.0, tslib@^2.8.0:
version "2.8.1"
resolved "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz"
integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==
@ -5010,6 +5322,22 @@ uncrypto@^0.1.3:
resolved "https://registry.npmjs.org/uncrypto/-/uncrypto-0.1.3.tgz"
integrity sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==
unicode-properties@^1.4.0, unicode-properties@^1.4.1:
version "1.4.1"
resolved "https://registry.npmjs.org/unicode-properties/-/unicode-properties-1.4.1.tgz"
integrity sha512-CLjCCLQ6UuMxWnbIylkisbRj31qxHPAurvena/0iwSVbQ2G1VY5/HjV0IRabOEbDHlzZlRdCrD4NhB0JtU40Pg==
dependencies:
base64-js "^1.3.0"
unicode-trie "^2.0.0"
unicode-trie@^2.0.0:
version "2.0.0"
resolved "https://registry.npmjs.org/unicode-trie/-/unicode-trie-2.0.0.tgz"
integrity sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==
dependencies:
pako "^0.2.5"
tiny-inflate "^1.0.0"
unified@^10.0.0, unified@~10.1.1:
version "10.1.2"
resolved "https://registry.npmjs.org/unified/-/unified-10.1.2.tgz"
@ -5296,6 +5624,15 @@ vfile@^6.0.0, vfile@^6.0.3:
"@types/unist" "^3.0.0"
vfile-message "^4.0.0"
vite-compatible-readable-stream@^3.6.1:
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==
dependencies:
inherits "^2.0.3"
string_decoder "^1.1.1"
util-deprecate "^1.0.1"
"vite@^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0", "vite@^4.2.0 || ^5.0.0 || ^6.0.0", vite@^6.2.0, vite@^6.2.1:
version "6.2.2"
resolved "https://registry.npmjs.org/vite/-/vite-6.2.2.tgz"
@ -5447,6 +5784,11 @@ yoctocolors@^2.1.1:
resolved "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.1.1.tgz"
integrity sha512-GQHQqAopRhwU8Kt1DDM8NjibDXHC8eoh1erhGAJPEyveY9qqVeXvVikNKrDz69sHowPMorbPUrH/mx8c50eiBQ==
yoga-layout@^3.2.1:
version "3.2.1"
resolved "https://registry.npmjs.org/yoga-layout/-/yoga-layout-3.2.1.tgz"
integrity sha512-0LPOt3AxKqMdFBZA3HBAt/t/8vIKq7VaQYbuA8WxCgung+p9TVyKRYdpvCb80HcdTN2NkbIKbhNwKUfm3tQywQ==
zod-to-json-schema@^3.24.3:
version "3.24.4"
resolved "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.24.4.tgz"