Begin consumption of API

This commit is contained in:
2024-07-24 01:25:12 +02:00
parent b40ae7d701
commit 1b62b890b9
15 changed files with 1023 additions and 526 deletions
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -5,7 +5,7 @@
<link rel="icon" type="image/svg+xml" href="/phpCourse/exam/dist/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + React + TS</title>
<script type="module" crossorigin src="/phpCourse/exam/dist/assets/index-CCI8Q-vE.js"></script>
<script type="module" crossorigin src="/phpCourse/exam/dist/assets/index-Bv9g1hLV.js"></script>
</head>
<body>
<div id="root"></div>
+1
View File
@@ -0,0 +1 @@
v18
+7 -1
View File
@@ -13,12 +13,18 @@
"@emotion/react": "^11.13.0",
"@emotion/styled": "^11.13.0",
"@mui/material": "^5.16.4",
"@tanstack/react-query": "^5.51.11",
"@tanstack/react-router": "^1.45.8",
"@types/node": "^20.14.12",
"react": "^18.3.1",
"react-dom": "^18.3.1"
"react-dom": "^18.3.1",
"zustand": "^4.5.4"
},
"devDependencies": {
"@redux-devtools/extension": "^3.3.0",
"@tanstack/eslint-plugin-query": "^5.51.12",
"@tanstack/router-devtools": "^1.45.8",
"@tanstack/react-query-devtools": "^5.51.11",
"@tanstack/router-plugin": "^1.45.8",
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
+201 -8
View File
@@ -17,22 +17,40 @@ importers:
'@mui/material':
specifier: ^5.16.4
version: 5.16.4(@emotion/react@11.13.0(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@tanstack/react-query':
specifier: ^5.51.11
version: 5.51.11(react@18.3.1)
'@tanstack/react-query-devtools':
specifier: ^5.51.11
version: 5.51.11(@tanstack/react-query@5.51.11(react@18.3.1))(react@18.3.1)
'@tanstack/react-router':
specifier: ^1.45.8
version: 1.45.8(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@types/node':
specifier: ^20.14.12
version: 20.14.12
react:
specifier: ^18.3.1
version: 18.3.1
react-dom:
specifier: ^18.3.1
version: 18.3.1(react@18.3.1)
zustand:
specifier: ^4.5.4
version: 4.5.4(@types/react@18.3.3)(react@18.3.1)
devDependencies:
'@redux-devtools/extension':
specifier: ^3.3.0
version: 3.3.0(redux@5.0.1)
'@tanstack/eslint-plugin-query':
specifier: ^5.51.12
version: 5.51.12(eslint@8.57.0)(typescript@5.5.3)
'@tanstack/router-devtools':
specifier: ^1.45.8
version: 1.45.8(@tanstack/react-router@1.45.8(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(csstype@3.1.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@tanstack/router-plugin':
specifier: ^1.45.8
version: 1.45.8(vite@5.3.4)
version: 1.45.8(vite@5.3.4(@types/node@20.14.12))
'@types/react':
specifier: ^18.3.3
version: 18.3.3
@@ -47,7 +65,7 @@ importers:
version: 7.16.1(eslint@8.57.0)(typescript@5.5.3)
'@vitejs/plugin-react':
specifier: ^4.3.1
version: 4.3.1(vite@5.3.4)
version: 4.3.1(vite@5.3.4(@types/node@20.14.12))
eslint:
specifier: ^8.57.0
version: 8.57.0
@@ -68,7 +86,7 @@ importers:
version: 5.5.3
vite:
specifier: ^5.3.4
version: 5.3.4
version: 5.3.4(@types/node@20.14.12)
packages:
@@ -528,6 +546,11 @@ packages:
'@popperjs/core@2.11.8':
resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==}
'@redux-devtools/extension@3.3.0':
resolution: {integrity: sha512-X34S/rC8S/M1BIrkYD1mJ5f8vlH0BDqxXrs96cvxSBo4FhMdbhU+GUGsmNYov1xjSyLMHgo8NYrUG8bNX7525g==}
peerDependencies:
redux: ^3.1.0 || ^4.0.0 || ^5.0.0
'@rollup/rollup-android-arm-eabi@4.18.1':
resolution: {integrity: sha512-lncuC4aHicncmbORnx+dUaAgzee9cm/PbIqgWz1PpXuwc+sa1Ct83tnqUDy/GFKleLiN7ZIeytM6KJ4cAn1SxA==}
cpu: [arm]
@@ -608,10 +631,32 @@ packages:
cpu: [x64]
os: [win32]
'@tanstack/eslint-plugin-query@5.51.12':
resolution: {integrity: sha512-vzUXXIVzDP2c6wVSJ+1imPGaKQ2ILuWnta64FJc/JnQ5WunfO17bQJSk6uKDbzTQG/YKgPYBMG3C9qFA4b7Ayg==}
peerDependencies:
eslint: ^8 || ^9
'@tanstack/history@1.45.3':
resolution: {integrity: sha512-n4XXInV9irIq0obRvINIkESkGk280Q+xkIIbswmM0z9nAu2wsIRZNvlmPrtYh6bgNWtItOWWoihFUjLTW8g6Jg==}
engines: {node: '>=12'}
'@tanstack/query-core@5.51.9':
resolution: {integrity: sha512-HsAwaY5J19MD18ykZDS3aVVh+bAt0i7m6uQlFC2b77DLV9djo+xEN7MWQAQQTR8IM+7r/zbozTQ7P0xr0bHuew==}
'@tanstack/query-devtools@5.51.9':
resolution: {integrity: sha512-FQqJynaEDuwQxoFLP3/i10HQwNYh4wxgs0NeSoL24BLWvpUdstgHqUm2zgwRov8Tmh5kjndPIWaXenwl0D47EA==}
'@tanstack/react-query-devtools@5.51.11':
resolution: {integrity: sha512-8nQRbhdtvl/J9bO+bk/kPQesCOtDgk+oI4AmZJDnkf5OfKTJL3J4tTe+fhuXph7KP4DUOS+ge9o9TGt0OgWFHw==}
peerDependencies:
'@tanstack/react-query': ^5.51.11
react: ^18 || ^19
'@tanstack/react-query@5.51.11':
resolution: {integrity: sha512-4Kq2x0XpDlpvSnaLG+8pHNH60zEc3mBvb3B2tOMDjcPCi/o+Du3p/9qpPLwJOTliVxxPJAP27fuIhLrsRdCr7A==}
peerDependencies:
react: ^18.0.0
'@tanstack/react-router@1.45.8':
resolution: {integrity: sha512-hLJOKDK5lGHteoMjpF6COQrlhsl4C6GyBCzmSJHFcoh26GBa7tv/94li0H1a3deJpzMNpSvmSXrQDpxj9h9bNA==}
engines: {node: '>=12'}
@@ -670,6 +715,9 @@ packages:
'@types/estree@1.0.5':
resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==}
'@types/node@20.14.12':
resolution: {integrity: sha512-r7wNXakLeSsGT0H1AU863vS2wa5wBOK4bWMjZz2wj+8nBx+m5PeIn0k8AloSLpRuiwdRQZwarZqHE4FNArPuJQ==}
'@types/parse-json@4.0.2':
resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==}
@@ -710,6 +758,10 @@ packages:
resolution: {integrity: sha512-nYpyv6ALte18gbMz323RM+vpFpTjfNdyakbf3nsLvF43uF9KeNC289SUEW3QLZ1xPtyINJ1dIsZOuWuSRIWygw==}
engines: {node: ^18.18.0 || >=20.0.0}
'@typescript-eslint/scope-manager@8.0.0-alpha.30':
resolution: {integrity: sha512-FGW/iPWGyPFamAVZ60oCAthMqQrqafUGebF8UKuq/ha+e9SVG6YhJoRzurlQXOVf8dHfOhJ0ADMXyFnMc53clg==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@typescript-eslint/type-utils@7.16.1':
resolution: {integrity: sha512-rbu/H2MWXN4SkjIIyWcmYBjlp55VT+1G3duFOIukTNFxr9PI35pLc2ydwAfejCEitCv4uztA07q0QWanOHC7dA==}
engines: {node: ^18.18.0 || >=20.0.0}
@@ -724,6 +776,10 @@ packages:
resolution: {integrity: sha512-AQn9XqCzUXd4bAVEsAXM/Izk11Wx2u4H3BAfQVhSfzfDOm/wAON9nP7J5rpkCxts7E5TELmN845xTUCQrD1xIQ==}
engines: {node: ^18.18.0 || >=20.0.0}
'@typescript-eslint/types@8.0.0-alpha.30':
resolution: {integrity: sha512-4WzLlw27SO9pK9UFj/Hu7WGo8WveT0SEiIpFVsV2WwtQmLps6kouwtVCB8GJPZKJyurhZhcqCoQVQFmpv441Vg==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@typescript-eslint/typescript-estree@7.16.1':
resolution: {integrity: sha512-0vFPk8tMjj6apaAZ1HlwM8w7jbghC8jc1aRNJG5vN8Ym5miyhTQGMqU++kuBFDNKe9NcPeZ6x0zfSzV8xC1UlQ==}
engines: {node: ^18.18.0 || >=20.0.0}
@@ -733,16 +789,35 @@ packages:
typescript:
optional: true
'@typescript-eslint/typescript-estree@8.0.0-alpha.30':
resolution: {integrity: sha512-WSXbc9ZcXI+7yC+6q95u77i8FXz6HOLsw3ST+vMUlFy1lFbXyFL/3e6HDKQCm2Clt0krnoCPiTGvIn+GkYPn4Q==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
typescript: '*'
peerDependenciesMeta:
typescript:
optional: true
'@typescript-eslint/utils@7.16.1':
resolution: {integrity: sha512-WrFM8nzCowV0he0RlkotGDujx78xudsxnGMBHI88l5J8wEhED6yBwaSLP99ygfrzAjsQvcYQ94quDwI0d7E1fA==}
engines: {node: ^18.18.0 || >=20.0.0}
peerDependencies:
eslint: ^8.56.0
'@typescript-eslint/utils@8.0.0-alpha.30':
resolution: {integrity: sha512-rfhqfLqFyXhHNDwMnHiVGxl/Z2q/3guQ1jLlGQ0hi9Rb7inmwz42crM+NnLPR+2vEnwyw1P/g7fnQgQ3qvFx4g==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
eslint: ^8.57.0 || ^9.0.0
'@typescript-eslint/visitor-keys@7.16.1':
resolution: {integrity: sha512-Qlzzx4sE4u3FsHTPQAAQFJFNOuqtuY0LFrZHwQ8IHK705XxBiWOFkfKRWu6niB7hwfgnwIpO4jTC75ozW1PHWg==}
engines: {node: ^18.18.0 || >=20.0.0}
'@typescript-eslint/visitor-keys@8.0.0-alpha.30':
resolution: {integrity: sha512-XZuNurZxBqmr6ZIRIwWFq7j5RZd6ZlkId/HZEWyfciK+CWoyOxSF9Pv2VXH9Rlu2ZG2PfbhLz2Veszl4Pfn7yA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@ungap/structured-clone@1.2.0':
resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==}
@@ -1067,6 +1142,9 @@ packages:
resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==}
engines: {node: '>= 4'}
immutable@4.3.7:
resolution: {integrity: sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw==}
import-fresh@3.3.0:
resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==}
engines: {node: '>=6'}
@@ -1316,6 +1394,9 @@ packages:
resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
engines: {node: '>=8.10.0'}
redux@5.0.1:
resolution: {integrity: sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==}
regenerator-runtime@0.14.1:
resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==}
@@ -1435,6 +1516,9 @@ packages:
engines: {node: '>=14.17'}
hasBin: true
undici-types@5.26.5:
resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==}
unplugin@1.11.0:
resolution: {integrity: sha512-3r7VWZ/webh0SGgJScpWl2/MRCZK5d3ZYFcNaeci/GQ7Teop7zf0Nl2pUuz7G21BwPd9pcUPOC5KmJ2L3WgC5g==}
engines: {node: '>=14.0.0'}
@@ -1448,6 +1532,11 @@ packages:
uri-js@4.4.1:
resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
use-sync-external-store@1.2.0:
resolution: {integrity: sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==}
peerDependencies:
react: ^16.8.0 || ^17.0.0 || ^18.0.0
use-sync-external-store@1.2.2:
resolution: {integrity: sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw==}
peerDependencies:
@@ -1514,6 +1603,21 @@ packages:
zod@3.23.8:
resolution: {integrity: sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==}
zustand@4.5.4:
resolution: {integrity: sha512-/BPMyLKJPtFEvVL0E9E9BTUM63MNyhPGlvxk1XjrfWTUlV+BR8jufjsovHzrtR6YNcBEcL7cMHovL1n9xHawEg==}
engines: {node: '>=12.7.0'}
peerDependencies:
'@types/react': '>=16.8'
immer: '>=9.0.6'
react: '>=16.8'
peerDependenciesMeta:
'@types/react':
optional: true
immer:
optional: true
react:
optional: true
snapshots:
'@ampproject/remapping@2.3.0':
@@ -1972,6 +2076,12 @@ snapshots:
'@popperjs/core@2.11.8': {}
'@redux-devtools/extension@3.3.0(redux@5.0.1)':
dependencies:
'@babel/runtime': 7.24.8
immutable: 4.3.7
redux: 5.0.1
'@rollup/rollup-android-arm-eabi@4.18.1':
optional: true
@@ -2020,8 +2130,31 @@ snapshots:
'@rollup/rollup-win32-x64-msvc@4.18.1':
optional: true
'@tanstack/eslint-plugin-query@5.51.12(eslint@8.57.0)(typescript@5.5.3)':
dependencies:
'@typescript-eslint/utils': 8.0.0-alpha.30(eslint@8.57.0)(typescript@5.5.3)
eslint: 8.57.0
transitivePeerDependencies:
- supports-color
- typescript
'@tanstack/history@1.45.3': {}
'@tanstack/query-core@5.51.9': {}
'@tanstack/query-devtools@5.51.9': {}
'@tanstack/react-query-devtools@5.51.11(@tanstack/react-query@5.51.11(react@18.3.1))(react@18.3.1)':
dependencies:
'@tanstack/query-devtools': 5.51.9
'@tanstack/react-query': 5.51.11(react@18.3.1)
react: 18.3.1
'@tanstack/react-query@5.51.11(react@18.3.1)':
dependencies:
'@tanstack/query-core': 5.51.9
react: 18.3.1
'@tanstack/react-router@1.45.8(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
'@tanstack/history': 1.45.3
@@ -2053,7 +2186,7 @@ snapshots:
prettier: 3.3.3
zod: 3.23.8
'@tanstack/router-plugin@1.45.8(vite@5.3.4)':
'@tanstack/router-plugin@1.45.8(vite@5.3.4(@types/node@20.14.12))':
dependencies:
'@babel/core': 7.24.9
'@babel/generator': 7.24.10
@@ -2073,7 +2206,7 @@ snapshots:
unplugin: 1.11.0
zod: 3.23.8
optionalDependencies:
vite: 5.3.4
vite: 5.3.4(@types/node@20.14.12)
transitivePeerDependencies:
- supports-color
@@ -2102,6 +2235,10 @@ snapshots:
'@types/estree@1.0.5': {}
'@types/node@20.14.12':
dependencies:
undici-types: 5.26.5
'@types/parse-json@4.0.2': {}
'@types/prop-types@15.7.12': {}
@@ -2155,6 +2292,11 @@ snapshots:
'@typescript-eslint/types': 7.16.1
'@typescript-eslint/visitor-keys': 7.16.1
'@typescript-eslint/scope-manager@8.0.0-alpha.30':
dependencies:
'@typescript-eslint/types': 8.0.0-alpha.30
'@typescript-eslint/visitor-keys': 8.0.0-alpha.30
'@typescript-eslint/type-utils@7.16.1(eslint@8.57.0)(typescript@5.5.3)':
dependencies:
'@typescript-eslint/typescript-estree': 7.16.1(typescript@5.5.3)
@@ -2169,6 +2311,8 @@ snapshots:
'@typescript-eslint/types@7.16.1': {}
'@typescript-eslint/types@8.0.0-alpha.30': {}
'@typescript-eslint/typescript-estree@7.16.1(typescript@5.5.3)':
dependencies:
'@typescript-eslint/types': 7.16.1
@@ -2184,6 +2328,21 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@typescript-eslint/typescript-estree@8.0.0-alpha.30(typescript@5.5.3)':
dependencies:
'@typescript-eslint/types': 8.0.0-alpha.30
'@typescript-eslint/visitor-keys': 8.0.0-alpha.30
debug: 4.3.5
globby: 11.1.0
is-glob: 4.0.3
minimatch: 9.0.5
semver: 7.6.3
ts-api-utils: 1.3.0(typescript@5.5.3)
optionalDependencies:
typescript: 5.5.3
transitivePeerDependencies:
- supports-color
'@typescript-eslint/utils@7.16.1(eslint@8.57.0)(typescript@5.5.3)':
dependencies:
'@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0)
@@ -2195,21 +2354,37 @@ snapshots:
- supports-color
- typescript
'@typescript-eslint/utils@8.0.0-alpha.30(eslint@8.57.0)(typescript@5.5.3)':
dependencies:
'@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0)
'@typescript-eslint/scope-manager': 8.0.0-alpha.30
'@typescript-eslint/types': 8.0.0-alpha.30
'@typescript-eslint/typescript-estree': 8.0.0-alpha.30(typescript@5.5.3)
eslint: 8.57.0
transitivePeerDependencies:
- supports-color
- typescript
'@typescript-eslint/visitor-keys@7.16.1':
dependencies:
'@typescript-eslint/types': 7.16.1
eslint-visitor-keys: 3.4.3
'@typescript-eslint/visitor-keys@8.0.0-alpha.30':
dependencies:
'@typescript-eslint/types': 8.0.0-alpha.30
eslint-visitor-keys: 3.4.3
'@ungap/structured-clone@1.2.0': {}
'@vitejs/plugin-react@4.3.1(vite@5.3.4)':
'@vitejs/plugin-react@4.3.1(vite@5.3.4(@types/node@20.14.12))':
dependencies:
'@babel/core': 7.24.9
'@babel/plugin-transform-react-jsx-self': 7.24.7(@babel/core@7.24.9)
'@babel/plugin-transform-react-jsx-source': 7.24.7(@babel/core@7.24.9)
'@types/babel__core': 7.20.5
react-refresh: 0.14.2
vite: 5.3.4
vite: 5.3.4(@types/node@20.14.12)
transitivePeerDependencies:
- supports-color
@@ -2582,6 +2757,8 @@ snapshots:
ignore@5.3.1: {}
immutable@4.3.7: {}
import-fresh@3.3.0:
dependencies:
parent-module: 1.0.1
@@ -2788,6 +2965,8 @@ snapshots:
dependencies:
picomatch: 2.3.1
redux@5.0.1: {}
regenerator-runtime@0.14.1: {}
resolve-from@4.0.0: {}
@@ -2892,6 +3071,8 @@ snapshots:
typescript@5.5.3: {}
undici-types@5.26.5: {}
unplugin@1.11.0:
dependencies:
acorn: 8.12.1
@@ -2909,16 +3090,21 @@ snapshots:
dependencies:
punycode: 2.3.1
use-sync-external-store@1.2.0(react@18.3.1):
dependencies:
react: 18.3.1
use-sync-external-store@1.2.2(react@18.3.1):
dependencies:
react: 18.3.1
vite@5.3.4:
vite@5.3.4(@types/node@20.14.12):
dependencies:
esbuild: 0.21.5
postcss: 8.4.39
rollup: 4.18.1
optionalDependencies:
'@types/node': 20.14.12
fsevents: 2.3.3
webpack-sources@3.2.3: {}
@@ -2940,3 +3126,10 @@ snapshots:
yocto-queue@0.1.0: {}
zod@3.23.8: {}
zustand@4.5.4(@types/react@18.3.3)(react@18.3.1):
dependencies:
use-sync-external-store: 1.2.0(react@18.3.1)
optionalDependencies:
'@types/react': 18.3.3
react: 18.3.1
+61
View File
@@ -0,0 +1,61 @@
import { User } from '../types/User';
const BASE = 'https://khofmann.userpage.fu-berlin.de/phpCourse/exam/api/';
let instance: ApiImpl;
class ApiImpl {
private token: string = '';
constructor() {
if (instance) {
throw new Error('New instance cannot be created!!');
}
instance = this;
}
public logIn = async (email: string, password: string): Promise<User> => {
const { user, token } = await (await this.post('login', { email, password })).json();
this.token = token;
return user;
};
public logOut = async (): Promise<boolean> => {
return await (await this.postAuth('logout')).json();
};
private post = async (
endpoint: string,
body: Record<string, unknown> | undefined = undefined,
headers: HeadersInit | undefined = undefined
) => {
const response = await fetch(`${BASE}${endpoint}`, {
mode: 'cors',
method: 'post',
headers,
body: JSON.stringify(body),
});
if (response.ok) return response;
throw await response.json();
};
private postAuth = async (
endpoint: string,
body: Record<string, unknown> | undefined = undefined,
headers: HeadersInit | undefined = undefined
) => {
const response = await fetch(`${BASE}${endpoint}`, {
mode: 'cors',
method: 'post',
headers: { token: this.token, ...headers },
body: JSON.stringify(body),
});
if (response.ok) return response;
throw await response.json();
};
}
const Api = new ApiImpl();
export default Api;
+20 -2
View File
@@ -1,12 +1,27 @@
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { RouterProvider, createRouter } from '@tanstack/react-router';
import { StrictMode } from 'react';
import ReactDOM from 'react-dom/client';
// Import the generated route tree
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
import { routeTree } from './routeTree.gen';
// Query Client
const queryClient = new QueryClient();
// Create a new router instance
const router = createRouter({ routeTree });
const router = createRouter({
routeTree,
context: {
queryClient,
},
defaultPreload: 'intent',
// Since we're using React Query, we don't want loader calls to ever be stale
// This will ensure that the loader is always called when the route is preloaded or visited
defaultPreloadStaleTime: 0,
basepath: process.env.NODE_ENV === 'development' ? 'phpCourse/exam/dist' : '/phpCourse/exam',
});
// Register the router instance for type safety
declare module '@tanstack/react-router' {
@@ -21,7 +36,10 @@ if (!rootElement.innerHTML) {
const root = ReactDOM.createRoot(rootElement);
root.render(
<StrictMode>
<RouterProvider router={router} />
<QueryClientProvider client={queryClient}>
<RouterProvider router={router} />
<ReactQueryDevtools initialIsOpen={false} />
</QueryClientProvider>
</StrictMode>
);
}
+22 -3
View File
@@ -11,18 +11,32 @@
// Import Routes
import { Route as rootRoute } from './routes/__root'
import { Route as IndexImport } from './routes/index'
// Create/Update Routes
const IndexRoute = IndexImport.update({
path: '/',
getParentRoute: () => rootRoute,
} as any)
// Populate the FileRoutesByPath interface
declare module '@tanstack/react-router' {
interface FileRoutesByPath {}
interface FileRoutesByPath {
'/': {
id: '/'
path: '/'
fullPath: '/'
preLoaderRoute: typeof IndexImport
parentRoute: typeof rootRoute
}
}
}
// Create and export the route tree
export const routeTree = rootRoute.addChildren({})
export const routeTree = rootRoute.addChildren({ IndexRoute })
/* prettier-ignore-end */
@@ -31,7 +45,12 @@ export const routeTree = rootRoute.addChildren({})
"routes": {
"__root__": {
"filePath": "__root.tsx",
"children": []
"children": [
"/"
]
},
"/": {
"filePath": "index.tsx"
}
}
}
+12 -2
View File
@@ -1,9 +1,19 @@
import { createRootRoute, Outlet } from '@tanstack/react-router';
import { QueryClient } from '@tanstack/react-query';
import { createRootRouteWithContext, Link, Outlet } from '@tanstack/react-router';
import { TanStackRouterDevtools } from '@tanstack/router-devtools';
export const Route = createRootRoute({
export const Route = createRootRouteWithContext<{ queryClient: QueryClient }>()({
component: () => (
<>
<Link
to="/"
activeProps={{
className: 'font-bold',
}}
activeOptions={{ exact: true }}
>
Home
</Link>
<Outlet />
<TanStackRouterDevtools />
</>
+40
View File
@@ -0,0 +1,40 @@
import { Button } from '@mui/material';
import { createFileRoute } from '@tanstack/react-router';
import Api from '../api/Api';
import useGuestBookStore from '../store/store';
export const Route = createFileRoute('/')({
component: Home,
});
function Home() {
const setUser = useGuestBookStore((state) => state.setUser);
return (
<>
<Button
onClick={async () => {
try {
setUser(await Api.logIn('max@moritz.net', 'max'));
} catch (error) {
console.log(error);
}
}}
>
Log In
</Button>
<Button
onClick={async () => {
try {
await Api.logOut();
setUser(undefined);
} catch (error) {
console.log(error);
}
}}
>
Log Out
</Button>
</>
);
}
+18
View File
@@ -0,0 +1,18 @@
import type {} from '@redux-devtools/extension'; // required for devtools typing
import { create } from 'zustand';
import { devtools } from 'zustand/middleware';
import { User } from '../types/User';
interface GuestBookState {
user: User | undefined;
setUser: (user: User | undefined) => void;
}
const useGuestBookStore = create<GuestBookState>()(
devtools((set) => ({
user: undefined,
setUser: (user: User | undefined) => set(() => ({ user })),
}))
);
export default useGuestBookStore;
+6
View File
@@ -0,0 +1,6 @@
import { User } from './User';
export interface LoginResponse {
token: string;
user: User;
}
+5
View File
@@ -0,0 +1,5 @@
export interface Timestamp {
date: string;
timezone_type: number;
timezone: string;
}
+12
View File
@@ -0,0 +1,12 @@
import { Timestamp } from './Timestamp';
export interface User {
id: number;
username: string;
status: number;
email: string;
image: string;
isAdmin: boolean;
memberSince: Timestamp;
postCount: number;
}