mirror of
https://github.com/Since-3/Kuma.git
synced 2026-10-12 20:41:16 +00:00
added in course creation timeFrom till timeTo
This commit is contained in:
parent
65cc91b3c0
commit
dd433be2f8
10 changed files with 95 additions and 282 deletions
246
package-lock.json
generated
246
package-lock.json
generated
|
|
@ -3621,61 +3621,6 @@
|
|||
"integrity": "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@supabase/auth-js": {
|
||||
"version": "2.89.0",
|
||||
"resolved": "https://registry.npmjs.org/@supabase/auth-js/-/auth-js-2.89.0.tgz",
|
||||
"integrity": "sha512-wiWZdz8WMad8LQdJMWYDZ2SJtZP5MwMqzQq3ehtW2ngiI3UTgbKiFrvMUUS3KADiVlk4LiGfODB2mrYx7w2f8w==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"tslib": "2.8.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@supabase/functions-js": {
|
||||
"version": "2.89.0",
|
||||
"resolved": "https://registry.npmjs.org/@supabase/functions-js/-/functions-js-2.89.0.tgz",
|
||||
"integrity": "sha512-XEueaC5gMe5NufNYfBh9kPwJlP5M2f+Ogr8rvhmRDAZNHgY6mI35RCkYDijd92pMcNM7g8pUUJov93UGUnqfyw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"tslib": "2.8.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@supabase/postgrest-js": {
|
||||
"version": "2.89.0",
|
||||
"resolved": "https://registry.npmjs.org/@supabase/postgrest-js/-/postgrest-js-2.89.0.tgz",
|
||||
"integrity": "sha512-/b0fKrxV9i7RNOEXMno/I1862RsYhuUo+Q6m6z3ar1f4ulTMXnDfv0y4YYxK2POcgrOXQOgKYQx1eArybyNvtg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"tslib": "2.8.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@supabase/realtime-js": {
|
||||
"version": "2.89.0",
|
||||
"resolved": "https://registry.npmjs.org/@supabase/realtime-js/-/realtime-js-2.89.0.tgz",
|
||||
"integrity": "sha512-aMOvfDb2a52u6PX6jrrjvACHXGV3zsOlWRzZsTIOAJa0hOVvRp01AwC1+nLTGUzxzezejrYeCX+KnnM1xHdl+w==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/phoenix": "^1.6.6",
|
||||
"@types/ws": "^8.18.1",
|
||||
"tslib": "2.8.1",
|
||||
"ws": "^8.18.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@supabase/ssr": {
|
||||
"version": "0.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@supabase/ssr/-/ssr-0.7.0.tgz",
|
||||
|
|
@ -3688,37 +3633,6 @@
|
|||
"@supabase/supabase-js": "^2.43.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@supabase/storage-js": {
|
||||
"version": "2.89.0",
|
||||
"resolved": "https://registry.npmjs.org/@supabase/storage-js/-/storage-js-2.89.0.tgz",
|
||||
"integrity": "sha512-6zKcXofk/M/4Eato7iqpRh+B+vnxeiTumCIP+Tz26xEqIiywzD9JxHq+udRrDuv6hXE+pmetvJd8n5wcf4MFRQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"iceberg-js": "^0.8.1",
|
||||
"tslib": "2.8.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@supabase/supabase-js": {
|
||||
"version": "2.89.0",
|
||||
"resolved": "https://registry.npmjs.org/@supabase/supabase-js/-/supabase-js-2.89.0.tgz",
|
||||
"integrity": "sha512-KlaRwSfFA0fD73PYVMHj5/iXFtQGCcX7PSx0FdQwYEEw9b2wqM7GxadY+5YwcmuEhalmjFB/YvqaoNVF+sWUlg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@supabase/auth-js": "2.89.0",
|
||||
"@supabase/functions-js": "2.89.0",
|
||||
"@supabase/postgrest-js": "2.89.0",
|
||||
"@supabase/realtime-js": "2.89.0",
|
||||
"@supabase/storage-js": "2.89.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/helpers": {
|
||||
"version": "0.5.15",
|
||||
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz",
|
||||
|
|
@ -3999,46 +3913,6 @@
|
|||
"tailwindcss": "4.1.16"
|
||||
}
|
||||
},
|
||||
"node_modules/@testing-library/dom": {
|
||||
"version": "10.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.1.tgz",
|
||||
"integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "^7.10.4",
|
||||
"@babel/runtime": "^7.12.5",
|
||||
"@types/aria-query": "^5.0.1",
|
||||
"aria-query": "5.3.0",
|
||||
"dom-accessibility-api": "^0.5.9",
|
||||
"lz-string": "^1.5.0",
|
||||
"picocolors": "1.1.1",
|
||||
"pretty-format": "^27.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@testing-library/dom/node_modules/aria-query": {
|
||||
"version": "5.3.0",
|
||||
"resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz",
|
||||
"integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"dequal": "^2.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@testing-library/dom/node_modules/dom-accessibility-api": {
|
||||
"version": "0.5.16",
|
||||
"resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz",
|
||||
"integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@testing-library/jest-dom": {
|
||||
"version": "6.9.1",
|
||||
"resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.9.1.tgz",
|
||||
|
|
@ -4559,14 +4433,6 @@
|
|||
"tslib": "^2.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/aria-query": {
|
||||
"version": "5.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz",
|
||||
"integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@types/babel__core": {
|
||||
"version": "7.20.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
|
||||
|
|
@ -4677,22 +4543,17 @@
|
|||
"version": "20.19.24",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.24.tgz",
|
||||
"integrity": "sha512-FE5u0ezmi6y9OZEzlJfg37mqqf6ZDSF2V/NLjUyGrR9uTZ7Sb9F7bLNZ03S4XVUNRWGA7Ck4c1kK+YnuWjl+DA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"undici-types": "~6.21.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/phoenix": {
|
||||
"version": "1.6.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/phoenix/-/phoenix-1.6.7.tgz",
|
||||
"integrity": "sha512-oN9ive//QSBkf19rfDv45M7eZPi0eEXylht2OLEXicu5b4KoQ1OzXIw+xDSGWxSxe1JmepRR/ZH283vsu518/Q==",
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@types/react": {
|
||||
"version": "19.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.2.tgz",
|
||||
"integrity": "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"csstype": "^3.0.2"
|
||||
|
|
@ -4702,6 +4563,7 @@
|
|||
"version": "19.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.2.tgz",
|
||||
"integrity": "sha512-9KQPoO6mZCi7jcIStSnlOWn2nEF3mNmyr3rIAsGnAbQKYbRLyqmeSc39EVgtxXVia+LMT8j3knZLAZAh+xLmrw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@types/react": "^19.2.0"
|
||||
|
|
@ -4713,16 +4575,6 @@
|
|||
"integrity": "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/ws": {
|
||||
"version": "8.18.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz",
|
||||
"integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||
"version": "8.46.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.46.2.tgz",
|
||||
|
|
@ -6223,6 +6075,7 @@
|
|||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
|
||||
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/damerau-levenshtein": {
|
||||
|
|
@ -6383,17 +6236,6 @@
|
|||
"integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/dequal": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
|
||||
"integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/destr": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/destr/-/destr-2.0.5.tgz",
|
||||
|
|
@ -7854,16 +7696,6 @@
|
|||
"url": "https://github.com/sponsors/typicode"
|
||||
}
|
||||
},
|
||||
"node_modules/iceberg-js": {
|
||||
"version": "0.8.1",
|
||||
"resolved": "https://registry.npmjs.org/iceberg-js/-/iceberg-js-0.8.1.tgz",
|
||||
"integrity": "sha512-1dhVQZXhcHje7798IVM+xoo/1ZdVfzOMIc8/rgVSijRK38EDqOJoGula9N/8ZI5RD8QTxNQtK/Gozpr+qUqRRA==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/iconv-lite": {
|
||||
"version": "0.6.3",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
|
||||
|
|
@ -8426,9 +8258,9 @@
|
|||
"license": "MIT"
|
||||
},
|
||||
"node_modules/js-yaml": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
|
||||
"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
|
||||
"integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
|
|
@ -8979,17 +8811,6 @@
|
|||
"react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/lz-string": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz",
|
||||
"integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"lz-string": "bin/bin.js"
|
||||
}
|
||||
},
|
||||
"node_modules/magic-string": {
|
||||
"version": "0.30.21",
|
||||
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
|
||||
|
|
@ -9719,55 +9540,6 @@
|
|||
"url": "https://github.com/prettier/prettier?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/pretty-format": {
|
||||
"version": "27.5.1",
|
||||
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz",
|
||||
"integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"ansi-regex": "^5.0.1",
|
||||
"ansi-styles": "^5.0.0",
|
||||
"react-is": "^17.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/pretty-format/node_modules/ansi-regex": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
|
||||
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/pretty-format/node_modules/ansi-styles": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
|
||||
"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/pretty-format/node_modules/react-is": {
|
||||
"version": "17.0.2",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
|
||||
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/prisma": {
|
||||
"version": "6.19.0",
|
||||
"resolved": "https://registry.npmjs.org/prisma/-/prisma-6.19.0.tgz",
|
||||
|
|
@ -11339,7 +11111,7 @@
|
|||
"version": "5.9.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
|
||||
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
||||
"devOptional": true,
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
|
|
@ -11402,6 +11174,7 @@
|
|||
"version": "6.21.0",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
|
||||
"integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/unrs-resolver": {
|
||||
|
|
@ -11943,6 +11716,7 @@
|
|||
"version": "8.18.3",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz",
|
||||
"integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
Warnings:
|
||||
|
||||
- You are about to drop the column `time` on the `Course` table. All the data in the column will be lost.
|
||||
- Added the required column `timeFrom` to the `Course` table without a default value. This is not possible if the table is not empty.
|
||||
- Added the required column `timeTo` to the `Course` table without a default value. This is not possible if the table is not empty.
|
||||
|
||||
*/
|
||||
-- AlterTable
|
||||
ALTER TABLE "Course" DROP COLUMN "time",
|
||||
ADD COLUMN "timeFrom" TEXT NOT NULL,
|
||||
ADD COLUMN "timeTo" TEXT NOT NULL;
|
||||
|
|
@ -97,7 +97,8 @@ model Course {
|
|||
name String
|
||||
sport String
|
||||
date DateTime
|
||||
time String
|
||||
timeFrom String // Anfangszeit
|
||||
timeTo String // Endzeit
|
||||
trainers String[] // Array of trainer IDs
|
||||
room String
|
||||
description String // Rich text HTML content
|
||||
|
|
|
|||
|
|
@ -37,29 +37,42 @@ export type ManagerData = {
|
|||
|
||||
export type AuthUserData = UserData | ManagerData;
|
||||
|
||||
// Cache entry type
|
||||
type CacheEntry = {
|
||||
data: AuthUserData;
|
||||
timestamp: number;
|
||||
};
|
||||
|
||||
// Simple in-memory cache with timestamp
|
||||
const userDataCache = new Map<string, CacheEntry>();
|
||||
const CACHE_TTL = 5 * 60 * 1000; // 5 minutes
|
||||
// Note: We don't use in-memory caching because this app runs on Vercel (serverless)
|
||||
// Serverless functions are stateless - in-memory cache would be:
|
||||
// 1. Inconsistent across Lambda instances
|
||||
// 2. Lost on cold starts
|
||||
// 3. Not shared between requests
|
||||
// Instead, we rely on React's cache() for per-request deduplication only.
|
||||
|
||||
let userDataCallCount = 0;
|
||||
let supabaseCallCount = 0;
|
||||
|
||||
// Cache Supabase user (per request)
|
||||
// Get authenticated user from Supabase
|
||||
// Uses React's cache() for per-request deduplication
|
||||
// No cross-request caching due to serverless architecture
|
||||
export const getUser = cache(async () => {
|
||||
supabaseCallCount++;
|
||||
console.log(`🔐 [AUTH] getUser called (count: ${supabaseCallCount})`);
|
||||
|
||||
const supabase = await createClient();
|
||||
|
||||
// Validate with Auth server (secure - always authenticates against Supabase)
|
||||
const {
|
||||
data: { user },
|
||||
} = await supabase.auth.getUser();
|
||||
console.log("🔐 [AUTH] getUser called - User:", user?.email || "none");
|
||||
|
||||
if (user) {
|
||||
console.log("🔐 [AUTH] User authenticated:", user.email);
|
||||
} else {
|
||||
console.log("🔐 [AUTH] No authenticated user");
|
||||
}
|
||||
|
||||
return user;
|
||||
});
|
||||
|
||||
// Cache user data from database with time-based cache
|
||||
// Get user data from database
|
||||
// Uses React's cache() for per-request deduplication
|
||||
// No cross-request caching due to serverless architecture
|
||||
export const getUserData = cache(async (): Promise<AuthUserData | null> => {
|
||||
userDataCallCount++;
|
||||
console.log(`📊 [DB] getUserData called (count: ${userDataCallCount})`);
|
||||
|
|
@ -67,18 +80,7 @@ export const getUserData = cache(async (): Promise<AuthUserData | null> => {
|
|||
const user = await getUser();
|
||||
if (!user) return null;
|
||||
|
||||
// Check in-memory cache
|
||||
const cached = userDataCache.get(user.id);
|
||||
const now = Date.now();
|
||||
|
||||
if (cached && now - cached.timestamp < CACHE_TTL) {
|
||||
console.log(
|
||||
`⚡ [CACHE] Using cached data (${Math.round((now - cached.timestamp) / 1000)}s old)`
|
||||
);
|
||||
return cached.data;
|
||||
}
|
||||
|
||||
console.log("🗄️ [DB] Fetching user data from Prisma for:", user.email);
|
||||
console.log("🗄️ [DB] Fetching user data from database for:", user.email);
|
||||
|
||||
// Try to find in User table first
|
||||
const userData = await prisma.user.findUnique({
|
||||
|
|
@ -101,7 +103,6 @@ export const getUserData = cache(async (): Promise<AuthUserData | null> => {
|
|||
if (userData) {
|
||||
console.log("✅ [DB] User data fetched:", userData.name);
|
||||
const userWithRole: UserData = { ...userData, role: "user" };
|
||||
userDataCache.set(user.id, { data: userWithRole, timestamp: now });
|
||||
return userWithRole;
|
||||
}
|
||||
|
||||
|
|
@ -133,7 +134,6 @@ export const getUserData = cache(async (): Promise<AuthUserData | null> => {
|
|||
`${managerData.firstName} ${managerData.lastName}`
|
||||
);
|
||||
const managerWithRole: ManagerData = { ...managerData, role: "manager" };
|
||||
userDataCache.set(user.id, { data: managerWithRole, timestamp: now });
|
||||
return managerWithRole;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -64,7 +64,8 @@ export async function createCourse(data: CourseFormData, status: "draft" | "publ
|
|||
name: validatedData.name,
|
||||
sport: validatedData.sport,
|
||||
date: new Date(validatedData.date), // String zu Date konvertieren
|
||||
time: validatedData.time,
|
||||
timeFrom: validatedData.timeFrom,
|
||||
timeTo: validatedData.timeTo,
|
||||
trainers: validatedData.trainers,
|
||||
room: validatedData.room,
|
||||
description: validatedData.description,
|
||||
|
|
@ -334,7 +335,8 @@ export async function updateCourse(
|
|||
name: validatedData.name,
|
||||
sport: validatedData.sport,
|
||||
date: new Date(validatedData.date),
|
||||
time: validatedData.time,
|
||||
timeFrom: validatedData.timeFrom,
|
||||
timeTo: validatedData.timeTo,
|
||||
trainers: validatedData.trainers,
|
||||
room: validatedData.room,
|
||||
description: validatedData.description,
|
||||
|
|
|
|||
|
|
@ -28,8 +28,11 @@ export const courseSchema = z
|
|||
// Kursdatum als String im Format YYYY-MM-DD
|
||||
date: z.string().min(1, "Datum ist erforderlich"),
|
||||
|
||||
// Kurszeit als String im Format HH:MM
|
||||
time: z.string().min(1, "Uhrzeit ist erforderlich"),
|
||||
// Anfangszeit als String im Format HH:MM
|
||||
timeFrom: z.string().min(1, "Anfangszeit ist erforderlich"),
|
||||
|
||||
// Endzeit als String im Format HH:MM
|
||||
timeTo: z.string().min(1, "Endzeit ist erforderlich"),
|
||||
|
||||
// Array von Trainer-IDs (mindestens ein Trainer erforderlich)
|
||||
trainers: z.array(z.string()).min(1, "Mindestens ein Trainer muss ausgewählt werden"),
|
||||
|
|
|
|||
|
|
@ -3,7 +3,8 @@ export type Course = {
|
|||
name: string;
|
||||
sport: string;
|
||||
date: Date;
|
||||
time: string;
|
||||
timeFrom: string;
|
||||
timeTo: string;
|
||||
trainers: string[];
|
||||
room: string;
|
||||
description: string;
|
||||
|
|
|
|||
|
|
@ -14,7 +14,8 @@ import { Pen, Trash2 } from "lucide-react";
|
|||
interface CourseListItemProps {
|
||||
courseName: string; // Name des Kurses
|
||||
room: string; // Raum, in dem der Kurs stattfindet
|
||||
time: string; // Uhrzeit des Kurses (z.B. "14:00")
|
||||
timeFrom: string; // Uhrzeit am Start des Kurses
|
||||
timeTo: string; // Uhrzeit am Ende des Kurses
|
||||
currentParticipants: number; // Aktuelle Anzahl der Teilnehmer
|
||||
maxParticipants: number; // Maximale Anzahl der Teilnehmer
|
||||
trainerName: string; // Name(n) des/der Trainer
|
||||
|
|
@ -32,7 +33,8 @@ interface CourseListItemProps {
|
|||
const CourseListItem: React.FC<CourseListItemProps> = ({
|
||||
courseName,
|
||||
room,
|
||||
time,
|
||||
timeFrom,
|
||||
timeTo,
|
||||
currentParticipants,
|
||||
maxParticipants,
|
||||
trainerName,
|
||||
|
|
@ -63,7 +65,7 @@ const CourseListItem: React.FC<CourseListItemProps> = ({
|
|||
<div>
|
||||
<h2 className="text-xl font-semibold text-gray-900">{courseName}</h2>
|
||||
<p className="text-gray-500">
|
||||
{room} • {time}
|
||||
{room} • {timeFrom} - {timeTo}
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
|
|
|
|||
|
|
@ -62,7 +62,8 @@ const CourseCreateView = ({
|
|||
const router = useRouter();
|
||||
const [courseName, setCourseName] = useState("");
|
||||
const [courseDate, setCourseDate] = useState("");
|
||||
const [courseTime, setCourseTime] = useState("");
|
||||
const [timeFrom, setTimeFrom] = useState("");
|
||||
const [timeTo, setTimeTo] = useState("");
|
||||
const [selectedSport, setSelectedSport] = useState("");
|
||||
const [selectedTrainers, setSelectedTrainers] = useState<string[]>([]);
|
||||
const [selectedRoom, setSelectedRoom] = useState("");
|
||||
|
|
@ -112,7 +113,8 @@ const CourseCreateView = ({
|
|||
setCourseDate(formattedDate);
|
||||
}
|
||||
|
||||
setCourseTime(initialData.time || "");
|
||||
setTimeFrom(initialData.timeFrom || "");
|
||||
setTimeTo(initialData.timeTo || "");
|
||||
setSelectedTrainers(initialData.trainers || []);
|
||||
setSelectedRoom(initialData.room || "");
|
||||
setDescription(initialData.description || "");
|
||||
|
|
@ -129,7 +131,8 @@ const CourseCreateView = ({
|
|||
if (!courseName.trim()) newErrors.name = "Kursname ist erforderlich";
|
||||
if (!selectedSport) newErrors.sport = "Sportart ist erforderlich";
|
||||
if (!courseDate) newErrors.date = "Datum ist erforderlich";
|
||||
if (!courseTime) newErrors.time = "Uhrzeit ist erforderlich";
|
||||
if (!timeFrom) newErrors.timeFrom = "Anfangszeit ist erforderlich";
|
||||
if (!timeTo) newErrors.timeTo = "Endzeit ist erforderlich";
|
||||
if (selectedTrainers.length === 0)
|
||||
newErrors.trainers = "Mindestens ein Trainer muss ausgewählt werden";
|
||||
if (!selectedRoom) newErrors.room = "Raum ist erforderlich";
|
||||
|
|
@ -167,7 +170,8 @@ const CourseCreateView = ({
|
|||
name: courseName,
|
||||
sport: selectedSport,
|
||||
date: courseDate,
|
||||
time: courseTime,
|
||||
timeFrom: timeFrom,
|
||||
timeTo: timeTo,
|
||||
trainers: selectedTrainers,
|
||||
room: selectedRoom,
|
||||
description,
|
||||
|
|
@ -253,13 +257,25 @@ const CourseCreateView = ({
|
|||
<div>
|
||||
<InputComponent
|
||||
isLabel
|
||||
label="Uhrzeit"
|
||||
label="Uhrzeit von"
|
||||
type="time"
|
||||
id="course-create-time"
|
||||
value={courseTime}
|
||||
onChange={(e) => setCourseTime(e.target.value)}
|
||||
id="course-create-time-from"
|
||||
value={timeFrom}
|
||||
onChange={(e) => setTimeFrom(e.target.value)}
|
||||
/>
|
||||
{errors.time && <p className="text-red-500 text-sm mt-1">{errors.time}</p>}
|
||||
{errors.timeFrom && <p className="text-red-500 text-sm mt-1">{errors.timeFrom}</p>}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<InputComponent
|
||||
isLabel
|
||||
label="Uhrzeit bis"
|
||||
type="time"
|
||||
id="course-create-time-to"
|
||||
value={timeTo}
|
||||
onChange={(e) => setTimeTo(e.target.value)}
|
||||
/>
|
||||
{errors.timeTo && <p className="text-red-500 text-sm mt-1">{errors.timeTo}</p>}
|
||||
</div>
|
||||
|
||||
<MultiSelectDropdown
|
||||
|
|
|
|||
|
|
@ -14,7 +14,8 @@ type Course = {
|
|||
name: string;
|
||||
sport: string;
|
||||
date: Date;
|
||||
time: string;
|
||||
timeFrom: string;
|
||||
timeTo: string;
|
||||
trainers: string[];
|
||||
room: string;
|
||||
description: string;
|
||||
|
|
@ -460,7 +461,8 @@ const CourseListView = () => {
|
|||
key={course.id}
|
||||
courseName={course.name}
|
||||
room={roomsMap[course.room] || course.room}
|
||||
time={course.time}
|
||||
timeFrom={course.timeFrom}
|
||||
timeTo={course.timeTo}
|
||||
currentParticipants={0} // TODO: Implement participant tracking
|
||||
maxParticipants={course.maxParticipants}
|
||||
trainerName={getTrainerName(course.trainers)}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue