Finish Project
This commit is contained in:
6
.idea/compiler.xml
generated
Normal file
6
.idea/compiler.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="TypeScriptCompiler">
|
||||
<option name="useServicePoweredTypesWasEnabledByExperiment" value="true" />
|
||||
</component>
|
||||
</project>
|
||||
12
.idea/dataSources.xml
generated
Normal file
12
.idea/dataSources.xml
generated
Normal file
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
|
||||
<data-source source="LOCAL" name="ticket_sys@localhost" uuid="3d7ee8f1-4863-4cbc-8c64-6945c4151623">
|
||||
<driver-ref>mysql.8</driver-ref>
|
||||
<synchronize>true</synchronize>
|
||||
<jdbc-driver>com.mysql.cj.jdbc.Driver</jdbc-driver>
|
||||
<jdbc-url>jdbc:mysql://localhost:3306/ticket_sys</jdbc-url>
|
||||
<working-dir>$ProjectFileDir$</working-dir>
|
||||
</data-source>
|
||||
</component>
|
||||
</project>
|
||||
6
.idea/data_source_mapping.xml
generated
Normal file
6
.idea/data_source_mapping.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="DataSourcePerFileMappings">
|
||||
<file url="file://$APPLICATION_CONFIG_DIR$/consoles/db/3d7ee8f1-4863-4cbc-8c64-6945c4151623/console.sql" value="3d7ee8f1-4863-4cbc-8c64-6945c4151623" />
|
||||
</component>
|
||||
</project>
|
||||
5
.idea/runConfigurations/Next_js__debug_client_side.xml
generated
Normal file
5
.idea/runConfigurations/Next_js__debug_client_side.xml
generated
Normal file
@@ -0,0 +1,5 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Next.js: debug client-side" type="JavascriptDebugType" uri="http://localhost:3000/" useFirstLineBreakpoints="true">
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
||||
6
.idea/sqldialects.xml
generated
Normal file
6
.idea/sqldialects.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="SqlDialectMappings">
|
||||
<file url="PROJECT" dialect="MySQL" />
|
||||
</component>
|
||||
</project>
|
||||
509
package-lock.json
generated
509
package-lock.json
generated
@@ -8,6 +8,7 @@
|
||||
"name": "frontend-next",
|
||||
"version": "0.1.0",
|
||||
"dependencies": {
|
||||
"@storefront-ui/react": "^4.0.0",
|
||||
"bcrypt": "^6.0.0",
|
||||
"clsx": "^2.1.1",
|
||||
"next": "^16.1.4",
|
||||
@@ -42,9 +43,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/code-frame": {
|
||||
"version": "7.28.6",
|
||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.28.6.tgz",
|
||||
"integrity": "sha512-JYgintcMjRiCvS8mMECzaEn+m3PfoQiyqukOMCCVQtoJGYJw8j/8LBJEiqkHLkfwCcs74E3pbAUFNg7d9VNJ+Q==",
|
||||
"version": "7.29.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz",
|
||||
"integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -98,14 +99,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/generator": {
|
||||
"version": "7.28.6",
|
||||
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.6.tgz",
|
||||
"integrity": "sha512-lOoVRwADj8hjf7al89tvQ2a1lf53Z+7tiXMgpZJL3maQPDxh0DgLMN62B2MKUOFcoodBHLMbDM6WAbKgNy5Suw==",
|
||||
"version": "7.29.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.0.tgz",
|
||||
"integrity": "sha512-vSH118/wwM/pLR38g/Sgk05sNtro6TlTJKuiMXDaZqPUfjTFcudpCOt00IhOfj+1BFAX+UFAlzCU+6WXr3GLFQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/parser": "^7.28.6",
|
||||
"@babel/types": "^7.28.6",
|
||||
"@babel/parser": "^7.29.0",
|
||||
"@babel/types": "^7.29.0",
|
||||
"@jridgewell/gen-mapping": "^0.3.12",
|
||||
"@jridgewell/trace-mapping": "^0.3.28",
|
||||
"jsesc": "^3.0.2"
|
||||
@@ -218,13 +219,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/parser": {
|
||||
"version": "7.28.6",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.6.tgz",
|
||||
"integrity": "sha512-TeR9zWR18BvbfPmGbLampPMW+uW1NZnJlRuuHso8i87QZNq2JRF9i6RgxRqtEq+wQGsS19NNTWr2duhnE49mfQ==",
|
||||
"version": "7.29.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz",
|
||||
"integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/types": "^7.28.6"
|
||||
"@babel/types": "^7.29.0"
|
||||
},
|
||||
"bin": {
|
||||
"parser": "bin/babel-parser.js"
|
||||
@@ -233,6 +234,15 @@
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/runtime": {
|
||||
"version": "7.28.6",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.6.tgz",
|
||||
"integrity": "sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/template": {
|
||||
"version": "7.28.6",
|
||||
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz",
|
||||
@@ -268,9 +278,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/types": {
|
||||
"version": "7.28.6",
|
||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.6.tgz",
|
||||
"integrity": "sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg==",
|
||||
"version": "7.29.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz",
|
||||
"integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==",
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -458,6 +468,31 @@
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@floating-ui/core": {
|
||||
"version": "1.7.4",
|
||||
"resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.4.tgz",
|
||||
"integrity": "sha512-C3HlIdsBxszvm5McXlB8PeOEWfBhcGBTZGkGlWc2U0KFY5IwG5OQEuQ8rq52DZmcHDlPLd+YFBK+cZcytwIFWg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@floating-ui/utils": "^0.2.10"
|
||||
}
|
||||
},
|
||||
"node_modules/@floating-ui/dom": {
|
||||
"version": "1.7.5",
|
||||
"resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.5.tgz",
|
||||
"integrity": "sha512-N0bD2kIPInNHUHehXhMke1rBGs1dwqvC9O9KYMyyjK7iXt7GAhnro7UlcuYcGdS/yYOlq0MAVgrow8IbWJwyqg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@floating-ui/core": "^1.7.4",
|
||||
"@floating-ui/utils": "^0.2.10"
|
||||
}
|
||||
},
|
||||
"node_modules/@floating-ui/utils": {
|
||||
"version": "0.2.10",
|
||||
"resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.10.tgz",
|
||||
"integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@humanfs/core": {
|
||||
"version": "0.19.1",
|
||||
"resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz",
|
||||
@@ -1012,7 +1047,6 @@
|
||||
"version": "1.5.5",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
|
||||
"integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@jridgewell/trace-mapping": {
|
||||
@@ -1238,6 +1272,131 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@storefront-ui/react": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@storefront-ui/react/-/react-4.0.0.tgz",
|
||||
"integrity": "sha512-yj3dKvxGJH4IkT+oh0+Q1WIcOBVhFuYMHFz6eLjJo/+hMRJVROkSe/lmaKo35iXQ4p8/DuIIkC2ZhM4VCLbF1w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@floating-ui/react-dom": "^2.0.9",
|
||||
"@storefront-ui/shared": "3.1.0",
|
||||
"@storefront-ui/tailwind-config": "3.1.0",
|
||||
"classnames": "^2.5.1",
|
||||
"jw-paginate": "^1.0.4",
|
||||
"react-polymorphed": "^2.1.0",
|
||||
"react-transition-group": "^4.4.5",
|
||||
"react-use": "^17.5.1",
|
||||
"tabbable": "^6.1.1",
|
||||
"tailwind-merge": "^3.3.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^19.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@storefront-ui/react/node_modules/@floating-ui/react-dom": {
|
||||
"version": "2.1.7",
|
||||
"resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.7.tgz",
|
||||
"integrity": "sha512-0tLRojf/1Go2JgEVm+3Frg9A3IW8bJgKgdO0BN5RkF//ufuz2joZM63Npau2ff3J6lUVYgDSNzNkR+aH3IVfjg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@floating-ui/dom": "^1.7.5"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.8.0",
|
||||
"react-dom": ">=16.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@storefront-ui/react/node_modules/react-transition-group": {
|
||||
"version": "4.4.5",
|
||||
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz",
|
||||
"integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==",
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.5.5",
|
||||
"dom-helpers": "^5.0.1",
|
||||
"loose-envify": "^1.4.0",
|
||||
"prop-types": "^15.6.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.6.0",
|
||||
"react-dom": ">=16.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@storefront-ui/react/node_modules/react-use": {
|
||||
"version": "17.6.0",
|
||||
"resolved": "https://registry.npmjs.org/react-use/-/react-use-17.6.0.tgz",
|
||||
"integrity": "sha512-OmedEScUMKFfzn1Ir8dBxiLLSOzhKe/dPZwVxcujweSj45aNM7BEGPb9BEVIgVEqEXx6f3/TsXzwIktNgUR02g==",
|
||||
"license": "Unlicense",
|
||||
"dependencies": {
|
||||
"@types/js-cookie": "^2.2.6",
|
||||
"@xobotyi/scrollbar-width": "^1.9.5",
|
||||
"copy-to-clipboard": "^3.3.1",
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"fast-shallow-equal": "^1.0.0",
|
||||
"js-cookie": "^2.2.1",
|
||||
"nano-css": "^5.6.2",
|
||||
"react-universal-interface": "^0.6.2",
|
||||
"resize-observer-polyfill": "^1.5.1",
|
||||
"screenfull": "^5.1.0",
|
||||
"set-harmonic-interval": "^1.0.1",
|
||||
"throttle-debounce": "^3.0.1",
|
||||
"ts-easing": "^0.2.0",
|
||||
"tslib": "^2.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "*",
|
||||
"react-dom": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@storefront-ui/react/node_modules/react-use/node_modules/nano-css": {
|
||||
"version": "5.6.2",
|
||||
"resolved": "https://registry.npmjs.org/nano-css/-/nano-css-5.6.2.tgz",
|
||||
"integrity": "sha512-+6bHaC8dSDGALM1HJjOHVXpuastdu2xFoZlC77Jh4cg+33Zcgm+Gxd+1xsnpZK14eyHObSp82+ll5y3SX75liw==",
|
||||
"license": "Unlicense",
|
||||
"dependencies": {
|
||||
"@jridgewell/sourcemap-codec": "^1.4.15",
|
||||
"css-tree": "^1.1.2",
|
||||
"csstype": "^3.1.2",
|
||||
"fastest-stable-stringify": "^2.0.2",
|
||||
"inline-style-prefixer": "^7.0.1",
|
||||
"rtl-css-js": "^1.16.1",
|
||||
"stacktrace-js": "^2.0.2",
|
||||
"stylis": "^4.3.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "*",
|
||||
"react-dom": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@storefront-ui/shared": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@storefront-ui/shared/-/shared-3.1.0.tgz",
|
||||
"integrity": "sha512-TqYPguDt8EBit1ukAM35jxVnwNvmIYrsOddYk0qN3Ij9MNEgXNGYYXczJCU3Ct2UHbzY9VTfR/JKA06uBYJrmw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@storefront-ui/tailwind-config": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@storefront-ui/tailwind-config/-/tailwind-config-3.1.0.tgz",
|
||||
"integrity": "sha512-f2qeb7ii2gWfjlkBLhQ7H2jpntu3G7aoxixlTcIfL0b38cNZPPxCsk5y40bptQ42gkJh10/Ne0eoM5YpLDNM8Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@storefront-ui/tw-plugin-peer-next": "3.1.0",
|
||||
"@tailwindcss/container-queries": "^0.1.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tailwindcss/typography": ">=0.5.19",
|
||||
"tailwindcss": ">= 4.0.0-alpha.20 || >= 4.0.0-beta.1 || >= 4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@storefront-ui/tw-plugin-peer-next": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@storefront-ui/tw-plugin-peer-next/-/tw-plugin-peer-next-3.1.0.tgz",
|
||||
"integrity": "sha512-690GvYL97S9YSI6dqtNKfEo/n6dJJXT5iq196yJWT0FmDi9I3uGdcN5+F419V4jRmePsYDhptlZCaZ6HQjwlNQ==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"tailwindcss": ">= 4.0.0-alpha.20 || >= 4.0.0-beta.1 || >= 4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/helpers": {
|
||||
"version": "0.5.15",
|
||||
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz",
|
||||
@@ -1247,6 +1406,15 @@
|
||||
"tslib": "^2.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tailwindcss/container-queries": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@tailwindcss/container-queries/-/container-queries-0.1.1.tgz",
|
||||
"integrity": "sha512-p18dswChx6WnTSaJCSGx6lTmrGzNNvm2FtXmiO6AuA1V4U5REyoqwmT6kgAsIMdjo07QdAfYXHJ4hnMtfHzWgA==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"tailwindcss": ">=3.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tailwindcss/node": {
|
||||
"version": "4.1.18",
|
||||
"resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.18.tgz",
|
||||
@@ -1518,6 +1686,19 @@
|
||||
"tailwindcss": "4.1.18"
|
||||
}
|
||||
},
|
||||
"node_modules/@tailwindcss/typography": {
|
||||
"version": "0.5.19",
|
||||
"resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.19.tgz",
|
||||
"integrity": "sha512-w31dd8HOx3k9vPtcQh5QHP9GwKcgbMp87j58qi6xgiBnFFtKEAgCWnDw4qUT8aHwkCp8bKvb/KGKWWHedP0AAg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"postcss-selector-parser": "6.0.10"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"tailwindcss": ">=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@tybys/wasm-util": {
|
||||
"version": "0.10.1",
|
||||
"resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz",
|
||||
@@ -1546,6 +1727,12 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/js-cookie": {
|
||||
"version": "2.2.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/js-cookie/-/js-cookie-2.2.7.tgz",
|
||||
"integrity": "sha512-aLkWa0C0vO5b4Sr798E26QgOkss68Un0bLjs7u9qxzPT5CG+8DuNTffWES58YzJs3hrVAOs1wonycqEBqNJubA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/json-schema": {
|
||||
"version": "7.0.15",
|
||||
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
|
||||
@@ -1574,7 +1761,6 @@
|
||||
"version": "19.2.10",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.10.tgz",
|
||||
"integrity": "sha512-WPigyYuGhgZ/cTPRXB2EwUw+XvsRA3GqHlsP4qteqrnnjDrApbS7MxcGr/hke5iUoeB7E/gQtrs9I37zAJ0Vjw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"csstype": "^3.2.2"
|
||||
@@ -2128,6 +2314,12 @@
|
||||
"win32"
|
||||
]
|
||||
},
|
||||
"node_modules/@xobotyi/scrollbar-width": {
|
||||
"version": "1.9.5",
|
||||
"resolved": "https://registry.npmjs.org/@xobotyi/scrollbar-width/-/scrollbar-width-1.9.5.tgz",
|
||||
"integrity": "sha512-N8tkAACJx2ww8vFMneJmaAgmjAG1tnVBZJRLRcx061tmsLRZHSEZSLuGWnwPtunsSLvSqXQ2wfp7Mgqg1I+2dQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/acorn": {
|
||||
"version": "8.15.0",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
|
||||
@@ -2609,6 +2801,12 @@
|
||||
"url": "https://github.com/chalk/chalk?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/classnames": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz",
|
||||
"integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/client-only": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz",
|
||||
@@ -2658,6 +2856,15 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/copy-to-clipboard": {
|
||||
"version": "3.3.3",
|
||||
"resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz",
|
||||
"integrity": "sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"toggle-selection": "^1.0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/cross-spawn": {
|
||||
"version": "7.0.6",
|
||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
|
||||
@@ -2673,11 +2880,45 @@
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/css-in-js-utils": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/css-in-js-utils/-/css-in-js-utils-3.1.0.tgz",
|
||||
"integrity": "sha512-fJAcud6B3rRu+KHYk+Bwf+WFL2MDCJJ1XG9x137tJQ0xYxor7XziQtuGFbWNdqrvF4Tk26O3H73nfVqXt/fW1A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"hyphenate-style-name": "^1.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/css-tree": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz",
|
||||
"integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"mdn-data": "2.0.14",
|
||||
"source-map": "^0.6.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/cssesc": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
|
||||
"integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"cssesc": "bin/cssesc"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/csstype": {
|
||||
"version": "3.2.3",
|
||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
|
||||
"integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/damerau-levenshtein": {
|
||||
@@ -2825,6 +3066,16 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/dom-helpers": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz",
|
||||
"integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.8.7",
|
||||
"csstype": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/dunder-proto": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
|
||||
@@ -2868,6 +3119,15 @@
|
||||
"node": ">=10.13.0"
|
||||
}
|
||||
},
|
||||
"node_modules/error-stack-parser": {
|
||||
"version": "2.1.4",
|
||||
"resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.1.4.tgz",
|
||||
"integrity": "sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"stackframe": "^1.3.4"
|
||||
}
|
||||
},
|
||||
"node_modules/es-abstract": {
|
||||
"version": "1.24.1",
|
||||
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.1.tgz",
|
||||
@@ -3496,7 +3756,6 @@
|
||||
"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-glob": {
|
||||
@@ -3543,6 +3802,17 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/fast-shallow-equal": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fast-shallow-equal/-/fast-shallow-equal-1.0.0.tgz",
|
||||
"integrity": "sha512-HPtaa38cPgWvaCFmRNhlc6NG7pv6NUHqjPgVAkWGoB9mQMwYB27/K0CvOM5Czy+qpT3e8XJ6Q4aPAnzpNpzNaw=="
|
||||
},
|
||||
"node_modules/fastest-stable-stringify": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/fastest-stable-stringify/-/fastest-stable-stringify-2.0.2.tgz",
|
||||
"integrity": "sha512-bijHueCGd0LqqNK9b5oCMHc0MluJAx0cwqASgbWMvkO01lCYgIhacVRLcaDz3QnyYIRNJRDwMb41VuT6pHJ91Q==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/fastq": {
|
||||
"version": "1.20.1",
|
||||
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz",
|
||||
@@ -3938,6 +4208,12 @@
|
||||
"hermes-estree": "0.25.1"
|
||||
}
|
||||
},
|
||||
"node_modules/hyphenate-style-name": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.1.0.tgz",
|
||||
"integrity": "sha512-WDC/ui2VVRrz3jOVi+XtjqkDjiVjTtFaAGiW37k6b+ohyQ5wYDOGkvCZa8+H0nx3gyvv0+BST9xuOgIyGQ00gw==",
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/ignore": {
|
||||
"version": "5.3.2",
|
||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
|
||||
@@ -3975,6 +4251,15 @@
|
||||
"node": ">=0.8.19"
|
||||
}
|
||||
},
|
||||
"node_modules/inline-style-prefixer": {
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npmjs.org/inline-style-prefixer/-/inline-style-prefixer-7.0.1.tgz",
|
||||
"integrity": "sha512-lhYo5qNTQp3EvSSp3sRvXMbVQTLrvGV6DycRMJ5dm2BLMiJ30wpXKdDdgX+GmJZ5uQMucwRKHamXSst3Sj/Giw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"css-in-js-utils": "^3.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/internal-slot": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz",
|
||||
@@ -4447,11 +4732,16 @@
|
||||
"jiti": "lib/jiti-cli.mjs"
|
||||
}
|
||||
},
|
||||
"node_modules/js-cookie": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-2.2.1.tgz",
|
||||
"integrity": "sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/js-tokens": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/js-yaml": {
|
||||
@@ -4530,6 +4820,12 @@
|
||||
"node": ">=4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/jw-paginate": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/jw-paginate/-/jw-paginate-1.0.4.tgz",
|
||||
"integrity": "sha512-W0bv782exgCoynUL/egbRpaYwf/r6T6e02H870H5u3hfSgEYrxgz5POwmFF5aApS6iPi6yhZ0VF8IbafNFsntA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/keyv": {
|
||||
"version": "4.5.4",
|
||||
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
|
||||
@@ -4862,7 +5158,6 @@
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
|
||||
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"js-tokens": "^3.0.0 || ^4.0.0"
|
||||
@@ -4901,6 +5196,12 @@
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/mdn-data": {
|
||||
"version": "2.0.14",
|
||||
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz",
|
||||
"integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==",
|
||||
"license": "CC0-1.0"
|
||||
},
|
||||
"node_modules/merge2": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
|
||||
@@ -5108,7 +5409,6 @@
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
@@ -5393,6 +5693,20 @@
|
||||
"node": "^10 || ^12 || >=14"
|
||||
}
|
||||
},
|
||||
"node_modules/postcss-selector-parser": {
|
||||
"version": "6.0.10",
|
||||
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz",
|
||||
"integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"cssesc": "^3.0.0",
|
||||
"util-deprecate": "^1.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/prelude-ls": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
|
||||
@@ -5407,7 +5721,6 @@
|
||||
"version": "15.8.1",
|
||||
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
|
||||
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.4.0",
|
||||
@@ -5471,9 +5784,26 @@
|
||||
"version": "16.13.1",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/react-polymorphed": {
|
||||
"version": "2.2.2",
|
||||
"resolved": "https://registry.npmjs.org/react-polymorphed/-/react-polymorphed-2.2.2.tgz",
|
||||
"integrity": "sha512-8pv0VvOHITcmGs+E/FNAuE+4IZpIaKEThCJsvmp+NC54Lq5YbjHtPX0Af6H6MazhEQ7WQyJBt6b6aY+7WUytJw==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@types/react": ">=16.8"
|
||||
}
|
||||
},
|
||||
"node_modules/react-universal-interface": {
|
||||
"version": "0.6.2",
|
||||
"resolved": "https://registry.npmjs.org/react-universal-interface/-/react-universal-interface-0.6.2.tgz",
|
||||
"integrity": "sha512-dg8yXdcQmvgR13RIlZbTRQOoUrDciFVoSBZILwjE2LFISxZZ8loVJKAkuzswl5js8BHda79bIb2b84ehU8IjXw==",
|
||||
"peerDependencies": {
|
||||
"react": "*",
|
||||
"tslib": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/reflect.getprototypeof": {
|
||||
"version": "1.0.10",
|
||||
"resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz",
|
||||
@@ -5518,6 +5848,12 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/resize-observer-polyfill": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz",
|
||||
"integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/resolve": {
|
||||
"version": "1.22.11",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz",
|
||||
@@ -5570,6 +5906,15 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/rtl-css-js": {
|
||||
"version": "1.16.1",
|
||||
"resolved": "https://registry.npmjs.org/rtl-css-js/-/rtl-css-js-1.16.1.tgz",
|
||||
"integrity": "sha512-lRQgou1mu19e+Ya0LsTvKrVJ5TYUbqCVPAiImX3UfLTenarvPUl1QFdvu5Z3PYmHT9RCcwIfbjRQBntExyj3Zg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.1.2"
|
||||
}
|
||||
},
|
||||
"node_modules/run-parallel": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
|
||||
@@ -5655,6 +6000,18 @@
|
||||
"integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/screenfull": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/screenfull/-/screenfull-5.2.0.tgz",
|
||||
"integrity": "sha512-9BakfsO2aUQN2K9Fdbj87RJIEZ82Q9IGim7FqM5OsebfoFC6ZHXgDq/KvniuLTPdeM8wY2o6Dj3WQ7KeQCj3cA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/semver": {
|
||||
"version": "6.3.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
||||
@@ -5699,6 +6056,15 @@
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/set-harmonic-interval": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/set-harmonic-interval/-/set-harmonic-interval-1.0.1.tgz",
|
||||
"integrity": "sha512-AhICkFV84tBP1aWqPwLZqFvAwqEoVA9kxNMniGEUvzOlm4vLmOFLiTT3UZ6bziJTy4bOVpzWGTfSCbmaayGx8g==",
|
||||
"license": "Unlicense",
|
||||
"engines": {
|
||||
"node": ">=6.9"
|
||||
}
|
||||
},
|
||||
"node_modules/set-proto": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz",
|
||||
@@ -5871,6 +6237,15 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/source-map": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
||||
"license": "BSD-3-Clause",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/source-map-js": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
|
||||
@@ -5887,6 +6262,51 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/stack-generator": {
|
||||
"version": "2.0.10",
|
||||
"resolved": "https://registry.npmjs.org/stack-generator/-/stack-generator-2.0.10.tgz",
|
||||
"integrity": "sha512-mwnua/hkqM6pF4k8SnmZ2zfETsRUpWXREfA/goT8SLCV4iOFa4bzOX2nDipWAZFPTjLvQB82f5yaodMVhK0yJQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"stackframe": "^1.3.4"
|
||||
}
|
||||
},
|
||||
"node_modules/stackframe": {
|
||||
"version": "1.3.4",
|
||||
"resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz",
|
||||
"integrity": "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/stacktrace-gps": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/stacktrace-gps/-/stacktrace-gps-3.1.2.tgz",
|
||||
"integrity": "sha512-GcUgbO4Jsqqg6RxfyTHFiPxdPqF+3LFmQhm7MgCuYQOYuWyqxo5pwRPz5d/u6/WYJdEnWfK4r+jGbyD8TSggXQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"source-map": "0.5.6",
|
||||
"stackframe": "^1.3.4"
|
||||
}
|
||||
},
|
||||
"node_modules/stacktrace-gps/node_modules/source-map": {
|
||||
"version": "0.5.6",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz",
|
||||
"integrity": "sha512-MjZkVp0NHr5+TPihLcadqnlVoGIoWo4IBHptutGh9wI3ttUYvCG26HkSuDi+K6lsZ25syXJXcctwgyVCt//xqA==",
|
||||
"license": "BSD-3-Clause",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/stacktrace-js": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/stacktrace-js/-/stacktrace-js-2.0.2.tgz",
|
||||
"integrity": "sha512-Je5vBeY4S1r/RnLydLl0TBTi3F2qdfWmYsGvtfZgEI+SCprPppaIhQf5nGcal4gI4cGpCV/duLcAzT1np6sQqg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"error-stack-parser": "^2.0.6",
|
||||
"stack-generator": "^2.0.5",
|
||||
"stacktrace-gps": "^3.0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/stop-iteration-iterator": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz",
|
||||
@@ -6060,6 +6480,12 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/stylis": {
|
||||
"version": "4.3.6",
|
||||
"resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.6.tgz",
|
||||
"integrity": "sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/supports-color": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
||||
@@ -6086,6 +6512,12 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/tabbable": {
|
||||
"version": "6.4.0",
|
||||
"resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.4.0.tgz",
|
||||
"integrity": "sha512-05PUHKSNE8ou2dwIxTngl4EzcnsCDZGJ/iCLtDflR/SHB/ny14rXc+qU5P4mG9JkusiV7EivzY9Mhm55AzAvCg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/tailwind-merge": {
|
||||
"version": "3.4.0",
|
||||
"resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.4.0.tgz",
|
||||
@@ -6100,7 +6532,6 @@
|
||||
"version": "4.1.18",
|
||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.18.tgz",
|
||||
"integrity": "sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/tapable": {
|
||||
@@ -6117,6 +6548,15 @@
|
||||
"url": "https://opencollective.com/webpack"
|
||||
}
|
||||
},
|
||||
"node_modules/throttle-debounce": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/throttle-debounce/-/throttle-debounce-3.0.1.tgz",
|
||||
"integrity": "sha512-dTEWWNu6JmeVXY0ZYoPuH5cRIwc0MeGbJwah9KUNYSJwommQpCzTySTpEe8Gs1J23aeWEuAobe4Ag7EHVt/LOg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/tinyglobby": {
|
||||
"version": "0.2.15",
|
||||
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
|
||||
@@ -6178,6 +6618,12 @@
|
||||
"node": ">=8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/toggle-selection": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz",
|
||||
"integrity": "sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/ts-api-utils": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.4.0.tgz",
|
||||
@@ -6191,6 +6637,12 @@
|
||||
"typescript": ">=4.8.4"
|
||||
}
|
||||
},
|
||||
"node_modules/ts-easing": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/ts-easing/-/ts-easing-0.2.0.tgz",
|
||||
"integrity": "sha512-Z86EW+fFFh/IFB1fqQ3/+7Zpf9t2ebOAxNI/V6Wo7r5gqiqtxmgTlQ1qbqQcjLKYeSHPTsEmvlJUDg/EuL0uHQ==",
|
||||
"license": "Unlicense"
|
||||
},
|
||||
"node_modules/tsconfig-paths": {
|
||||
"version": "3.15.0",
|
||||
"resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz",
|
||||
@@ -6454,6 +6906,13 @@
|
||||
"punycode": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"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",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/which": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
"lint": "eslint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@storefront-ui/react": "^4.0.0",
|
||||
"bcrypt": "^6.0.0",
|
||||
"clsx": "^2.1.1",
|
||||
"next": "^16.1.4",
|
||||
|
||||
BIN
public/favicon.ico
Normal file
BIN
public/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.2 KiB |
@@ -1,16 +1,29 @@
|
||||
"use client"
|
||||
import {Button} from "@/components/Button/Button";
|
||||
import {SingleCard} from "@/components/SingleCard/SingleCard";
|
||||
import {Link} from "@/components/Link";
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
<div className={"flex flex-col items-center justify-center h-full border-[#e20074]!"}>
|
||||
<Button onClick={() => {
|
||||
alert("WOW")
|
||||
}} className={""}>
|
||||
Hallo Welt Knopf
|
||||
</Button>
|
||||
<Button typeStyle={"secondary"}>Tes23</Button>
|
||||
<Button typeStyle={"tertiary"}>Tes23</Button>
|
||||
<div className={"flex flex-col items-center justify-between h-full "}>
|
||||
<div className={"h-20"}/>
|
||||
|
||||
<SingleCard className={"w-400 rounded-2xl! flex-col!"}>
|
||||
<a className={"md:text-4xl pb-4 pt-2"}>Gibt es ein Problem?</a>
|
||||
<div className={"h-10"}/>
|
||||
<Link href={"/new/ticket"} className={"mb-8"} onClick={() => {
|
||||
}} typeStyle={"primary"}>Problem melden</Link>
|
||||
</SingleCard>
|
||||
|
||||
<div className={"h-10"}/>
|
||||
|
||||
<SingleCard className={"w-400 rounded-2xl! flex-col! bg-primary/15!"}>
|
||||
<a className={"md:text-4xl pb-4 pt-2"}>Du möchtest deine Tickets ansehen?</a>
|
||||
<div className={"h-10"}/>
|
||||
<Link href={"/tickets"} className={"mb-8"} onClick={() => {
|
||||
}} typeStyle={"primary"}>Zur Ticketansicht</Link>
|
||||
</SingleCard>
|
||||
|
||||
<div className={"h-20"}/>
|
||||
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import type { Metadata } from "next";
|
||||
import { Geist, Geist_Mono } from "next/font/google";
|
||||
import type {Metadata} from "next";
|
||||
import {Geist, Geist_Mono} from "next/font/google";
|
||||
import "@/app/globals.css";
|
||||
import React from "react";
|
||||
import {Header} from "@/components/Header/Header";
|
||||
import {Footer} from "@/components/Footer";
|
||||
|
||||
const geistSans = Geist({
|
||||
variable: "--font-geist-sans",
|
||||
@@ -28,11 +29,15 @@ export default function RootLayout({
|
||||
return (
|
||||
<html lang="de" suppressHydrationWarning>
|
||||
<body
|
||||
className={`${geistSans.variable} ${geistMono.variable} antialiased` }
|
||||
className={`${geistSans.variable} ${geistMono.variable} antialiased flex flex-col min-h-screen`}
|
||||
suppressHydrationWarning
|
||||
>
|
||||
|
||||
<Header/>
|
||||
<main className={"grow"}>
|
||||
{children}
|
||||
</main>
|
||||
<Footer/>
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
|
||||
159
src/app/(auth-required)/new/ticket/page.tsx
Normal file
159
src/app/(auth-required)/new/ticket/page.tsx
Normal file
@@ -0,0 +1,159 @@
|
||||
'use client'
|
||||
import { use, useEffect, useState, ChangeEvent } from 'react'
|
||||
import { SingleCard } from "@/components/SingleCard/SingleCard";
|
||||
import Form from "next/dist/client/form";
|
||||
import { Button } from "@/components/Button";
|
||||
import {getCategories, Ticket} from "@/components/Tickets";
|
||||
import {sendRequestwTokenClient} from "@/app/actions/auth";
|
||||
import {getUser} from "@/components/getUser";
|
||||
import {useRouter} from "next/navigation";
|
||||
|
||||
export default function Page({
|
||||
params,
|
||||
}: {
|
||||
params: Promise<{ slug: string }>
|
||||
}) {
|
||||
|
||||
const router = useRouter();
|
||||
const StateMapping = ["Offen","Bearbeitet","Abgeschlossen"]
|
||||
const PrioMapping = ["Niedrig","Mittel","Hoch","Notfall"]
|
||||
|
||||
|
||||
// Initialer State leer, damit wir keine Fehler bei undefined haben
|
||||
const [currentUser, setCurrentUser] = useState<string | null>()
|
||||
const [currentTicket, setCurrentTicket] = useState<Ticket| null>({
|
||||
category: undefined,
|
||||
description: "",
|
||||
priority: 1,
|
||||
status: 1,
|
||||
ticketID: 1,
|
||||
ticketname: "",
|
||||
username: ""
|
||||
|
||||
});
|
||||
const [categories, setCategories] = useState<string[] | null>(null);
|
||||
|
||||
const { slug } = use(params);
|
||||
const ticketId: number = Number(slug);
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
const runAsync = async () => {
|
||||
const category = await getCategories() || null;
|
||||
const user = await getUser() || "none"
|
||||
setCategories(category)
|
||||
setCurrentUser(user)
|
||||
setCurrentTicket((prev) => {return {...(prev as Ticket), username: user}})
|
||||
}
|
||||
runAsync();
|
||||
}, [ticketId]);
|
||||
|
||||
// Zentraler Change-Handler für alle Inputs
|
||||
const handleChange = (e: ChangeEvent<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>) => {
|
||||
const { name, value } = e.target;
|
||||
|
||||
setCurrentTicket((prev) => {
|
||||
if (!prev) return null;
|
||||
|
||||
return {
|
||||
...prev,
|
||||
[name]: value
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
const formAction = (e: FormData) => {
|
||||
|
||||
// Wenn du die Daten aus dem e: FormData Objekt ziehen willst (wie bisher):
|
||||
const ticket: Ticket = {
|
||||
status: Number(e.get("status")),
|
||||
priority: Number(e.get("priority")),
|
||||
category: e.get("category")?.toString(),
|
||||
ticketname: e.get("ticketname")?.toString() || "none",
|
||||
description: e.get("description")?.toString() || "none",
|
||||
username: currentUser || "none",
|
||||
};
|
||||
sendRequestwTokenClient(`/ticket/create`, "POST",JSON.stringify(ticket))
|
||||
router.push("/tickets")
|
||||
};
|
||||
|
||||
if (!currentUser) {
|
||||
return <a>Loading...</a>
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={"flex flex-col"}>
|
||||
<SingleCard>
|
||||
<Form className={"flex flex-row grow justify-between"} action={formAction}>
|
||||
<div className={"flex flex-col"}>
|
||||
<div className={"flex flex-row"}>
|
||||
<label className={"my-auto w-24"}>Ticketname</label>
|
||||
<input
|
||||
type={"text"}
|
||||
name={"ticketname"}
|
||||
className={"bg-secondary/25 m-2 p-1 w-80"}
|
||||
value={currentTicket?.ticketname}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
</div>
|
||||
<div className={"flex flex-row"}>
|
||||
<label className={"my-auto w-24 min-w-24"}>Status</label>
|
||||
<select
|
||||
name={"status"}
|
||||
className={"bg-secondary/25 rounded p-2 m-2 w-80"}
|
||||
value={currentTicket?.status}
|
||||
onChange={handleChange}
|
||||
>
|
||||
{
|
||||
StateMapping?.map((value, index) => {
|
||||
return (<option key={`${value}-${index}`} value={index +1}>{value}</option>)
|
||||
})
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
<div className={"flex flex-row align-items-center"}>
|
||||
<label className={"my-auto w-24 min-w-24"}>Kategorie</label>
|
||||
<select
|
||||
className={"bg-secondary/25 rounded p-2 m-2 w-80"}
|
||||
name={"category"}
|
||||
|
||||
value={currentTicket?.category}
|
||||
onChange={handleChange}
|
||||
>
|
||||
{categories && categories?.map((value, index) => {
|
||||
return (<option key={`${value}-${index}`} value={value}>{value}</option>)
|
||||
})}
|
||||
</select>
|
||||
</div>
|
||||
<div className={"flex flex-row"}>
|
||||
<label className={"my-auto w-24 min-w-24"}>Priorität</label>
|
||||
<select
|
||||
className={"bg-secondary/25 rounded p-2 m-2 w-80"}
|
||||
name={"priority"}
|
||||
value={currentTicket?.priority}
|
||||
onChange={handleChange}
|
||||
>
|
||||
{
|
||||
PrioMapping?.map((value, index) => {
|
||||
return (<option key={`${value}-${index}`} value={index +1}>{value}</option>)
|
||||
})
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div className={"flex flex-col px-20 grow"}>
|
||||
<label className={"my-auto w-24 min-w-24 m-2"}>Beschreibung</label>
|
||||
<textarea
|
||||
name="description"
|
||||
className="bg-secondary/25 m-2 grow p-2 min-h-10 resize-none overflow-hidden wrap-break-word focus:outline-none"
|
||||
rows={3}
|
||||
value={currentTicket?.description}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
</div>
|
||||
<Button type={"submit"} className={"w-min p-4 h-min m-auto text-xl"}>Bearbeiten</Button>
|
||||
</Form>
|
||||
</SingleCard>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
147
src/app/(auth-required)/tickets/[slug]/page.tsx
Normal file
147
src/app/(auth-required)/tickets/[slug]/page.tsx
Normal file
@@ -0,0 +1,147 @@
|
||||
'use client'
|
||||
import { use, useEffect, useState, ChangeEvent } from 'react'
|
||||
import { SingleCard } from "@/components/SingleCard/SingleCard";
|
||||
import Form from "next/dist/client/form";
|
||||
import { Button } from "@/components/Button";
|
||||
import {DetailedTicket, getCategories, Ticket} from "@/components/Tickets";
|
||||
import { getTicket } from "@/components/Tickets/getTicket";
|
||||
import {sendRequestwTokenClient} from "@/app/actions/auth";
|
||||
|
||||
export default function Page({
|
||||
params,
|
||||
}: {
|
||||
params: Promise<{ slug: string }>
|
||||
}) {
|
||||
|
||||
const StateMapping = ["A","B","C"]
|
||||
const PrioMapping = ["Niedrig","Mittel","Hoch","Notfall"]
|
||||
|
||||
|
||||
// Initialer State leer, damit wir keine Fehler bei undefined haben
|
||||
const [currentTicket, setCurrentTicket] = useState<DetailedTicket | null>(null);
|
||||
const [categories, setCategories] = useState<string[] | null>(null);
|
||||
|
||||
const { slug } = use(params);
|
||||
const ticketId: number = Number(slug);
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
const runAsync = async () => {
|
||||
const ticket = await getTicket(ticketId) || null;
|
||||
const category = await getCategories() || null;
|
||||
setCategories(category)
|
||||
setCurrentTicket(ticket);
|
||||
}
|
||||
runAsync();
|
||||
}, [ticketId]);
|
||||
|
||||
// Zentraler Change-Handler für alle Inputs
|
||||
const handleChange = (e: ChangeEvent<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>) => {
|
||||
const { name, value } = e.target;
|
||||
console.log("IS CHANGED", name);
|
||||
|
||||
setCurrentTicket((prev) => {
|
||||
if (!prev) return null;
|
||||
|
||||
return {
|
||||
...prev,
|
||||
[name]: value
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
const formAction = (e: FormData) => {
|
||||
// Hier kannst du die Daten an den Server schicken
|
||||
console.log("Form submitted with:", currentTicket);
|
||||
|
||||
// Wenn du die Daten aus dem e: FormData Objekt ziehen willst (wie bisher):
|
||||
const ticket: Ticket = {
|
||||
status: Number(e.get("status")),
|
||||
priority: Number(e.get("priority")),
|
||||
category: e.get("category")?.toString(),
|
||||
ticketname: e.get("ticketname")?.toString() || "none",
|
||||
description: e.get("description")?.toString() || "none",
|
||||
username: currentTicket?.username || "none",
|
||||
};
|
||||
sendRequestwTokenClient(`/ticket/update/${ticketId}`, "POST",JSON.stringify(ticket))
|
||||
alert("Gespeichert!");
|
||||
};
|
||||
|
||||
if (!currentTicket) return <div>Lade Ticket...</div>;
|
||||
console.log(currentTicket);
|
||||
return (
|
||||
<div className={"flex flex-col "}>
|
||||
<SingleCard>
|
||||
<Form className={"flex flex-row grow justify-between"} action={formAction}>
|
||||
<div className={"flex flex-col"}>
|
||||
<div className={"flex flex-row"}>
|
||||
<label className={"my-auto w-24"}>Ticketname</label>
|
||||
<input
|
||||
type={"text"}
|
||||
name={"ticketname"}
|
||||
className={"bg-secondary/25 m-2 p-1 w-80"}
|
||||
value={currentTicket.ticketname}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
</div>
|
||||
<div className={"flex flex-row"}>
|
||||
<label className={"my-auto w-24 min-w-24"}>Status</label>
|
||||
<select
|
||||
name={"status"}
|
||||
className={"bg-secondary/25 rounded p-2 m-2 w-80"}
|
||||
value={currentTicket.status}
|
||||
onChange={handleChange}
|
||||
>
|
||||
{
|
||||
StateMapping?.map((value, index) => {
|
||||
return (<option key={`${value}-${index}`} value={index +1}>{value}</option>)
|
||||
})
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
<div className={"flex flex-row align-items-center"}>
|
||||
<label className={"my-auto w-24 min-w-24"}>Kategorie</label>
|
||||
<select
|
||||
className={"bg-secondary/25 rounded p-2 m-2 w-80"}
|
||||
name={"category"}
|
||||
value={currentTicket.category}
|
||||
onChange={handleChange}
|
||||
>
|
||||
{categories && categories?.map((value, index) => {
|
||||
return (<option key={`${value}-${index}`} value={value}>{value}</option>)
|
||||
})}
|
||||
</select>
|
||||
</div>
|
||||
<div className={"flex flex-row"}>
|
||||
<label className={"my-auto w-24 min-w-24"}>Priorität</label>
|
||||
<select
|
||||
|
||||
className={"bg-secondary/25 rounded p-2 m-2 w-80"}
|
||||
name={"priority"}
|
||||
value={currentTicket.priority}
|
||||
onChange={handleChange}
|
||||
>
|
||||
{
|
||||
PrioMapping?.map((value, index) => {
|
||||
return (<option key={`${value}-${index}`} value={index +1}>{value}</option>)
|
||||
})
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div className={"flex flex-col px-20 grow"}>
|
||||
<label className={"my-auto w-24 min-w-24 m-2"}>Beschreibung</label>
|
||||
<textarea
|
||||
name="description"
|
||||
className="bg-secondary/25 m-2 grow p-2 min-h-10 resize-none overflow-hidden wrap-break-word focus:outline-none"
|
||||
rows={3}
|
||||
value={currentTicket.description}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
</div>
|
||||
<Button type={"submit"} className={"w-min p-4 h-min m-auto text-xl"}>Bearbeiten</Button>
|
||||
</Form>
|
||||
</SingleCard>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
18
src/app/(auth-required)/tickets/page.tsx
Normal file
18
src/app/(auth-required)/tickets/page.tsx
Normal file
@@ -0,0 +1,18 @@
|
||||
'use server'
|
||||
|
||||
import React from "react";
|
||||
import {SingleCard} from "@/components/SingleCard/SingleCard";
|
||||
import {TicketTable} from "@/components/TicketTable";
|
||||
|
||||
export default async function Page() {
|
||||
|
||||
return (
|
||||
<>
|
||||
<SingleCard>
|
||||
<a>Deine Tickets</a>
|
||||
</SingleCard>
|
||||
<TicketTable/>
|
||||
<a></a>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -2,6 +2,8 @@ import type {Metadata} from "next";
|
||||
import {Geist, Geist_Mono} from "next/font/google";
|
||||
import "@/app/globals.css";
|
||||
import React from "react";
|
||||
import {Header} from "@/components/Header/Header";
|
||||
import {Footer} from "@/components/Footer";
|
||||
|
||||
const geistSans = Geist({
|
||||
variable: "--font-geist-sans",
|
||||
@@ -25,13 +27,17 @@ export default function RootLayout({
|
||||
}>) {
|
||||
|
||||
return (
|
||||
<html lang="en" suppressHydrationWarning>
|
||||
<html lang="de" suppressHydrationWarning>
|
||||
<body
|
||||
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
|
||||
className={`${geistSans.variable} ${geistMono.variable} antialiased flex flex-col min-h-screen`}
|
||||
suppressHydrationWarning
|
||||
>
|
||||
<a>OFFENES LAYOUT</a>
|
||||
|
||||
<Header/>
|
||||
<main className={"flex grow"}>
|
||||
{children}
|
||||
</main>
|
||||
<Footer/>
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
|
||||
@@ -1,12 +1,7 @@
|
||||
'use client'
|
||||
'use server'
|
||||
import {SignInForm} from "@/components/SignInForm/SignInForm";
|
||||
|
||||
interface Submission {
|
||||
username: string;
|
||||
password: string;
|
||||
}
|
||||
|
||||
export default function Page() {
|
||||
export default async function Page() {
|
||||
|
||||
return (
|
||||
<SignInForm/>
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
'use server'
|
||||
import {FormState} from '@/components/FormState/definitions'
|
||||
import {ResponseToken} from "@/app/actions/interfaces";
|
||||
import { cookies } from 'next/headers'
|
||||
import {cookies} from 'next/headers'
|
||||
import 'server-only'
|
||||
import {encrypt} from "next/dist/server/app-render/encryption-utils";
|
||||
import {redirect} from "next/dist/client/components/redirect";
|
||||
|
||||
export async function signup(state: FormState, formData: FormData) {
|
||||
@@ -14,7 +13,7 @@ export async function signup(state: FormState, formData: FormData) {
|
||||
if (!username || !password) {
|
||||
return {
|
||||
errors: {
|
||||
name: !username ? ["username not defined"]: undefined,
|
||||
name: !username ? ["username not defined"] : undefined,
|
||||
message: !password ? ["password not defined"] : undefined,
|
||||
}
|
||||
}
|
||||
@@ -22,7 +21,7 @@ export async function signup(state: FormState, formData: FormData) {
|
||||
|
||||
console.log("Sign up", username, password)
|
||||
|
||||
const endpoint: string = process.env.RUST_BACKEND_API_ENDPOINT as string;
|
||||
const endpoint: string = process.env.API_ENDPOINT as string;
|
||||
|
||||
|
||||
// 3. Insert the user into the database or call an Auth Library's API
|
||||
@@ -40,7 +39,7 @@ export async function signup(state: FormState, formData: FormData) {
|
||||
if (!resp.ok) {
|
||||
return {
|
||||
errors: {
|
||||
message: !resp.ok ? "Sign in unsuccessful" : undefined,
|
||||
message: "Sign in unsuccessful"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -52,8 +51,15 @@ export async function signup(state: FormState, formData: FormData) {
|
||||
const cookieStore = await cookies()
|
||||
|
||||
cookieStore.set('token', response.token, {
|
||||
httpOnly: true,
|
||||
secure: true,
|
||||
/*httpOnly: true,
|
||||
secure: true, */
|
||||
expires: expiresAt,
|
||||
sameSite: 'lax',
|
||||
path: '/',
|
||||
})
|
||||
cookieStore.set('user', username, {
|
||||
/*httpOnly: true,
|
||||
secure: true, */
|
||||
expires: expiresAt,
|
||||
sameSite: 'lax',
|
||||
path: '/',
|
||||
@@ -62,9 +68,13 @@ export async function signup(state: FormState, formData: FormData) {
|
||||
redirect("/home")
|
||||
}
|
||||
|
||||
export async function sendRequestwToken(url: string,method: string, body?: JSON){
|
||||
export async function sendRequestwToken(url: string, method: string, body?: string): Promise<Response | null> {
|
||||
const cookieStore = await cookies();
|
||||
const token = cookieStore.get("token")?.value
|
||||
const backendURL = process.env.API_ENDPOINT as string;
|
||||
const fullUrl = `${backendURL}${url.startsWith("/") ? url: `/${url}`}`;
|
||||
|
||||
|
||||
|
||||
if (!token) return null;
|
||||
|
||||
@@ -75,9 +85,13 @@ export async function sendRequestwToken(url: string,method: string, body?: JSON)
|
||||
"Authorization": bearerToken,
|
||||
}
|
||||
|
||||
return await fetch(url, {
|
||||
return await fetch(fullUrl, {
|
||||
method,
|
||||
headers,
|
||||
body: body ? JSON.stringify(body) : undefined,
|
||||
body: body ? body : undefined,
|
||||
})
|
||||
}
|
||||
|
||||
export async function sendRequestwTokenClient(url: string, method: string, body?: string) {
|
||||
await sendRequestwToken(url, method, body)
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 206 KiB |
@@ -1,19 +1,11 @@
|
||||
"use client"
|
||||
import React from "react";
|
||||
import {ClassNameValue, twMerge} from "tailwind-merge"
|
||||
import {clsx} from "clsx";
|
||||
import {CustomButtonProps} from "@/components/Button";
|
||||
import {cn} from "@/components/cn";
|
||||
|
||||
interface CustomButtonProps extends React.HTMLProps<HTMLButtonElement> {
|
||||
children?: React.ReactNode
|
||||
type?: "button" | "submit" | "reset"
|
||||
typeStyle?: "primary" | "secondary" | "tertiary"
|
||||
}
|
||||
export function Button({children, className, onClick, typeStyle = "primary", link, ...otherProps}: CustomButtonProps) {
|
||||
|
||||
const cn = (...input: ClassNameValue[]) => twMerge(clsx(input));
|
||||
|
||||
export function Button({children, className, onClick, typeStyle = "primary", ...otherProps}: CustomButtonProps) {
|
||||
|
||||
let typStyleCss = () => {
|
||||
const typStyleCss = () => {
|
||||
switch (typeStyle) {
|
||||
case "primary":
|
||||
return cn("bg-primary", "border-primary", "hover:border-tertiary");
|
||||
@@ -35,10 +27,11 @@ export function Button({children, className, onClick, typeStyle = "primary", ...
|
||||
typStyleCss(),
|
||||
"transition-all",
|
||||
"border-2",
|
||||
"p-1",
|
||||
"p-2 pr-8 pl-8",
|
||||
"rounded",
|
||||
"m-2",
|
||||
"text-center",
|
||||
"text-2xl",
|
||||
className,
|
||||
onClick && "hover:cursor-pointer",
|
||||
)
|
||||
|
||||
2
src/components/Button/index.ts
Normal file
2
src/components/Button/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from './Button';
|
||||
export * from './interfaces';
|
||||
6
src/components/Button/interfaces.ts
Normal file
6
src/components/Button/interfaces.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
export interface CustomButtonProps extends React.HTMLProps<HTMLButtonElement> {
|
||||
children?: React.ReactNode
|
||||
type?: "button" | "submit" | "reset"
|
||||
typeStyle?: "primary" | "secondary" | "tertiary"
|
||||
link?: string
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import 'server-only'
|
||||
|
||||
import { cookies } from 'next/headers'
|
||||
import {cookies} from 'next/headers'
|
||||
import {cache} from "react";
|
||||
import {sendRequestwToken} from "@/app/actions/auth";
|
||||
import {TokenIsValid} from "@/app/actions/interfaces";
|
||||
@@ -10,13 +10,13 @@ import {TokenIsValid} from "@/app/actions/interfaces";
|
||||
export const verifySession = cache(async () => {
|
||||
const cookie = (await cookies()).get('token')?.value
|
||||
|
||||
const resp = await sendRequestwToken(`${process.env.API_ENDPOINT}/token/validate`,'GET')
|
||||
const resp = await sendRequestwToken(`/token/validate`, 'GET')
|
||||
|
||||
if (!cookie || resp === null) {
|
||||
return { isAuth: false, token: cookie }
|
||||
return {isAuth: false, token: cookie}
|
||||
}
|
||||
|
||||
console.log("hello world")
|
||||
const is_valid = (await (resp as Response).json()) as TokenIsValid
|
||||
|
||||
return { isAuth: is_valid.is_valid, token: cookie }
|
||||
return {isAuth: is_valid.is_valid, token: cookie}
|
||||
})
|
||||
25
src/components/Footer/Footer.tsx
Normal file
25
src/components/Footer/Footer.tsx
Normal file
@@ -0,0 +1,25 @@
|
||||
'use server'
|
||||
import {Link} from "@/components/Link";
|
||||
|
||||
export async function Footer() {
|
||||
const date = new Date();
|
||||
const year = date.getFullYear();
|
||||
|
||||
return (
|
||||
|
||||
<div
|
||||
className={"border-t border-gray-100 flex items-center justify-between shadow-md transition-all mt-auto bottom-0 align-bottom"}>
|
||||
<div className={"pl-4 flex flex-row ml-16"}>
|
||||
<div className={"h-24"}></div>
|
||||
<Link href={"/home"} typeStyle={"tertiary"} className={"text-xl h-min m-auto border-0"}>Home</Link>
|
||||
<Link href={"/contact"} typeStyle={"tertiary"}
|
||||
className={"text-xl h-min m-auto border-0"}>Kontakt</Link>
|
||||
<Link href={"/privacy"} typeStyle={"tertiary"}
|
||||
className={"text-xl h-min m-auto border-0"}>Datenschutzerklärung</Link>
|
||||
</div>
|
||||
<div className={"pl-4 flex flex-row mr-16"}>
|
||||
© {year} Leander Mundkowsky
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
1
src/components/Footer/index.ts
Normal file
1
src/components/Footer/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from './Footer';
|
||||
@@ -1,15 +1,52 @@
|
||||
'use client'
|
||||
import Logo from "@/components/svg/logo";
|
||||
import {Notification} from "@/components/Notification";
|
||||
import {Link} from "@/components/Link";
|
||||
import {LogoutButton} from "@/components/LogoutButton";
|
||||
import {useLoggedState} from "@/components/isLoggedIn";
|
||||
import {getUser} from "@/components/getUser";
|
||||
import {useEffect, useState} from "react";
|
||||
|
||||
export function Header() {
|
||||
const [username, setUsername] = useState<string | undefined>(undefined);
|
||||
|
||||
useEffect(() => {
|
||||
const execAsync = async () => {
|
||||
const user = await getUser();
|
||||
setUsername(user);
|
||||
}
|
||||
|
||||
execAsync();
|
||||
}, [])
|
||||
|
||||
|
||||
const loggedState = useLoggedState();
|
||||
return (
|
||||
<div className={"border-b border-gray-200 flex items-center justify-between shadow-md"}>
|
||||
<div className={"pl-4"}>
|
||||
<Logo className={"bg-primary p-4"} fill="white" width={"7dvh"} height={"7dvh"}/>
|
||||
<div className={"border-b border-gray-200 flex items-center justify-between shadow-md sticky transition-all"}>
|
||||
<div className={"pl-4 flex flex-row ml-16"}>
|
||||
<Logo className={"bg-primary p-4"} fill="transparent" width={"6rem"} height={"6rem"}/>
|
||||
<div className={"w-20"}></div>
|
||||
<Link href={"/home"} typeStyle={"tertiary"} className={"text-xl h-min m-auto border-0"}>Home</Link>
|
||||
<Link href={"/tickets"} typeStyle={"tertiary"}
|
||||
className={"text-xl h-min m-auto border-0"}>Tickets</Link>
|
||||
<Link href={"/user"} typeStyle={"tertiary"}
|
||||
className={"text-xl h-min m-auto border-0"}>Nutzer</Link>
|
||||
</div>
|
||||
<div>
|
||||
<a className={"text-4xl"}></a>
|
||||
</div>
|
||||
<div className={""}>
|
||||
<div className={"mr-16 flex flex-row"}>
|
||||
{loggedState &&
|
||||
(<>
|
||||
<Notification/>
|
||||
<LogoutButton/>
|
||||
<div className={"m-auto"}>
|
||||
<a>Angemeldet als {username}</a>
|
||||
</div>
|
||||
</>
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
44
src/components/Link/Link.tsx
Normal file
44
src/components/Link/Link.tsx
Normal file
@@ -0,0 +1,44 @@
|
||||
'use client'
|
||||
import React from "react";
|
||||
import {cn} from "@/components/cn";
|
||||
import {CustomLinkProps} from "@/components/Link/interfaces";
|
||||
import NextLink from "next/link";
|
||||
|
||||
export function Link({children, className, typeStyle = "primary", href, ...otherProps}: CustomLinkProps) {
|
||||
|
||||
const typStyleCss = () => {
|
||||
switch (typeStyle) {
|
||||
case "primary":
|
||||
return cn("bg-primary", "border-primary", "hover:border-tertiary");
|
||||
case "secondary":
|
||||
return cn("bg-primary/75", "border-primary/70", "hover:border-secondary");
|
||||
case "tertiary":
|
||||
return cn("border-tertiary", "hover:bg-primary/50", "hover:border-primary");
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<NextLink
|
||||
href={href}
|
||||
className={
|
||||
cn(
|
||||
typStyleCss(),
|
||||
"transition-all",
|
||||
"border-2",
|
||||
"p-2 pr-8 pl-8",
|
||||
"rounded",
|
||||
"m-2",
|
||||
"text-center",
|
||||
"text-2xl",
|
||||
className,
|
||||
)
|
||||
}
|
||||
{...otherProps}
|
||||
>
|
||||
{children}
|
||||
</NextLink>
|
||||
)
|
||||
}
|
||||
2
src/components/Link/index.ts
Normal file
2
src/components/Link/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from './Link';
|
||||
export * from './interfaces';
|
||||
10
src/components/Link/interfaces.ts
Normal file
10
src/components/Link/interfaces.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import {LinkProps} from "next/link";
|
||||
import React, {AnchorHTMLAttributes} from "react";
|
||||
import {Url} from "next/dist/shared/lib/router/router";
|
||||
|
||||
export interface CustomLinkProps extends LinkProps, Omit<AnchorHTMLAttributes<HTMLAnchorElement>, keyof LinkProps> {
|
||||
children?: React.ReactNode
|
||||
type?: "button" | "submit" | "reset"
|
||||
typeStyle?: "primary" | "secondary" | "tertiary"
|
||||
link?: Url
|
||||
}
|
||||
36
src/components/LogoutButton/LogoutButton.tsx
Normal file
36
src/components/LogoutButton/LogoutButton.tsx
Normal file
@@ -0,0 +1,36 @@
|
||||
'use client'
|
||||
import {Button} from "@/components/Button";
|
||||
import {removeSession} from "@/components/LogoutButton/removeCookie";
|
||||
import {useEffect, useState} from "react";
|
||||
import Logout from "@/components/svg/logout";
|
||||
|
||||
import {refresh} from "next/cache";
|
||||
|
||||
export function LogoutButton() {
|
||||
|
||||
const [removeCookieState, setRemoveCookieState] = useState<boolean>(false);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
if (!removeCookieState) {
|
||||
return;
|
||||
}
|
||||
console.log("Cleared Login")
|
||||
|
||||
const execAsync = async () => {
|
||||
await removeSession();
|
||||
setRemoveCookieState(false);
|
||||
}
|
||||
execAsync();
|
||||
|
||||
|
||||
}, [removeCookieState])
|
||||
|
||||
function onClick() {
|
||||
setRemoveCookieState(true);
|
||||
}
|
||||
|
||||
return (
|
||||
<Button onClick={onClick} className="m-auto w-min p-2 mr-2"><Logout/></Button>
|
||||
)
|
||||
}
|
||||
1
src/components/LogoutButton/index.ts
Normal file
1
src/components/LogoutButton/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from "./LogoutButton"
|
||||
14
src/components/LogoutButton/removeCookie.ts
Normal file
14
src/components/LogoutButton/removeCookie.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
'use server'
|
||||
|
||||
import {cookies} from "next/headers";
|
||||
import {redirect} from "next/dist/client/components/redirect";
|
||||
|
||||
export async function removeSession() {
|
||||
|
||||
const cookieStore = await cookies()
|
||||
cookieStore.delete("token")
|
||||
cookieStore.delete("user")
|
||||
|
||||
redirect("/login")
|
||||
|
||||
}
|
||||
38
src/components/Notification/Notification.tsx
Normal file
38
src/components/Notification/Notification.tsx
Normal file
@@ -0,0 +1,38 @@
|
||||
'use client'
|
||||
|
||||
import {Button} from "@/components/Button";
|
||||
import Bell from "@/components/svg/notifications/bell";
|
||||
import {useState} from "react";
|
||||
|
||||
export function Notification() {
|
||||
const [notificationIsActive, setNotificationIsActive] = useState<boolean>(false);
|
||||
|
||||
return (
|
||||
/* 'relative' sorgt dafür, dass das absolute Menü hier verankert bleibt */
|
||||
<div className="relative inline-block">
|
||||
<Button
|
||||
className="w-min p-2"
|
||||
onClick={() => setNotificationIsActive(!notificationIsActive)}
|
||||
>
|
||||
<Bell/>
|
||||
</Button>
|
||||
|
||||
{notificationIsActive && <NotificationMenu/>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function NotificationMenu() {
|
||||
return (
|
||||
/* 'absolute' nimmt das Element aus dem Fluss.
|
||||
'right-0' richtet es an der rechten Kante des Buttons aus.
|
||||
'z-50' sorgt dafür, dass es über dem Footer/Content liegt.
|
||||
*/
|
||||
<div
|
||||
className="absolute right-0 w-64 bg-white border-2 border-gray-200 transition shadow-lg rounded-md p-4 z-50">
|
||||
<p className="text-sm font-semibold text-gray-700">Benachrichtigungen</p>
|
||||
<hr className="my-2"/>
|
||||
<div className="text-gray-600">Hello World</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
1
src/components/Notification/index.ts
Normal file
1
src/components/Notification/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from './Notification';
|
||||
0
src/components/Notification/interfaces.ts
Normal file
0
src/components/Notification/interfaces.ts
Normal file
@@ -1,18 +1,25 @@
|
||||
'use client'
|
||||
import Form from "next/dist/client/form";
|
||||
import {useActionState} from "react";
|
||||
import {signup} from "@/app/actions/auth";
|
||||
import {Button} from "@/components/Button";
|
||||
|
||||
export function SignInForm() {
|
||||
const [state, action, pending] = useActionState(signup, undefined)
|
||||
return (
|
||||
<>
|
||||
<Form action={action} className={'flex flex-col items-center justify-center'}>
|
||||
<input id="username" type="text" required={true} name="username" className={"bg-gray-800/50 rounded p-4 m-2"} placeholder="Username" />
|
||||
{state?.errors?.name && <p>{state.errors.name}</p>}
|
||||
<input id="password" type="password" required={true} name="password" className={"bg-gray-800/50 rounded p-4 m-2"} placeholder="Password" />
|
||||
<button disabled={pending} type="submit" className={"bg-gray-800/50 rounded p-4 m-2 hover:bg-gray-800 hover:text-white transition-all"}>Login</button>
|
||||
<Form action={action} className={'flex grow flex-col items-center justify-center'}>
|
||||
<input id="username" type="text" required={true} name="username"
|
||||
className={"bg-primary/50 rounded p-4 m-2"} placeholder="Username"/>
|
||||
{state?.errors?.name && <p>{state.errors.name.map((item, i) => (
|
||||
<div key={i}>
|
||||
{item}
|
||||
</div>
|
||||
))}</p>}
|
||||
<input id="password" type="password" required={true} name="password"
|
||||
className={"bg-primary/50 rounded p-4 m-2"} placeholder="Password"/>
|
||||
<Button disabled={pending} type="submit">
|
||||
Login
|
||||
</Button>
|
||||
</Form>
|
||||
</>
|
||||
|
||||
)
|
||||
}
|
||||
17
src/components/SingleCard/SingleCard.tsx
Normal file
17
src/components/SingleCard/SingleCard.tsx
Normal file
@@ -0,0 +1,17 @@
|
||||
'use client'
|
||||
import React from "react";
|
||||
import {cn} from "@/components/cn";
|
||||
|
||||
interface SingleCardProps extends React.HTMLProps<HTMLDivElement> {
|
||||
children?: React.ReactNode
|
||||
}
|
||||
|
||||
export function SingleCard({children, className, ...props}: SingleCardProps) {
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(className, "rounded", "flex", "flex-row", "items-center", "bg-secondary/15", "justify-center", "min-w-10", "min-h-10", "m-2", "p-3")} {...props}>
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
0
src/components/SingleCard/index.ts
Normal file
0
src/components/SingleCard/index.ts
Normal file
33
src/components/TicketTable/Row.tsx
Normal file
33
src/components/TicketTable/Row.tsx
Normal file
@@ -0,0 +1,33 @@
|
||||
'use client'
|
||||
|
||||
import {Ticket} from "@/components/Tickets";
|
||||
import {useRouter} from "next/navigation";
|
||||
import React from "react";
|
||||
|
||||
export function Row({
|
||||
ticketID,
|
||||
ticketname,
|
||||
username,
|
||||
status,
|
||||
priority,
|
||||
category
|
||||
}: Ticket) {
|
||||
const router = useRouter()
|
||||
const handleTableClick = () => {
|
||||
router.push(`/tickets/${ticketID}`, {})
|
||||
};
|
||||
const StateMapping = ["Offen","Bearbeitet","Abgeschlossen"]
|
||||
const PrioMapping = ["Niedrig","Mittel","Hoch","Notfall"]
|
||||
return (
|
||||
<tr
|
||||
onClick={handleTableClick}
|
||||
className="text-center border-b h-16 hover:bg-primary/10 cursor-pointer transition-colors "
|
||||
>
|
||||
<td>{ticketname}</td>
|
||||
<td>{`${StateMapping[status]}`}</td>
|
||||
<td>{`${PrioMapping[priority]}`}</td>
|
||||
<td>{category}</td>
|
||||
<td>{username}</td>
|
||||
</tr>
|
||||
)
|
||||
}
|
||||
72
src/components/TicketTable/TicketTable.tsx
Normal file
72
src/components/TicketTable/TicketTable.tsx
Normal file
@@ -0,0 +1,72 @@
|
||||
import React from "react";
|
||||
import {Row} from "@/components/TicketTable";
|
||||
import {Ticket} from "@/components/Tickets";
|
||||
import {getTickets} from "@/components/Tickets/getTickets";
|
||||
|
||||
|
||||
export async function TicketTable() {
|
||||
|
||||
const tickets = await getTickets();
|
||||
console.log(tickets);
|
||||
const _mockData: Ticket[] = [{
|
||||
"ticketID": 1,
|
||||
"ticketname": "ADAQ",
|
||||
"username": "admin",
|
||||
"status": 1,
|
||||
"priority": 5,
|
||||
"category": "Crack",
|
||||
"description": "string"
|
||||
},
|
||||
{
|
||||
"ticketID": 2,
|
||||
"ticketname": "ADAQ",
|
||||
"username": "admin",
|
||||
"status": 1,
|
||||
"priority": 5,
|
||||
"category": "Crack",
|
||||
"description": "string"
|
||||
},
|
||||
{
|
||||
"ticketID": 3,
|
||||
"ticketname": "ADAQ",
|
||||
"username": "admin",
|
||||
"status": 1,
|
||||
"priority": 5,
|
||||
"category": "Crack",
|
||||
"description": "string"
|
||||
},
|
||||
{
|
||||
"ticketID": 4,
|
||||
"ticketname": "ADAQ",
|
||||
"username": "admin",
|
||||
"status": 1,
|
||||
"priority": 5,
|
||||
"category": "Crack",
|
||||
"description": "string"
|
||||
}]
|
||||
|
||||
|
||||
return (
|
||||
<div className="flex flex-col w-full px-8">
|
||||
<table className="w-full rounded bg-primary/25 overflow-hidden">
|
||||
<thead className="bg-primary/25 border-b border-secondary">
|
||||
<tr className="h-14">
|
||||
<th scope="col">Titel</th>
|
||||
<th scope="col">Status</th>
|
||||
<th scope="col">Priorität</th>
|
||||
<th scope="col">Kategorie</th>
|
||||
<th scope="col">Erstellt von</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{tickets ? tickets.map((item, i) => (
|
||||
<Row key={`${item.ticketname}-${i}`} ticketID={item.ticketID} ticketname={item.ticketname}
|
||||
username={item.username}
|
||||
status={item.status} priority={item.priority} category={item.category}/>
|
||||
)): (<tr><td>There are no Tickets available</td></tr>)}
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
2
src/components/TicketTable/index.ts
Normal file
2
src/components/TicketTable/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from './TicketTable';
|
||||
export * from "./Row"
|
||||
18
src/components/Tickets/getCategories.ts
Normal file
18
src/components/Tickets/getCategories.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
'use server'
|
||||
import {sendRequestwToken} from "@/app/actions/auth";
|
||||
|
||||
export async function getCategories() : Promise<string[]| undefined> {
|
||||
|
||||
const result = await sendRequestwToken(`/categories`,"GET");
|
||||
|
||||
if (!(await result?.clone().text())) {
|
||||
return undefined;
|
||||
}
|
||||
const ticket = (await result?.json()) as string[];
|
||||
|
||||
if (ticket === null || ticket === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return ticket;
|
||||
}
|
||||
19
src/components/Tickets/getTicket.ts
Normal file
19
src/components/Tickets/getTicket.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
'use server'
|
||||
import {sendRequestwToken} from "@/app/actions/auth";
|
||||
import {DetailedTicket} from "@/components/Tickets";
|
||||
|
||||
export async function getTicket(ticketId: number) : Promise<DetailedTicket| undefined> {
|
||||
|
||||
const result = await sendRequestwToken(`/ticket/show/${ticketId}`,"GET");
|
||||
|
||||
if (!(await result?.clone().text())) {
|
||||
return undefined;
|
||||
}
|
||||
const ticket = (await result?.json()) as DetailedTicket;
|
||||
|
||||
if (ticket === null || ticket === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return ticket;
|
||||
}
|
||||
21
src/components/Tickets/getTickets.ts
Normal file
21
src/components/Tickets/getTickets.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import {sendRequestwToken} from "@/app/actions/auth";
|
||||
import {Ticket} from "@/components/Tickets/interfaces";
|
||||
|
||||
export async function getTickets() {
|
||||
|
||||
const result = await sendRequestwToken("/ticket/show/all","GET");
|
||||
if (!(await result?.clone().text())) {
|
||||
return undefined;
|
||||
}
|
||||
const tickets = await result?.json() as Ticket[];
|
||||
console.log("/////////////////////////////")
|
||||
console.dir(tickets);
|
||||
|
||||
console.log(tickets);
|
||||
|
||||
if (tickets === null || tickets === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return tickets;
|
||||
}
|
||||
4
src/components/Tickets/index.ts
Normal file
4
src/components/Tickets/index.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export * from "./interfaces"
|
||||
export * from "./getTicket"
|
||||
export * from "./getTickets"
|
||||
export * from "./getCategories"
|
||||
23
src/components/Tickets/interfaces.ts
Normal file
23
src/components/Tickets/interfaces.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
export interface Ticket {
|
||||
"ticketID"?: number,
|
||||
"status" : number,
|
||||
"priority": number,
|
||||
"category": string | undefined,
|
||||
"ticketname": string,
|
||||
description?: string,
|
||||
"username": string,
|
||||
}
|
||||
|
||||
export interface Messages {
|
||||
"messageID": number,
|
||||
"sequence": number,
|
||||
"sendAt": string,
|
||||
"content": string,
|
||||
"sender": number,
|
||||
"senderUsername": string,
|
||||
}
|
||||
|
||||
export interface DetailedTicket extends Ticket {
|
||||
userID: number,
|
||||
messages: Messages[] | undefined,
|
||||
}
|
||||
30
src/components/UserTable/Row.tsx
Normal file
30
src/components/UserTable/Row.tsx
Normal file
@@ -0,0 +1,30 @@
|
||||
'use client'
|
||||
|
||||
import {Ticket} from "@/components/Tickets";
|
||||
|
||||
export function Row({
|
||||
ticketID,
|
||||
ticketname,
|
||||
username,
|
||||
status,
|
||||
priority,
|
||||
category
|
||||
}: Ticket) {
|
||||
const handleTableClick = (event: React.MouseEvent<HTMLTableRowElement>) => {
|
||||
// Beispiel: ID aus einem Daten-Attribut auslesen
|
||||
const target = event.currentTarget;
|
||||
console.log("Zeile geklickt!");
|
||||
};
|
||||
return (
|
||||
<tr
|
||||
onClick={handleTableClick}
|
||||
className="text-center border-b h-16 hover:bg-primary/10 cursor-pointer transition-colors"
|
||||
>
|
||||
<td>{ticketname}</td>
|
||||
<td>{`${status}`}</td>
|
||||
<td>{`${priority}`}</td>
|
||||
<td>{category}</td>
|
||||
<td>{username}</td>
|
||||
</tr>
|
||||
)
|
||||
}
|
||||
65
src/components/UserTable/UserTable.tsx
Normal file
65
src/components/UserTable/UserTable.tsx
Normal file
@@ -0,0 +1,65 @@
|
||||
import React from "react";
|
||||
import {Row} from "@/components/TicketTable";
|
||||
import {RequestTicket} from "@/components/RequestTickets";
|
||||
|
||||
|
||||
export async function UserTable() {
|
||||
const mockData: RequestTicket[] = [{
|
||||
"ticketID": 1,
|
||||
"ticketname": "ADAQ",
|
||||
"username": "admin",
|
||||
"status": 1,
|
||||
"priority": 5,
|
||||
"category": "Crack"
|
||||
},
|
||||
{
|
||||
"ticketID": 2,
|
||||
"ticketname": "ADAQ",
|
||||
"username": "admin",
|
||||
"status": 1,
|
||||
"priority": 5,
|
||||
"category": "Crack"
|
||||
},
|
||||
{
|
||||
"ticketID": 3,
|
||||
"ticketname": "ADAQ",
|
||||
"username": "admin",
|
||||
"status": 1,
|
||||
"priority": 5,
|
||||
"category": "Crack"
|
||||
},
|
||||
{
|
||||
"ticketID": 4,
|
||||
"ticketname": "ADAQ",
|
||||
"username": "admin",
|
||||
"status": 1,
|
||||
"priority": 5,
|
||||
"category": "Crack"
|
||||
}]
|
||||
|
||||
|
||||
return (
|
||||
<div className="flex flex-col w-full px-8">
|
||||
{/* Hinweis: mx-8 statt ml/mr für saubere Zentrierung bei w-full */}
|
||||
<table className="w-full rounded bg-primary/25 overflow-hidden">
|
||||
<thead className="bg-primary/25 border-b border-secondary">
|
||||
<tr className="h-14">
|
||||
<th scope="col">Nutzer</th>
|
||||
<th scope="col">Status</th>
|
||||
<th scope="col">Priorität</th>
|
||||
<th scope="col">Kategorie</th>
|
||||
<th scope="col">Erstellt von</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{mockData.map((item, i) => (
|
||||
<Row key={`${item.ticketID}-${i}`} ticketID={item.ticketID} ticketname={item.ticketname}
|
||||
username={item.username}
|
||||
status={item.status} priority={item.priority} category={item.category}/>
|
||||
))}
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
2
src/components/UserTable/index.ts
Normal file
2
src/components/UserTable/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from './UserTable';
|
||||
export * from "./Row"
|
||||
4
src/components/cn/cn.tsx
Normal file
4
src/components/cn/cn.tsx
Normal file
@@ -0,0 +1,4 @@
|
||||
import {ClassNameValue, twMerge} from "tailwind-merge";
|
||||
import {clsx} from "clsx";
|
||||
|
||||
export const cn = (...input: ClassNameValue[]) => twMerge(clsx(input));
|
||||
1
src/components/cn/index.ts
Normal file
1
src/components/cn/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from "./cn"
|
||||
0
src/components/cn/interfaces.ts
Normal file
0
src/components/cn/interfaces.ts
Normal file
7
src/components/getUser/getUser.ts
Normal file
7
src/components/getUser/getUser.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
'use server'
|
||||
import {cookies} from "next/headers";
|
||||
|
||||
export async function getUser() {
|
||||
const cookieStore = await cookies()
|
||||
return cookieStore.get("user")?.value || undefined;
|
||||
}
|
||||
1
src/components/getUser/index.ts
Normal file
1
src/components/getUser/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from "./getUser"
|
||||
2
src/components/isLoggedIn/index.ts
Normal file
2
src/components/isLoggedIn/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from "./isLoggedIn"
|
||||
export * from "./isLoggedInServer"
|
||||
26
src/components/isLoggedIn/isLoggedIn.ts
Normal file
26
src/components/isLoggedIn/isLoggedIn.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
'use client'
|
||||
|
||||
import {useEffect, useState} from "react";
|
||||
import {usePathname} from "next/navigation";
|
||||
import {isLoggedInServer} from "@/components/isLoggedIn/isLoggedInServer";
|
||||
|
||||
/**
|
||||
* checks if the user is logged in
|
||||
*
|
||||
* Updates every time a new Path is evaluated
|
||||
*/
|
||||
export function useLoggedState() {
|
||||
const [isLoggedinVal, setIsLoggedIn] = useState<boolean>(false);
|
||||
|
||||
const path = usePathname()
|
||||
|
||||
useEffect(()=> {
|
||||
const asyncReq = async () => {
|
||||
const response = await isLoggedInServer()
|
||||
setIsLoggedIn(response)
|
||||
}
|
||||
asyncReq()
|
||||
},[path])
|
||||
|
||||
return isLoggedinVal
|
||||
}
|
||||
11
src/components/isLoggedIn/isLoggedInServer.ts
Normal file
11
src/components/isLoggedIn/isLoggedInServer.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
'use server'
|
||||
import {cookies} from "next/headers";
|
||||
|
||||
export async function isLoggedInServer() {
|
||||
'use server'
|
||||
const cookieStore = await cookies()
|
||||
const token = cookieStore.get('token');
|
||||
const user = cookieStore.get("user");
|
||||
return !!(user && token);
|
||||
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
17
src/components/svg/logout.tsx
Normal file
17
src/components/svg/logout.tsx
Normal file
@@ -0,0 +1,17 @@
|
||||
import * as React from "react"
|
||||
import {SVGProps} from "react"
|
||||
|
||||
const Logout = (props: SVGProps<SVGSVGElement>) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width={24}
|
||||
height={24}
|
||||
fill="#FFF"
|
||||
viewBox="0 -960 960 960"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h280v80H200v560h280v80H200Zm440-160-55-58 102-102H360v-80h327L585-622l55-58 200 200-200 200Z"/>
|
||||
</svg>
|
||||
)
|
||||
export default Logout
|
||||
17
src/components/svg/notifications/bell.tsx
Normal file
17
src/components/svg/notifications/bell.tsx
Normal file
@@ -0,0 +1,17 @@
|
||||
import * as React from "react"
|
||||
import {SVGProps} from "react"
|
||||
|
||||
const Bell = (props: SVGProps<SVGSVGElement>) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width={24}
|
||||
height={24}
|
||||
fill="#FFF"
|
||||
viewBox="0 -960 960 960"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M180-204.62v-59.99h72.31v-298.47q0-80.69 49.81-142.69 49.8-62 127.88-79.31V-810q0-20.83 14.57-35.42Q459.14-860 479.95-860q20.82 0 35.43 14.58Q530-830.83 530-810v24.92q78.08 17.31 127.88 79.31 49.81 62 49.81 142.69v298.47H780v59.99H180ZM479.93-92.31q-29.85 0-51.04-21.24-21.2-21.24-21.2-51.07h144.62q0 29.93-21.26 51.12-21.26 21.19-51.12 21.19Z"/>
|
||||
</svg>
|
||||
)
|
||||
export default Bell
|
||||
1
src/components/svg/notifications/index.ts
Normal file
1
src/components/svg/notifications/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from "./bell"
|
||||
@@ -1,8 +1,9 @@
|
||||
import {NextRequest, NextResponse} from "next/server";
|
||||
import {verifySession} from "@/components/DAL/dal";
|
||||
|
||||
export default async function proxy(req: NextRequest) {
|
||||
|
||||
const auth_is_valid = true // (await verifySession()).isAuth;
|
||||
const auth_is_valid = (await verifySession()).isAuth;
|
||||
const route_is_login = req.nextUrl.pathname === "/login"
|
||||
|
||||
if (route_is_login && auth_is_valid) { // Redirect User to Home if Login already acquired
|
||||
|
||||
Reference in New Issue
Block a user