Major update
This commit is contained in:
292
app/package-lock.json
generated
292
app/package-lock.json
generated
@@ -11,6 +11,7 @@
|
||||
"dependencies": {
|
||||
"@apollo/client": "^3.7.3",
|
||||
"@fluentui/react": "^8.104.2",
|
||||
"@microsoft/signalr": "^7.0.3",
|
||||
"classnames": "^2.3.2",
|
||||
"graphql": "^16.6.0",
|
||||
"react": "^18.2.0",
|
||||
@@ -2562,6 +2563,38 @@
|
||||
"resolved": "https://registry.npmjs.org/@microsoft/load-themed-styles/-/load-themed-styles-1.10.295.tgz",
|
||||
"integrity": "sha512-W+IzEBw8a6LOOfRJM02dTT7BDZijxm+Z7lhtOAz1+y9vQm1Kdz9jlAO+qCEKsfxtUOmKilW8DIRqFw2aUgKeGg=="
|
||||
},
|
||||
"node_modules/@microsoft/signalr": {
|
||||
"version": "7.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@microsoft/signalr/-/signalr-7.0.3.tgz",
|
||||
"integrity": "sha512-gQbrCQxvC/djy+/GBHFpNnAqubGLe0Hrp3ZO8x8NRGAU8jhj3QcHuxhq6N5Z3A0zI6IE/fMfX2xSheQxOwA3ZA==",
|
||||
"dependencies": {
|
||||
"abort-controller": "^3.0.0",
|
||||
"eventsource": "^2.0.2",
|
||||
"fetch-cookie": "^2.0.3",
|
||||
"node-fetch": "^2.6.7",
|
||||
"ws": "^7.4.5"
|
||||
}
|
||||
},
|
||||
"node_modules/@microsoft/signalr/node_modules/ws": {
|
||||
"version": "7.5.9",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz",
|
||||
"integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==",
|
||||
"engines": {
|
||||
"node": ">=8.3.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"bufferutil": "^4.0.1",
|
||||
"utf-8-validate": "^5.0.2"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"bufferutil": {
|
||||
"optional": true
|
||||
},
|
||||
"utf-8-validate": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@nodelib/fs.scandir": {
|
||||
"version": "2.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
|
||||
@@ -3517,6 +3550,17 @@
|
||||
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/abort-controller": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
|
||||
"integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==",
|
||||
"dependencies": {
|
||||
"event-target-shim": "^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.5"
|
||||
}
|
||||
},
|
||||
"node_modules/accepts": {
|
||||
"version": "1.3.8",
|
||||
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
|
||||
@@ -6277,7 +6321,6 @@
|
||||
"version": "0.1.13",
|
||||
"resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz",
|
||||
"integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"iconv-lite": "^0.6.2"
|
||||
@@ -6860,6 +6903,14 @@
|
||||
"through": "~2.3.1"
|
||||
}
|
||||
},
|
||||
"node_modules/event-target-shim": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
|
||||
"integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/eventemitter2": {
|
||||
"version": "6.4.7",
|
||||
"resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.7.tgz",
|
||||
@@ -6881,6 +6932,14 @@
|
||||
"node": ">=0.4.x"
|
||||
}
|
||||
},
|
||||
"node_modules/eventsource": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/eventsource/-/eventsource-2.0.2.tgz",
|
||||
"integrity": "sha512-IzUmBGPR3+oUG9dUeXynyNmf91/3zUSJg1lCktzKw47OXuhco54U3r9B7O4XX+Rb1Itm9OZ2b0RkTs10bICOxA==",
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/evp_bytestokey": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz",
|
||||
@@ -7150,6 +7209,45 @@
|
||||
"pend": "~1.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/fetch-cookie": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fetch-cookie/-/fetch-cookie-2.1.0.tgz",
|
||||
"integrity": "sha512-39+cZRbWfbibmj22R2Jy6dmTbAWC+oqun1f1FzQaNurkPDUP4C38jpeZbiXCR88RKRVDp8UcDrbFXkNhN+NjYg==",
|
||||
"dependencies": {
|
||||
"set-cookie-parser": "^2.4.8",
|
||||
"tough-cookie": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/fetch-cookie/node_modules/punycode": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz",
|
||||
"integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/fetch-cookie/node_modules/tough-cookie": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.2.tgz",
|
||||
"integrity": "sha512-G9fqXWoYFZgTc2z8Q5zaHy/vJMjm+WV0AkAeHxVCQiEB1b+dGvWzFW6QV07cY5jQ5gRkeid2qIkzkxUnmoQZUQ==",
|
||||
"dependencies": {
|
||||
"psl": "^1.1.33",
|
||||
"punycode": "^2.1.1",
|
||||
"universalify": "^0.2.0",
|
||||
"url-parse": "^1.5.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/fetch-cookie/node_modules/universalify": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz",
|
||||
"integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==",
|
||||
"engines": {
|
||||
"node": ">= 4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/figures": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz",
|
||||
@@ -8190,7 +8288,6 @@
|
||||
"version": "0.6.3",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
|
||||
"integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"safer-buffer": ">= 2.1.2 < 3.0.0"
|
||||
@@ -10324,6 +10421,25 @@
|
||||
"tslib": "^2.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/node-fetch": {
|
||||
"version": "2.6.9",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.9.tgz",
|
||||
"integrity": "sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg==",
|
||||
"dependencies": {
|
||||
"whatwg-url": "^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "4.x || >=6.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"encoding": "^0.1.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"encoding": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/node-forge": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz",
|
||||
@@ -11660,8 +11776,7 @@
|
||||
"node_modules/psl": {
|
||||
"version": "1.9.0",
|
||||
"resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz",
|
||||
"integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==",
|
||||
"dev": true
|
||||
"integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag=="
|
||||
},
|
||||
"node_modules/public-encrypt": {
|
||||
"version": "4.0.3",
|
||||
@@ -11733,6 +11848,11 @@
|
||||
"node": ">=0.4.x"
|
||||
}
|
||||
},
|
||||
"node_modules/querystringify": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz",
|
||||
"integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ=="
|
||||
},
|
||||
"node_modules/queue-microtask": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
|
||||
@@ -12225,8 +12345,7 @@
|
||||
"node_modules/requires-port": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
|
||||
"integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==",
|
||||
"dev": true
|
||||
"integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ=="
|
||||
},
|
||||
"node_modules/resolve": {
|
||||
"version": "1.22.1",
|
||||
@@ -12393,7 +12512,7 @@
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
|
||||
"dev": true
|
||||
"devOptional": true
|
||||
},
|
||||
"node_modules/sass-graph": {
|
||||
"version": "4.0.1",
|
||||
@@ -12793,6 +12912,11 @@
|
||||
"integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/set-cookie-parser": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.5.1.tgz",
|
||||
"integrity": "sha512-1jeBGaKNGdEq4FgIrORu/N570dwoPYio8lSoYLWmX7sQ//0JY08Xh9o5pBcgmHQ/MbsYp/aZnOe1s1lIsbLprQ=="
|
||||
},
|
||||
"node_modules/setprototypeof": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
|
||||
@@ -13758,6 +13882,11 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/tr46": {
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
||||
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
|
||||
},
|
||||
"node_modules/trim-newlines": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz",
|
||||
@@ -14252,6 +14381,15 @@
|
||||
"querystring": "0.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/url-parse": {
|
||||
"version": "1.5.10",
|
||||
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz",
|
||||
"integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==",
|
||||
"dependencies": {
|
||||
"querystringify": "^2.1.1",
|
||||
"requires-port": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/url/node_modules/punycode": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz",
|
||||
@@ -14581,6 +14719,11 @@
|
||||
"defaults": "^1.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/webidl-conversions": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
|
||||
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
|
||||
},
|
||||
"node_modules/webpack": {
|
||||
"version": "5.75.0",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.75.0.tgz",
|
||||
@@ -14832,6 +14975,15 @@
|
||||
"node": ">=0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/whatwg-url": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
|
||||
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
|
||||
"dependencies": {
|
||||
"tr46": "~0.0.3",
|
||||
"webidl-conversions": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/which": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||
@@ -16908,6 +17060,26 @@
|
||||
"resolved": "https://registry.npmjs.org/@microsoft/load-themed-styles/-/load-themed-styles-1.10.295.tgz",
|
||||
"integrity": "sha512-W+IzEBw8a6LOOfRJM02dTT7BDZijxm+Z7lhtOAz1+y9vQm1Kdz9jlAO+qCEKsfxtUOmKilW8DIRqFw2aUgKeGg=="
|
||||
},
|
||||
"@microsoft/signalr": {
|
||||
"version": "7.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@microsoft/signalr/-/signalr-7.0.3.tgz",
|
||||
"integrity": "sha512-gQbrCQxvC/djy+/GBHFpNnAqubGLe0Hrp3ZO8x8NRGAU8jhj3QcHuxhq6N5Z3A0zI6IE/fMfX2xSheQxOwA3ZA==",
|
||||
"requires": {
|
||||
"abort-controller": "^3.0.0",
|
||||
"eventsource": "^2.0.2",
|
||||
"fetch-cookie": "^2.0.3",
|
||||
"node-fetch": "^2.6.7",
|
||||
"ws": "^7.4.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"ws": {
|
||||
"version": "7.5.9",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz",
|
||||
"integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==",
|
||||
"requires": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@nodelib/fs.scandir": {
|
||||
"version": "2.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
|
||||
@@ -17684,6 +17856,14 @@
|
||||
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
|
||||
"dev": true
|
||||
},
|
||||
"abort-controller": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
|
||||
"integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==",
|
||||
"requires": {
|
||||
"event-target-shim": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"accepts": {
|
||||
"version": "1.3.8",
|
||||
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
|
||||
@@ -19859,7 +20039,6 @@
|
||||
"version": "0.1.13",
|
||||
"resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz",
|
||||
"integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"iconv-lite": "^0.6.2"
|
||||
@@ -20276,6 +20455,11 @@
|
||||
"through": "~2.3.1"
|
||||
}
|
||||
},
|
||||
"event-target-shim": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
|
||||
"integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ=="
|
||||
},
|
||||
"eventemitter2": {
|
||||
"version": "6.4.7",
|
||||
"resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.7.tgz",
|
||||
@@ -20294,6 +20478,11 @@
|
||||
"integrity": "sha512-3Zmiobend8P9DjmKAty0Era4jV8oJ0yGYe2nJJAxgymF9+N8F2m0hhZiMoWtcfepExzNKZumFU3ksdQbInGWCg==",
|
||||
"dev": true
|
||||
},
|
||||
"eventsource": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/eventsource/-/eventsource-2.0.2.tgz",
|
||||
"integrity": "sha512-IzUmBGPR3+oUG9dUeXynyNmf91/3zUSJg1lCktzKw47OXuhco54U3r9B7O4XX+Rb1Itm9OZ2b0RkTs10bICOxA=="
|
||||
},
|
||||
"evp_bytestokey": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz",
|
||||
@@ -20523,6 +20712,38 @@
|
||||
"pend": "~1.2.0"
|
||||
}
|
||||
},
|
||||
"fetch-cookie": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fetch-cookie/-/fetch-cookie-2.1.0.tgz",
|
||||
"integrity": "sha512-39+cZRbWfbibmj22R2Jy6dmTbAWC+oqun1f1FzQaNurkPDUP4C38jpeZbiXCR88RKRVDp8UcDrbFXkNhN+NjYg==",
|
||||
"requires": {
|
||||
"set-cookie-parser": "^2.4.8",
|
||||
"tough-cookie": "^4.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"punycode": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz",
|
||||
"integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA=="
|
||||
},
|
||||
"tough-cookie": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.2.tgz",
|
||||
"integrity": "sha512-G9fqXWoYFZgTc2z8Q5zaHy/vJMjm+WV0AkAeHxVCQiEB1b+dGvWzFW6QV07cY5jQ5gRkeid2qIkzkxUnmoQZUQ==",
|
||||
"requires": {
|
||||
"psl": "^1.1.33",
|
||||
"punycode": "^2.1.1",
|
||||
"universalify": "^0.2.0",
|
||||
"url-parse": "^1.5.3"
|
||||
}
|
||||
},
|
||||
"universalify": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz",
|
||||
"integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"figures": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz",
|
||||
@@ -21309,7 +21530,6 @@
|
||||
"version": "0.6.3",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
|
||||
"integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"safer-buffer": ">= 2.1.2 < 3.0.0"
|
||||
@@ -22894,6 +23114,14 @@
|
||||
"tslib": "^2.0.3"
|
||||
}
|
||||
},
|
||||
"node-fetch": {
|
||||
"version": "2.6.9",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.9.tgz",
|
||||
"integrity": "sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg==",
|
||||
"requires": {
|
||||
"whatwg-url": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"node-forge": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz",
|
||||
@@ -23916,8 +24144,7 @@
|
||||
"psl": {
|
||||
"version": "1.9.0",
|
||||
"resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz",
|
||||
"integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==",
|
||||
"dev": true
|
||||
"integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag=="
|
||||
},
|
||||
"public-encrypt": {
|
||||
"version": "4.0.3",
|
||||
@@ -23978,6 +24205,11 @@
|
||||
"integrity": "sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA==",
|
||||
"dev": true
|
||||
},
|
||||
"querystringify": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz",
|
||||
"integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ=="
|
||||
},
|
||||
"queue-microtask": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
|
||||
@@ -24367,8 +24599,7 @@
|
||||
"requires-port": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
|
||||
"integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==",
|
||||
"dev": true
|
||||
"integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ=="
|
||||
},
|
||||
"resolve": {
|
||||
"version": "1.22.1",
|
||||
@@ -24476,7 +24707,7 @@
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
|
||||
"dev": true
|
||||
"devOptional": true
|
||||
},
|
||||
"sass-graph": {
|
||||
"version": "4.0.1",
|
||||
@@ -24797,6 +25028,11 @@
|
||||
"integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==",
|
||||
"dev": true
|
||||
},
|
||||
"set-cookie-parser": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.5.1.tgz",
|
||||
"integrity": "sha512-1jeBGaKNGdEq4FgIrORu/N570dwoPYio8lSoYLWmX7sQ//0JY08Xh9o5pBcgmHQ/MbsYp/aZnOe1s1lIsbLprQ=="
|
||||
},
|
||||
"setprototypeof": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
|
||||
@@ -25550,6 +25786,11 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"tr46": {
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
||||
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
|
||||
},
|
||||
"trim-newlines": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz",
|
||||
@@ -25909,6 +26150,15 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"url-parse": {
|
||||
"version": "1.5.10",
|
||||
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz",
|
||||
"integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==",
|
||||
"requires": {
|
||||
"querystringify": "^2.1.1",
|
||||
"requires-port": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"util": {
|
||||
"version": "0.10.4",
|
||||
"resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz",
|
||||
@@ -26202,6 +26452,11 @@
|
||||
"defaults": "^1.0.3"
|
||||
}
|
||||
},
|
||||
"webidl-conversions": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
|
||||
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
|
||||
},
|
||||
"webpack": {
|
||||
"version": "5.75.0",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.75.0.tgz",
|
||||
@@ -26365,6 +26620,15 @@
|
||||
"integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==",
|
||||
"dev": true
|
||||
},
|
||||
"whatwg-url": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
|
||||
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
|
||||
"requires": {
|
||||
"tr46": "~0.0.3",
|
||||
"webidl-conversions": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"which": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||
|
||||
@@ -64,6 +64,7 @@
|
||||
"dependencies": {
|
||||
"@apollo/client": "^3.7.3",
|
||||
"@fluentui/react": "^8.104.2",
|
||||
"@microsoft/signalr": "^7.0.3",
|
||||
"classnames": "^2.3.2",
|
||||
"graphql": "^16.6.0",
|
||||
"react": "^18.2.0",
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
.content {
|
||||
padding: 30px;
|
||||
}
|
||||
padding: 30px;
|
||||
}
|
||||
|
||||
@@ -1,14 +1,19 @@
|
||||
import React from 'react';
|
||||
import styles from './App.module.scss'
|
||||
import styles from './App.module.scss';
|
||||
import { Routes, Route } from 'react-router-dom';
|
||||
import { initializeIcons } from '@fluentui/font-icons-mdl2';
|
||||
import { Grid, Sidebar } from 'semantic-ui-react';
|
||||
import Header from '../header/Header';
|
||||
import Footer from '../footer/Footer';
|
||||
import Navigation from '../navigation/Navigation';
|
||||
import Divisions from '../divisions/Divisions';
|
||||
import Leagues from '../leagues/Leagues';
|
||||
import Seasons from '../seasons/Seasons';
|
||||
import Sports from '../sports/Sports';
|
||||
import Teams from '../teams/Teams';
|
||||
import Venues from '../venues/Venues';
|
||||
import { useSidebarContext } from '../../hooks/sidebarContext/UseSidebarContext';
|
||||
import { usePagination } from '../..//hooks/usePaginiation/UsePagination';
|
||||
|
||||
initializeIcons();
|
||||
|
||||
@@ -18,7 +23,7 @@ const App: React.FC<unknown> = () => {
|
||||
return (
|
||||
<Sidebar.Pushable>
|
||||
<Sidebar.Pusher dimmed={sidebarContext.state.sidebar?.visible}>
|
||||
<Header />
|
||||
<Header />
|
||||
<Grid columns={16}>
|
||||
<Grid.Row>
|
||||
<Grid.Column width={3}>
|
||||
@@ -26,6 +31,18 @@ const App: React.FC<unknown> = () => {
|
||||
</Grid.Column>
|
||||
<Grid.Column width={12}>
|
||||
<div className={styles.content}>
|
||||
<Routes>
|
||||
<Route path='divisions' element={<Divisions />} />
|
||||
</Routes>
|
||||
<Routes>
|
||||
<Route path='leagues' element={<Leagues />} />
|
||||
</Routes>
|
||||
<Routes>
|
||||
<Route path='seasons' element={<Seasons />} />
|
||||
</Routes>
|
||||
<Routes>
|
||||
<Route path='sports' element={<Sports />} />
|
||||
</Routes>
|
||||
<Routes>
|
||||
<Route path='teams' element={<Teams />} />
|
||||
</Routes>
|
||||
@@ -36,7 +53,7 @@ const App: React.FC<unknown> = () => {
|
||||
</Grid.Column>
|
||||
</Grid.Row>
|
||||
</Grid>
|
||||
<Footer />
|
||||
{/* <Footer /> */}
|
||||
</Sidebar.Pusher>
|
||||
</Sidebar.Pushable>
|
||||
);
|
||||
|
||||
171
app/src/components/divisions/Divisions.tsx
Normal file
171
app/src/components/divisions/Divisions.tsx
Normal file
@@ -0,0 +1,171 @@
|
||||
import React, { SyntheticEvent, useEffect, useReducer } from 'react';
|
||||
import { useQuery } from '@apollo/client';
|
||||
import { MessageBar, MessageBarType } from '@fluentui/react/lib/MessageBar';
|
||||
import { initialState, reducer } from './reducer';
|
||||
import { useAppContext } from '../../hooks/appContext/UseAppContext';
|
||||
import { useSidebarContext } from '../../hooks/sidebarContext/UseSidebarContext';
|
||||
import { GET_DIVISIONS } from '../../constants/graphQL';
|
||||
import { INotification } from '../../models/INotification';
|
||||
import {
|
||||
Button,
|
||||
Grid,
|
||||
Header,
|
||||
Icon,
|
||||
Loader,
|
||||
Pagination,
|
||||
Sidebar,
|
||||
Table
|
||||
} from 'semantic-ui-react';
|
||||
import { usePagination } from '../../hooks/usePaginiation/UsePagination';
|
||||
|
||||
const Venues: React.FC<unknown> = () => {
|
||||
const [state, dispatch] = useReducer(reducer, initialState);
|
||||
const appContext = useAppContext();
|
||||
const sidebarContext = useSidebarContext();
|
||||
const currentPageNumber = state.currentPageNumber;
|
||||
const pageSize = state.pageSize;
|
||||
const { data, loading, error, refetch } = useQuery(GET_DIVISIONS, {
|
||||
variables: {
|
||||
pageNumber: currentPageNumber,
|
||||
pageSize: pageSize
|
||||
}
|
||||
});
|
||||
const { pagination } = usePagination();
|
||||
|
||||
const columns: string[] = ['Name', ''];
|
||||
|
||||
const onDismissMessageBar = () => {
|
||||
const notification: INotification = {
|
||||
...appContext.state.notification,
|
||||
isVisible: false
|
||||
};
|
||||
|
||||
appContext.dispatch({ type: 'SET_NOTIFICATION', payload: notification });
|
||||
};
|
||||
|
||||
const onPageChange = (event: SyntheticEvent, data: any) => {
|
||||
const newCurrentPage: number = data.activePage;
|
||||
|
||||
dispatch({ type: 'SET_CURRENT_PAGE_NUMBER', payload: newCurrentPage });
|
||||
};
|
||||
|
||||
const onDetails = (id: number) => {
|
||||
// sidebarContext.dispatch({
|
||||
// type: 'SET_SIDEBAR',
|
||||
// payload: {
|
||||
// sidebar: {
|
||||
// visible: true,
|
||||
// animation: 'overlay',
|
||||
// width: 'very wide',
|
||||
// direction: 'right'
|
||||
// },
|
||||
// content: <VenueDetails venueId={id} />
|
||||
// }
|
||||
// });
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (data) {
|
||||
dispatch({
|
||||
type: 'SET_ITEMS',
|
||||
payload: data.divisions
|
||||
});
|
||||
}
|
||||
}, [data]);
|
||||
|
||||
useEffect(() => {
|
||||
// console.log(error);
|
||||
const notification: INotification = {
|
||||
messageBarType: MessageBarType.error,
|
||||
message: error?.message,
|
||||
isMultiline: false,
|
||||
isVisible: false
|
||||
};
|
||||
|
||||
appContext.dispatch({ type: 'SET_NOTIFICATION', payload: notification });
|
||||
}, [error]);
|
||||
|
||||
useEffect(() => {
|
||||
refetch({
|
||||
pageNumber: currentPageNumber,
|
||||
pageSize: pageSize
|
||||
});
|
||||
}, [currentPageNumber]);
|
||||
|
||||
return (
|
||||
<Grid columns={1}>
|
||||
<Grid.Row>
|
||||
<Header as='h1'>Divisions</Header>
|
||||
</Grid.Row>
|
||||
{appContext.state.notification?.isVisible && (
|
||||
<Grid.Row>
|
||||
<Grid.Column>
|
||||
<MessageBar
|
||||
messageBarType={appContext.state.notification?.messageBarType}
|
||||
isMultiline={appContext.state.notification?.isMultiline}
|
||||
onDismiss={onDismissMessageBar}
|
||||
>
|
||||
{appContext.state.notification?.message}
|
||||
</MessageBar>
|
||||
</Grid.Column>
|
||||
</Grid.Row>
|
||||
)}
|
||||
<Grid.Row>
|
||||
<Grid.Column>
|
||||
{loading && (
|
||||
<Loader size='massive' active={loading}>
|
||||
Loading...
|
||||
</Loader>
|
||||
)}
|
||||
{!loading && (
|
||||
<Table selectable>
|
||||
<Table.Header>
|
||||
<Table.Row>
|
||||
{columns.map((column: string, index: number) => {
|
||||
return (
|
||||
<Table.HeaderCell key={index}>{column}</Table.HeaderCell>
|
||||
);
|
||||
})}
|
||||
</Table.Row>
|
||||
</Table.Header>
|
||||
<Table.Body>
|
||||
{state.items?.map((item) => {
|
||||
return (
|
||||
<Table.Row key={item.id}>
|
||||
<Table.Cell>{item.name}</Table.Cell>
|
||||
<Table.Cell textAlign='right'>
|
||||
<Button basic icon onClick={() => onDetails(item.id)}>
|
||||
<Icon name='info circle' />
|
||||
</Button>
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
);
|
||||
})}
|
||||
</Table.Body>
|
||||
<Table.Footer>
|
||||
<Table.Row>
|
||||
<Table.HeaderCell colSpan='2'>
|
||||
<Grid columns={1}>
|
||||
<Grid.Row>
|
||||
<Grid.Column textAlign='right'>
|
||||
<Pagination
|
||||
totalPages={pagination ? pagination.TotalPages : ''}
|
||||
activePage={state.currentPageNumber}
|
||||
onPageChange={onPageChange}
|
||||
size='mini'
|
||||
/>
|
||||
</Grid.Column>
|
||||
</Grid.Row>
|
||||
</Grid>
|
||||
</Table.HeaderCell>
|
||||
</Table.Row>
|
||||
</Table.Footer>
|
||||
</Table>
|
||||
)}
|
||||
</Grid.Column>
|
||||
</Grid.Row>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
|
||||
export default Venues;
|
||||
8
app/src/components/divisions/IDivisionsState.ts
Normal file
8
app/src/components/divisions/IDivisionsState.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { IDivision } from '../../models/IDivision';
|
||||
|
||||
export interface IDivisionsState {
|
||||
items: IDivision[];
|
||||
currentPageNumber: number;
|
||||
pageSize: number;
|
||||
isPanelOpen: boolean;
|
||||
}
|
||||
50
app/src/components/divisions/reducer.ts
Normal file
50
app/src/components/divisions/reducer.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
import { IDivisionsState } from './IDivisionsState';
|
||||
import { IDivision } from '../../models/IDivision';
|
||||
|
||||
export type Action =
|
||||
| { type: 'SET_ITEMS'; payload: IDivision[] }
|
||||
| { type: 'SET_CURRENT_PAGE_NUMBER'; payload: number }
|
||||
| { type: 'SET_PAGE_SIZE'; payload: number }
|
||||
| { type: 'SET_IS_PANEL_OPEN'; payload: boolean };
|
||||
|
||||
export const initialState: IDivisionsState = {
|
||||
items: [],
|
||||
currentPageNumber: 1,
|
||||
pageSize: 10,
|
||||
isPanelOpen: false
|
||||
};
|
||||
|
||||
export const reducer = (
|
||||
state: IDivisionsState,
|
||||
action: Action
|
||||
): IDivisionsState => {
|
||||
switch (action.type) {
|
||||
case 'SET_ITEMS': {
|
||||
return {
|
||||
...state,
|
||||
items: action.payload
|
||||
};
|
||||
}
|
||||
case 'SET_CURRENT_PAGE_NUMBER': {
|
||||
return {
|
||||
...state,
|
||||
currentPageNumber: action.payload
|
||||
};
|
||||
}
|
||||
case 'SET_PAGE_SIZE': {
|
||||
return {
|
||||
...state,
|
||||
pageSize: action.payload
|
||||
};
|
||||
}
|
||||
case 'SET_IS_PANEL_OPEN': {
|
||||
return {
|
||||
...state,
|
||||
isPanelOpen: action.payload
|
||||
};
|
||||
}
|
||||
default: {
|
||||
return state;
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1,4 +1,4 @@
|
||||
.siteFooter {
|
||||
background-color: #e0e1e2;
|
||||
height: 150px;
|
||||
}
|
||||
background-color: #e0e1e2;
|
||||
height: 150px;
|
||||
}
|
||||
|
||||
@@ -3,20 +3,18 @@ import styles from './Footer.module.scss';
|
||||
import { Grid } from 'semantic-ui-react';
|
||||
|
||||
const Footer: React.FC<unknown> = () => {
|
||||
return (
|
||||
<div className={styles.siteFooter}>
|
||||
<Grid columns={16}>
|
||||
<Grid.Row>
|
||||
<Grid.Column width={8}>
|
||||
Hello!
|
||||
</Grid.Column>
|
||||
<Grid.Column width={8} textAlign='right'>
|
||||
Goodbye!
|
||||
</Grid.Column>
|
||||
</Grid.Row>
|
||||
</Grid>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<div className={styles.siteFooter}>
|
||||
<Grid columns={16}>
|
||||
<Grid.Row>
|
||||
<Grid.Column width={8}>Hello!</Grid.Column>
|
||||
<Grid.Column width={8} textAlign='right'>
|
||||
Goodbye!
|
||||
</Grid.Column>
|
||||
</Grid.Row>
|
||||
</Grid>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Footer;
|
||||
export default Footer;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
.siteHeader {
|
||||
background-color: #e0e1e2;
|
||||
height: 100px;
|
||||
}
|
||||
background-color: #e0e1e2;
|
||||
height: 100px;
|
||||
}
|
||||
|
||||
@@ -3,20 +3,20 @@ import styles from './Header.module.scss';
|
||||
import { Grid, Icon } from 'semantic-ui-react';
|
||||
|
||||
const Header: React.FC<unknown> = () => {
|
||||
return (
|
||||
<div className={styles.siteHeader}>
|
||||
<Grid columns={16}>
|
||||
<Grid.Row>
|
||||
<Grid.Column width={8}>
|
||||
<Icon name='baseball ball' size='huge' />
|
||||
</Grid.Column>
|
||||
<Grid.Column width={8} textAlign='right'>
|
||||
Goodbye!
|
||||
</Grid.Column>
|
||||
</Grid.Row>
|
||||
</Grid>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<div className={styles.siteHeader}>
|
||||
<Grid columns={16}>
|
||||
<Grid.Row>
|
||||
<Grid.Column width={8}>
|
||||
<Icon name='baseball ball' size='huge' />
|
||||
</Grid.Column>
|
||||
<Grid.Column width={8} textAlign='right'>
|
||||
Goodbye!
|
||||
</Grid.Column>
|
||||
</Grid.Row>
|
||||
</Grid>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Header;
|
||||
export default Header;
|
||||
|
||||
8
app/src/components/leagues/ILeaguesState.ts
Normal file
8
app/src/components/leagues/ILeaguesState.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { ILeague } from '../../models/ILeague';
|
||||
|
||||
export interface ILeaguesState {
|
||||
items: ILeague[];
|
||||
currentPageNumber: number;
|
||||
pageSize: number;
|
||||
isPanelOpen: boolean;
|
||||
}
|
||||
173
app/src/components/leagues/Leagues.tsx
Normal file
173
app/src/components/leagues/Leagues.tsx
Normal file
@@ -0,0 +1,173 @@
|
||||
import React, { SyntheticEvent, useEffect, useReducer } from 'react';
|
||||
import { useQuery } from '@apollo/client';
|
||||
import { MessageBar, MessageBarType } from '@fluentui/react/lib/MessageBar';
|
||||
import { initialState, reducer } from './reducer';
|
||||
import { useAppContext } from '../../hooks/appContext/UseAppContext';
|
||||
import { useSidebarContext } from '../../hooks/sidebarContext/UseSidebarContext';
|
||||
import { GET_LEAGUES } from '../../constants/graphQL';
|
||||
import { INotification } from '../../models/INotification';
|
||||
import {
|
||||
Button,
|
||||
Grid,
|
||||
Header,
|
||||
Icon,
|
||||
Loader,
|
||||
Pagination,
|
||||
Sidebar,
|
||||
Table
|
||||
} from 'semantic-ui-react';
|
||||
// import VenueDetails from '../venueDetails/VenueDetails';
|
||||
import { usePagination } from '../../hooks/usePaginiation/UsePagination';
|
||||
|
||||
const Leagues: React.FC<unknown> = () => {
|
||||
const [state, dispatch] = useReducer(reducer, initialState);
|
||||
const appContext = useAppContext();
|
||||
const sidebarContext = useSidebarContext();
|
||||
const currentPageNumber = state.currentPageNumber;
|
||||
const pageSize = state.pageSize;
|
||||
const { data, loading, error, refetch } = useQuery(GET_LEAGUES, {
|
||||
variables: {
|
||||
pageNumber: currentPageNumber,
|
||||
pageSize: pageSize
|
||||
}
|
||||
});
|
||||
const { pagination } = usePagination();
|
||||
|
||||
const columns: string[] = ['Name', ''];
|
||||
|
||||
const onDismissMessageBar = () => {
|
||||
const notification: INotification = {
|
||||
...appContext.state.notification,
|
||||
isVisible: false
|
||||
};
|
||||
|
||||
appContext.dispatch({ type: 'SET_NOTIFICATION', payload: notification });
|
||||
};
|
||||
|
||||
const onPageChange = (event: SyntheticEvent, data: any) => {
|
||||
const newCurrentPage: number = data.activePage;
|
||||
|
||||
dispatch({ type: 'SET_CURRENT_PAGE_NUMBER', payload: newCurrentPage });
|
||||
};
|
||||
|
||||
const onDetails = (id: number) => {
|
||||
// sidebarContext.dispatch({
|
||||
// type: 'SET_SIDEBAR',
|
||||
// payload: {
|
||||
// sidebar: {
|
||||
// visible: true,
|
||||
// animation: 'overlay',
|
||||
// width: 'very wide',
|
||||
// direction: 'right'
|
||||
// },
|
||||
// content: <VenueDetails venueId={id} />
|
||||
// }
|
||||
// });
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
console.log(data)
|
||||
if (data) {
|
||||
dispatch({
|
||||
type: 'SET_ITEMS',
|
||||
payload: data.leagues
|
||||
});
|
||||
}
|
||||
}, [data]);
|
||||
|
||||
useEffect(() => {
|
||||
// console.log(error);
|
||||
const notification: INotification = {
|
||||
messageBarType: MessageBarType.error,
|
||||
message: error?.message,
|
||||
isMultiline: false,
|
||||
isVisible: false
|
||||
};
|
||||
|
||||
appContext.dispatch({ type: 'SET_NOTIFICATION', payload: notification });
|
||||
}, [error]);
|
||||
|
||||
useEffect(() => {
|
||||
refetch({
|
||||
pageNumber: currentPageNumber,
|
||||
pageSize: pageSize
|
||||
});
|
||||
}, [currentPageNumber]);
|
||||
|
||||
return (
|
||||
<Grid columns={1}>
|
||||
<Grid.Row>
|
||||
<Header as='h1'>Leagues</Header>
|
||||
</Grid.Row>
|
||||
{appContext.state.notification?.isVisible && (
|
||||
<Grid.Row>
|
||||
<Grid.Column>
|
||||
<MessageBar
|
||||
messageBarType={appContext.state.notification?.messageBarType}
|
||||
isMultiline={appContext.state.notification?.isMultiline}
|
||||
onDismiss={onDismissMessageBar}
|
||||
>
|
||||
{appContext.state.notification?.message}
|
||||
</MessageBar>
|
||||
</Grid.Column>
|
||||
</Grid.Row>
|
||||
)}
|
||||
<Grid.Row>
|
||||
<Grid.Column>
|
||||
{loading && (
|
||||
<Loader size='massive' active={loading}>
|
||||
Loading...
|
||||
</Loader>
|
||||
)}
|
||||
{!loading && (
|
||||
<Table selectable>
|
||||
<Table.Header>
|
||||
<Table.Row>
|
||||
{columns.map((column: string, index: number) => {
|
||||
return (
|
||||
<Table.HeaderCell key={index}>{column}</Table.HeaderCell>
|
||||
);
|
||||
})}
|
||||
</Table.Row>
|
||||
</Table.Header>
|
||||
<Table.Body>
|
||||
{state.items.map((item) => {
|
||||
return (
|
||||
<Table.Row key={item.id}>
|
||||
<Table.Cell>{item.name}</Table.Cell>
|
||||
<Table.Cell textAlign='right'>
|
||||
<Button basic icon onClick={() => onDetails(item.id)}>
|
||||
<Icon name='info circle' />
|
||||
</Button>
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
);
|
||||
})}
|
||||
</Table.Body>
|
||||
<Table.Footer>
|
||||
<Table.Row>
|
||||
<Table.HeaderCell colSpan='2'>
|
||||
<Grid columns={1}>
|
||||
<Grid.Row>
|
||||
<Grid.Column textAlign='right'>
|
||||
<Pagination
|
||||
totalPages={pagination ? pagination.TotalPages : ''}
|
||||
activePage={state.currentPageNumber}
|
||||
onPageChange={onPageChange}
|
||||
size='mini'
|
||||
/>
|
||||
</Grid.Column>
|
||||
</Grid.Row>
|
||||
</Grid>
|
||||
</Table.HeaderCell>
|
||||
</Table.Row>
|
||||
</Table.Footer>
|
||||
</Table>
|
||||
)}
|
||||
</Grid.Column>
|
||||
</Grid.Row>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
|
||||
export default Leagues;
|
||||
50
app/src/components/leagues/reducer.ts
Normal file
50
app/src/components/leagues/reducer.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
import { ILeaguesState } from './ILeaguesState';
|
||||
import { ILeague } from '../../models/ILeague';
|
||||
|
||||
export type Action =
|
||||
| { type: 'SET_ITEMS'; payload: ILeague[] }
|
||||
| { type: 'SET_CURRENT_PAGE_NUMBER'; payload: number }
|
||||
| { type: 'SET_PAGE_SIZE'; payload: number }
|
||||
| { type: 'SET_IS_PANEL_OPEN'; payload: boolean };
|
||||
|
||||
export const initialState: ILeaguesState = {
|
||||
items: [],
|
||||
currentPageNumber: 1,
|
||||
pageSize: 10,
|
||||
isPanelOpen: false
|
||||
};
|
||||
|
||||
export const reducer = (
|
||||
state: ILeaguesState,
|
||||
action: Action
|
||||
): ILeaguesState => {
|
||||
switch (action.type) {
|
||||
case 'SET_ITEMS': {
|
||||
return {
|
||||
...state,
|
||||
items: action.payload
|
||||
};
|
||||
}
|
||||
case 'SET_CURRENT_PAGE_NUMBER': {
|
||||
return {
|
||||
...state,
|
||||
currentPageNumber: action.payload
|
||||
};
|
||||
}
|
||||
case 'SET_PAGE_SIZE': {
|
||||
return {
|
||||
...state,
|
||||
pageSize: action.payload
|
||||
};
|
||||
}
|
||||
case 'SET_IS_PANEL_OPEN': {
|
||||
return {
|
||||
...state,
|
||||
isPanelOpen: action.payload
|
||||
};
|
||||
}
|
||||
default: {
|
||||
return state;
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -35,29 +35,22 @@ const Navigation: React.FC<unknown> = (props) => {
|
||||
const [state, dispatch] = useReducer(reducer, initialState);
|
||||
const location = useLocation();
|
||||
const navigate = useNavigate();
|
||||
const menuItems: string[] = [
|
||||
'gameday',
|
||||
'teams',
|
||||
'venues'
|
||||
];
|
||||
const menuItems: string[] = ['gameday', 'divisions', 'leagues', 'seasons', 'sports', 'teams', 'venues'];
|
||||
|
||||
const onMenuItemClicked = (event: any, { name }: any) => {
|
||||
navigate(name);
|
||||
dispatch({ type: 'SET_ACTIVE_MENU_ITEM', payload: name });
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const activeLink: string = location.pathname === '/' ? 'home' : location.pathname.replace('/', '')
|
||||
const activeLink: string =
|
||||
location.pathname === '/' ? 'home' : location.pathname.replace('/', '');
|
||||
|
||||
dispatch({ type: 'SET_ACTIVE_MENU_ITEM', payload: activeLink });
|
||||
}, [])
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Menu
|
||||
pointing
|
||||
secondary
|
||||
vertical
|
||||
>
|
||||
<Menu pointing secondary vertical>
|
||||
{menuItems.map((menuItem: string) => {
|
||||
return (
|
||||
<Menu.Item
|
||||
@@ -66,10 +59,10 @@ const Navigation: React.FC<unknown> = (props) => {
|
||||
active={state.activeLink === menuItem}
|
||||
onClick={onMenuItemClicked}
|
||||
/>
|
||||
)
|
||||
);
|
||||
})}
|
||||
</Menu>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export default Navigation;
|
||||
|
||||
@@ -1,19 +1,21 @@
|
||||
import { INavigationState } from "./INavigationState"
|
||||
import { INavigationState } from './INavigationState';
|
||||
|
||||
export type Action =
|
||||
| { type: 'SET_ACTIVE_MENU_ITEM', payload: string }
|
||||
export type Action = { type: 'SET_ACTIVE_MENU_ITEM'; payload: string };
|
||||
|
||||
export const initialState: INavigationState = {
|
||||
activeLink: ''
|
||||
}
|
||||
activeLink: ''
|
||||
};
|
||||
|
||||
export const reducer = (state: INavigationState, action: Action): INavigationState => {
|
||||
switch (action.type) {
|
||||
case 'SET_ACTIVE_MENU_ITEM': {
|
||||
return {
|
||||
...state,
|
||||
activeLink: action.payload
|
||||
}
|
||||
}
|
||||
export const reducer = (
|
||||
state: INavigationState,
|
||||
action: Action
|
||||
): INavigationState => {
|
||||
switch (action.type) {
|
||||
case 'SET_ACTIVE_MENU_ITEM': {
|
||||
return {
|
||||
...state,
|
||||
activeLink: action.payload
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
export interface INewSeasonModalProps {
|
||||
isModalOpen: boolean;
|
||||
onCloseModal: () => void;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
import { HubConnection } from "@microsoft/signalr";
|
||||
|
||||
export interface INewSeasonModalState {
|
||||
connection: HubConnection | undefined,
|
||||
year: string;
|
||||
percentComplete: number;
|
||||
loading: boolean;
|
||||
}
|
||||
134
app/src/components/newSeasonDialog/NewSeasonModal.tsx
Normal file
134
app/src/components/newSeasonDialog/NewSeasonModal.tsx
Normal file
@@ -0,0 +1,134 @@
|
||||
import React, { SyntheticEvent, useEffect, useReducer } from 'react';
|
||||
import { initialState, reducer } from './reducer';
|
||||
import {
|
||||
Button,
|
||||
Grid,
|
||||
Icon,
|
||||
Input,
|
||||
Modal,
|
||||
Progress
|
||||
} from 'semantic-ui-react';
|
||||
import { INewSeasonModalProps } from './INewSeasonModalProps';
|
||||
import { HubConnection, HubConnectionBuilder } from '@microsoft/signalr';
|
||||
import { ISeasonMessage } from '../../models/ISeasonMessage';
|
||||
|
||||
const NewSeasonModal: React.FC<INewSeasonModalProps> = ({ isModalOpen, onCloseModal }: INewSeasonModalProps) => {
|
||||
const [state, dispatch] = useReducer(reducer, initialState);
|
||||
const topic = 'ReceiveSeasonMessage';
|
||||
|
||||
const onYearChanged = (event: SyntheticEvent, data: any) => {
|
||||
dispatch({ type: 'SET_YEAR', payload: data['value']})
|
||||
}
|
||||
|
||||
const onOk = () => {
|
||||
dispatch({ type: 'SET_IS_LOADING', payload: true });
|
||||
|
||||
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (isModalOpen) {
|
||||
const newConnection: HubConnection = new HubConnectionBuilder()
|
||||
.withUrl('http://localhost:5580/hubs/season')
|
||||
.withAutomaticReconnect()
|
||||
.build();
|
||||
|
||||
dispatch({ type: 'SET_CONNECTION', payload: newConnection });
|
||||
} else {
|
||||
if (state.connection) {
|
||||
state.connection.stop();
|
||||
dispatch({ type: 'SET_CONNECTION', payload: undefined });
|
||||
}
|
||||
}
|
||||
}, [isModalOpen])
|
||||
|
||||
useEffect(() => {
|
||||
if (state.connection) {
|
||||
const connection: HubConnection = state.connection;
|
||||
|
||||
connection.start().then((result) => {
|
||||
console.log('connected');
|
||||
|
||||
connection.on(topic, (message: ISeasonMessage) => {
|
||||
console.log(message);
|
||||
dispatch({ type: 'SET_PERCENT_COMPLETE', payload: Math.floor((message.datesCompleted / message.totalDates) * 100) })
|
||||
})
|
||||
}).catch((error) => {
|
||||
console.log(`Connection failed with the following message: ${error}`);
|
||||
})
|
||||
}
|
||||
}, [state.connection]);
|
||||
|
||||
useEffect(() => {
|
||||
if (state.percentComplete === 100) {
|
||||
onCloseModal();
|
||||
dispatch({ type: 'SET_PERCENT_COMPLETE', payload: 0 })
|
||||
}
|
||||
}, [state.percentComplete])
|
||||
|
||||
return (
|
||||
<Modal
|
||||
open={isModalOpen}
|
||||
onClose={onCloseModal}
|
||||
closeOnEscape={false}
|
||||
closeOnDimmerClick={false}
|
||||
>
|
||||
<Modal.Header>
|
||||
Add New Season
|
||||
</Modal.Header>
|
||||
<Modal.Content>
|
||||
<Grid columns={1}>
|
||||
{!state.loading &&
|
||||
<React.Fragment>
|
||||
<Grid.Row>
|
||||
<span>Enter a year below and click <strong>OK</strong> to load games.</span>
|
||||
</Grid.Row>
|
||||
<Grid.Row>
|
||||
<Input
|
||||
label='Year'
|
||||
onChange={onYearChanged}
|
||||
/>
|
||||
</Grid.Row>
|
||||
</React.Fragment>
|
||||
}
|
||||
{state.loading &&
|
||||
<Grid.Row>
|
||||
<Grid.Column>
|
||||
<Progress
|
||||
percent={state.percentComplete}
|
||||
indicating
|
||||
progress
|
||||
>
|
||||
Loading games...
|
||||
</Progress>
|
||||
</Grid.Column>
|
||||
</Grid.Row>
|
||||
}
|
||||
</Grid>
|
||||
</Modal.Content>
|
||||
<Modal.Actions>
|
||||
<Button
|
||||
icon
|
||||
labelPosition='left'
|
||||
onClick={onCloseModal}
|
||||
disabled={state.loading}
|
||||
>
|
||||
<Icon name='cancel' />
|
||||
Cancel
|
||||
</Button>
|
||||
<Button
|
||||
primary
|
||||
icon
|
||||
labelPosition='left'
|
||||
disabled={state.loading}
|
||||
onClick={onOk}
|
||||
>
|
||||
<Icon name='check' />
|
||||
OK
|
||||
</Button>
|
||||
</Modal.Actions>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
|
||||
export default NewSeasonModal;
|
||||
47
app/src/components/newSeasonDialog/reducer.ts
Normal file
47
app/src/components/newSeasonDialog/reducer.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
import { HubConnection } from "@microsoft/signalr";
|
||||
import { INewSeasonModalState } from "./INewSeasonModalState";
|
||||
|
||||
type Action =
|
||||
| { type: 'SET_CONNECTION'; payload: HubConnection | undefined }
|
||||
| { type: 'SET_YEAR'; payload: string }
|
||||
| { type: 'SET_PERCENT_COMPLETE'; payload: number }
|
||||
| { type: 'SET_IS_LOADING'; payload: boolean };
|
||||
|
||||
export const initialState: INewSeasonModalState = {
|
||||
connection: undefined,
|
||||
year: '',
|
||||
percentComplete: 0,
|
||||
loading: false
|
||||
}
|
||||
|
||||
export const reducer = (state: INewSeasonModalState, action: Action): INewSeasonModalState => {
|
||||
switch (action.type) {
|
||||
case 'SET_CONNECTION': {
|
||||
return {
|
||||
...state,
|
||||
connection: action.payload
|
||||
}
|
||||
}
|
||||
case 'SET_YEAR': {
|
||||
return {
|
||||
...state,
|
||||
year: action.payload
|
||||
}
|
||||
}
|
||||
case 'SET_PERCENT_COMPLETE': {
|
||||
return {
|
||||
...state,
|
||||
percentComplete: action.payload
|
||||
}
|
||||
}
|
||||
case 'SET_IS_LOADING': {
|
||||
return {
|
||||
...state,
|
||||
loading: action.payload
|
||||
}
|
||||
}
|
||||
default: {
|
||||
return state;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,7 @@
|
||||
import React from 'react';
|
||||
import { IPaginatorProps } from './IPaginatorProps';
|
||||
import styles from './Paginator.module.scss';
|
||||
import {
|
||||
IconButton
|
||||
} from '@fluentui/react/lib/Button';
|
||||
import { IconButton } from '@fluentui/react/lib/Button';
|
||||
import { Link } from '@fluentui/react/lib/Link';
|
||||
|
||||
const range = (start: number, end: number) => {
|
||||
|
||||
9
app/src/components/seasons/ISeasonsState.ts
Normal file
9
app/src/components/seasons/ISeasonsState.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { ISeason } from '../../models/ISeason';
|
||||
|
||||
export interface ISeasonsState {
|
||||
items: ISeason[];
|
||||
currentPageNumber: number;
|
||||
pageSize: number;
|
||||
isPanelOpen: boolean;
|
||||
isModalOpen: boolean;
|
||||
}
|
||||
202
app/src/components/seasons/Seasons.tsx
Normal file
202
app/src/components/seasons/Seasons.tsx
Normal file
@@ -0,0 +1,202 @@
|
||||
import React, { SyntheticEvent, useEffect, useReducer } from 'react';
|
||||
import { useQuery } from '@apollo/client';
|
||||
import { MessageBar, MessageBarType } from '@fluentui/react/lib/MessageBar';
|
||||
import { initialState, reducer } from './reducer';
|
||||
import { useAppContext } from '../../hooks/appContext/UseAppContext';
|
||||
import { useSidebarContext } from '../../hooks/sidebarContext/UseSidebarContext';
|
||||
import { GET_SEASONS } from '../../constants/graphQL';
|
||||
import { INotification } from '../../models/INotification';
|
||||
import {
|
||||
Button,
|
||||
Grid,
|
||||
Header,
|
||||
Icon,
|
||||
Loader,
|
||||
Pagination,
|
||||
Sidebar,
|
||||
Table
|
||||
} from 'semantic-ui-react';
|
||||
// import VenueDetails from '../venueDetails/VenueDetails';
|
||||
import { usePagination } from '../../hooks/usePaginiation/UsePagination';
|
||||
import NewSeasonModal from '../newSeasonDialog/NewSeasonModal';
|
||||
|
||||
const Seasons: React.FC<unknown> = () => {
|
||||
const [state, dispatch] = useReducer(reducer, initialState);
|
||||
const appContext = useAppContext();
|
||||
const sidebarContext = useSidebarContext();
|
||||
const currentPageNumber = state.currentPageNumber;
|
||||
const pageSize = state.pageSize;
|
||||
const { data, loading, error, refetch } = useQuery(GET_SEASONS, {
|
||||
variables: {
|
||||
pageNumber: currentPageNumber,
|
||||
pageSize: pageSize
|
||||
}
|
||||
});
|
||||
const { pagination } = usePagination();
|
||||
|
||||
const columns: string[] = ['Name', ''];
|
||||
|
||||
const onDismissMessageBar = () => {
|
||||
const notification: INotification = {
|
||||
...appContext.state.notification,
|
||||
isVisible: false
|
||||
};
|
||||
|
||||
appContext.dispatch({ type: 'SET_NOTIFICATION', payload: notification });
|
||||
};
|
||||
|
||||
const onPageChange = (event: SyntheticEvent, data: any) => {
|
||||
const newCurrentPage: number = data.activePage;
|
||||
|
||||
dispatch({ type: 'SET_CURRENT_PAGE_NUMBER', payload: newCurrentPage });
|
||||
};
|
||||
|
||||
const onDetails = (id: number) => {
|
||||
// sidebarContext.dispatch({
|
||||
// type: 'SET_SIDEBAR',
|
||||
// payload: {
|
||||
// sidebar: {
|
||||
// visible: true,
|
||||
// animation: 'overlay',
|
||||
// width: 'very wide',
|
||||
// direction: 'right'
|
||||
// },
|
||||
// content: <VenueDetails venueId={id} />
|
||||
// }
|
||||
// });
|
||||
};
|
||||
|
||||
const onIsModalOpen = () => {
|
||||
dispatch({ type: 'SET_IS_MODAL_OPEN', payload: !state.isModalOpen });
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (data) {
|
||||
dispatch({
|
||||
type: 'SET_ITEMS',
|
||||
payload: data.leagues
|
||||
});
|
||||
}
|
||||
}, [data]);
|
||||
|
||||
useEffect(() => {
|
||||
// console.log(error);
|
||||
const notification: INotification = {
|
||||
messageBarType: MessageBarType.error,
|
||||
message: error?.message,
|
||||
isMultiline: false,
|
||||
isVisible: false
|
||||
};
|
||||
|
||||
appContext.dispatch({ type: 'SET_NOTIFICATION', payload: notification });
|
||||
}, [error]);
|
||||
|
||||
useEffect(() => {
|
||||
refetch({
|
||||
pageNumber: currentPageNumber,
|
||||
pageSize: pageSize
|
||||
});
|
||||
}, [currentPageNumber]);
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Grid>
|
||||
<Grid.Row columns={2}>
|
||||
<Grid.Column >
|
||||
<Header as='h1'>Seasons</Header>
|
||||
</Grid.Column>
|
||||
<Grid.Column textAlign='right'>
|
||||
<Button
|
||||
primary
|
||||
icon
|
||||
labelPosition='left'
|
||||
onClick={onIsModalOpen}
|
||||
>
|
||||
<Icon name='add' />
|
||||
Add
|
||||
</Button>
|
||||
</Grid.Column>
|
||||
</Grid.Row>
|
||||
{appContext.state.notification?.isVisible && (
|
||||
<Grid.Row columns={1}>
|
||||
<Grid.Column>
|
||||
<MessageBar
|
||||
messageBarType={appContext.state.notification?.messageBarType}
|
||||
isMultiline={appContext.state.notification?.isMultiline}
|
||||
onDismiss={onDismissMessageBar}
|
||||
>
|
||||
{appContext.state.notification?.message}
|
||||
</MessageBar>
|
||||
</Grid.Column>
|
||||
</Grid.Row>
|
||||
)}
|
||||
<Grid.Row columns={1}>
|
||||
<Grid.Column>
|
||||
{loading && (
|
||||
<Loader size='massive' active={loading}>
|
||||
Loading...
|
||||
</Loader>
|
||||
)}
|
||||
{!loading && state.items.length === 0 &&
|
||||
<div>
|
||||
<p>There are currently no seasons loaded.</p>
|
||||
<p>Click <strong>Add</strong> to load a season.</p>
|
||||
</div>
|
||||
}
|
||||
{!loading && state.items.length > 0 && (
|
||||
<Table selectable>
|
||||
<Table.Header>
|
||||
<Table.Row>
|
||||
{columns.map((column: string, index: number) => {
|
||||
return (
|
||||
<Table.HeaderCell key={index}>{column}</Table.HeaderCell>
|
||||
);
|
||||
})}
|
||||
</Table.Row>
|
||||
</Table.Header>
|
||||
<Table.Body>
|
||||
{state.items.map((item) => {
|
||||
return (
|
||||
<Table.Row key={item.id}>
|
||||
<Table.Cell>{item.id}</Table.Cell>
|
||||
<Table.Cell textAlign='right'>
|
||||
<Button basic icon onClick={() => onDetails(item.id)}>
|
||||
<Icon name='info circle' />
|
||||
</Button>
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
);
|
||||
})}
|
||||
</Table.Body>
|
||||
<Table.Footer>
|
||||
<Table.Row>
|
||||
<Table.HeaderCell colSpan='2'>
|
||||
<Grid columns={1}>
|
||||
<Grid.Row>
|
||||
<Grid.Column textAlign='right'>
|
||||
<Pagination
|
||||
totalPages={pagination ? pagination.TotalPages : ''}
|
||||
activePage={state.currentPageNumber}
|
||||
onPageChange={onPageChange}
|
||||
size='mini'
|
||||
/>
|
||||
</Grid.Column>
|
||||
</Grid.Row>
|
||||
</Grid>
|
||||
</Table.HeaderCell>
|
||||
</Table.Row>
|
||||
</Table.Footer>
|
||||
</Table>
|
||||
)}
|
||||
</Grid.Column>
|
||||
</Grid.Row>
|
||||
</Grid>
|
||||
<NewSeasonModal
|
||||
isModalOpen={state.isModalOpen}
|
||||
onCloseModal={onIsModalOpen}
|
||||
/>
|
||||
</React.Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
export default Seasons;
|
||||
58
app/src/components/seasons/reducer.ts
Normal file
58
app/src/components/seasons/reducer.ts
Normal file
@@ -0,0 +1,58 @@
|
||||
import { ISeasonsState } from './ISeasonsState';
|
||||
import { ISeason } from '../../models/ISeason';
|
||||
|
||||
export type Action =
|
||||
| { type: 'SET_ITEMS'; payload: ISeason[] }
|
||||
| { type: 'SET_CURRENT_PAGE_NUMBER'; payload: number }
|
||||
| { type: 'SET_PAGE_SIZE'; payload: number }
|
||||
| { type: 'SET_IS_PANEL_OPEN'; payload: boolean }
|
||||
| { type: 'SET_IS_MODAL_OPEN'; payload: boolean };
|
||||
|
||||
export const initialState: ISeasonsState = {
|
||||
items: [],
|
||||
currentPageNumber: 1,
|
||||
pageSize: 10,
|
||||
isPanelOpen: false,
|
||||
isModalOpen: false,
|
||||
};
|
||||
|
||||
export const reducer = (
|
||||
state: ISeasonsState,
|
||||
action: Action
|
||||
): ISeasonsState => {
|
||||
switch (action.type) {
|
||||
case 'SET_ITEMS': {
|
||||
return {
|
||||
...state,
|
||||
items: action.payload
|
||||
};
|
||||
}
|
||||
case 'SET_CURRENT_PAGE_NUMBER': {
|
||||
return {
|
||||
...state,
|
||||
currentPageNumber: action.payload
|
||||
};
|
||||
}
|
||||
case 'SET_PAGE_SIZE': {
|
||||
return {
|
||||
...state,
|
||||
pageSize: action.payload
|
||||
};
|
||||
}
|
||||
case 'SET_IS_PANEL_OPEN': {
|
||||
return {
|
||||
...state,
|
||||
isPanelOpen: action.payload
|
||||
};
|
||||
}
|
||||
case 'SET_IS_MODAL_OPEN': {
|
||||
return {
|
||||
...state,
|
||||
isModalOpen: action.payload
|
||||
}
|
||||
}
|
||||
default: {
|
||||
return state;
|
||||
}
|
||||
}
|
||||
};
|
||||
8
app/src/components/sports/ISportsState.ts
Normal file
8
app/src/components/sports/ISportsState.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { ISport } from '../../models/ISport';
|
||||
|
||||
export interface ISportsState {
|
||||
items: ISport[];
|
||||
currentPageNumber: number;
|
||||
pageSize: number;
|
||||
isPanelOpen: boolean;
|
||||
}
|
||||
172
app/src/components/sports/Sports.tsx
Normal file
172
app/src/components/sports/Sports.tsx
Normal file
@@ -0,0 +1,172 @@
|
||||
import React, { SyntheticEvent, useEffect, useReducer } from 'react';
|
||||
import { useQuery } from '@apollo/client';
|
||||
import { MessageBar, MessageBarType } from '@fluentui/react/lib/MessageBar';
|
||||
import { initialState, reducer } from './reducer';
|
||||
import { useAppContext } from '../../hooks/appContext/UseAppContext';
|
||||
import { useSidebarContext } from '../../hooks/sidebarContext/UseSidebarContext';
|
||||
import { GET_SPORTS } from '../../constants/graphQL';
|
||||
import { INotification } from '../../models/INotification';
|
||||
import {
|
||||
Button,
|
||||
Grid,
|
||||
Header,
|
||||
Icon,
|
||||
Loader,
|
||||
Pagination,
|
||||
Sidebar,
|
||||
Table
|
||||
} from 'semantic-ui-react';
|
||||
// import VenueDetails from '../venueDetails/VenueDetails';
|
||||
import { usePagination } from '../../hooks/usePaginiation/UsePagination';
|
||||
|
||||
const Sports: React.FC<unknown> = () => {
|
||||
const [state, dispatch] = useReducer(reducer, initialState);
|
||||
const appContext = useAppContext();
|
||||
const sidebarContext = useSidebarContext();
|
||||
const currentPageNumber = state.currentPageNumber;
|
||||
const pageSize = state.pageSize;
|
||||
const { data, loading, error, refetch } = useQuery(GET_SPORTS, {
|
||||
variables: {
|
||||
pageNumber: currentPageNumber,
|
||||
pageSize: pageSize
|
||||
}
|
||||
});
|
||||
const { pagination } = usePagination();
|
||||
|
||||
const columns: string[] = ['Name', ''];
|
||||
|
||||
const onDismissMessageBar = () => {
|
||||
const notification: INotification = {
|
||||
...appContext.state.notification,
|
||||
isVisible: false
|
||||
};
|
||||
|
||||
appContext.dispatch({ type: 'SET_NOTIFICATION', payload: notification });
|
||||
};
|
||||
|
||||
const onPageChange = (event: SyntheticEvent, data: any) => {
|
||||
const newCurrentPage: number = data.activePage;
|
||||
|
||||
dispatch({ type: 'SET_CURRENT_PAGE_NUMBER', payload: newCurrentPage });
|
||||
};
|
||||
|
||||
const onDetails = (id: number) => {
|
||||
// sidebarContext.dispatch({
|
||||
// type: 'SET_SIDEBAR',
|
||||
// payload: {
|
||||
// sidebar: {
|
||||
// visible: true,
|
||||
// animation: 'overlay',
|
||||
// width: 'very wide',
|
||||
// direction: 'right'
|
||||
// },
|
||||
// content: <VenueDetails venueId={id} />
|
||||
// }
|
||||
// });
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (data) {
|
||||
dispatch({
|
||||
type: 'SET_ITEMS',
|
||||
payload: data.sports
|
||||
});
|
||||
}
|
||||
}, [data]);
|
||||
|
||||
useEffect(() => {
|
||||
// console.log(error);
|
||||
const notification: INotification = {
|
||||
messageBarType: MessageBarType.error,
|
||||
message: error?.message,
|
||||
isMultiline: false,
|
||||
isVisible: false
|
||||
};
|
||||
|
||||
appContext.dispatch({ type: 'SET_NOTIFICATION', payload: notification });
|
||||
}, [error]);
|
||||
|
||||
useEffect(() => {
|
||||
refetch({
|
||||
pageNumber: currentPageNumber,
|
||||
pageSize: pageSize
|
||||
});
|
||||
}, [currentPageNumber]);
|
||||
|
||||
return (
|
||||
<Grid columns={1}>
|
||||
<Grid.Row>
|
||||
<Header as='h1'>Sports</Header>
|
||||
</Grid.Row>
|
||||
{appContext.state.notification?.isVisible && (
|
||||
<Grid.Row>
|
||||
<Grid.Column>
|
||||
<MessageBar
|
||||
messageBarType={appContext.state.notification?.messageBarType}
|
||||
isMultiline={appContext.state.notification?.isMultiline}
|
||||
onDismiss={onDismissMessageBar}
|
||||
>
|
||||
{appContext.state.notification?.message}
|
||||
</MessageBar>
|
||||
</Grid.Column>
|
||||
</Grid.Row>
|
||||
)}
|
||||
<Grid.Row>
|
||||
<Grid.Column>
|
||||
{loading && (
|
||||
<Loader size='massive' active={loading}>
|
||||
Loading...
|
||||
</Loader>
|
||||
)}
|
||||
{!loading && (
|
||||
<Table selectable>
|
||||
<Table.Header>
|
||||
<Table.Row>
|
||||
{columns.map((column: string, index: number) => {
|
||||
return (
|
||||
<Table.HeaderCell key={index}>{column}</Table.HeaderCell>
|
||||
);
|
||||
})}
|
||||
</Table.Row>
|
||||
</Table.Header>
|
||||
<Table.Body>
|
||||
{state.items.map((item) => {
|
||||
return (
|
||||
<Table.Row key={item.id}>
|
||||
<Table.Cell>{item.name}</Table.Cell>
|
||||
<Table.Cell textAlign='right'>
|
||||
<Button basic icon onClick={() => onDetails(item.id)}>
|
||||
<Icon name='info circle' />
|
||||
</Button>
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
);
|
||||
})}
|
||||
</Table.Body>
|
||||
<Table.Footer>
|
||||
<Table.Row>
|
||||
<Table.HeaderCell colSpan='2'>
|
||||
<Grid columns={1}>
|
||||
<Grid.Row>
|
||||
<Grid.Column textAlign='right'>
|
||||
<Pagination
|
||||
totalPages={pagination ? pagination.TotalPages : ''}
|
||||
activePage={state.currentPageNumber}
|
||||
onPageChange={onPageChange}
|
||||
size='mini'
|
||||
/>
|
||||
</Grid.Column>
|
||||
</Grid.Row>
|
||||
</Grid>
|
||||
</Table.HeaderCell>
|
||||
</Table.Row>
|
||||
</Table.Footer>
|
||||
</Table>
|
||||
)}
|
||||
</Grid.Column>
|
||||
</Grid.Row>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
|
||||
export default Sports;
|
||||
50
app/src/components/sports/reducer.ts
Normal file
50
app/src/components/sports/reducer.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
import { ISportsState } from './ISportsState';
|
||||
import { ISport } from '../../models/ISport';
|
||||
|
||||
export type Action =
|
||||
| { type: 'SET_ITEMS'; payload: ISport[] }
|
||||
| { type: 'SET_CURRENT_PAGE_NUMBER'; payload: number }
|
||||
| { type: 'SET_PAGE_SIZE'; payload: number }
|
||||
| { type: 'SET_IS_PANEL_OPEN'; payload: boolean };
|
||||
|
||||
export const initialState: ISportsState = {
|
||||
items: [],
|
||||
currentPageNumber: 1,
|
||||
pageSize: 10,
|
||||
isPanelOpen: false
|
||||
};
|
||||
|
||||
export const reducer = (
|
||||
state: ISportsState,
|
||||
action: Action
|
||||
): ISportsState => {
|
||||
switch (action.type) {
|
||||
case 'SET_ITEMS': {
|
||||
return {
|
||||
...state,
|
||||
items: action.payload
|
||||
};
|
||||
}
|
||||
case 'SET_CURRENT_PAGE_NUMBER': {
|
||||
return {
|
||||
...state,
|
||||
currentPageNumber: action.payload
|
||||
};
|
||||
}
|
||||
case 'SET_PAGE_SIZE': {
|
||||
return {
|
||||
...state,
|
||||
pageSize: action.payload
|
||||
};
|
||||
}
|
||||
case 'SET_IS_PANEL_OPEN': {
|
||||
return {
|
||||
...state,
|
||||
isPanelOpen: action.payload
|
||||
};
|
||||
}
|
||||
default: {
|
||||
return state;
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1,13 +1,9 @@
|
||||
import { ICommandBarItemProps } from "@fluentui/react/lib/CommandBar";
|
||||
import { ICommandBarItemProps } from '@fluentui/react/lib/CommandBar';
|
||||
import { ITeam } from '../../models/ITeam';
|
||||
|
||||
export interface ITeamsState {
|
||||
items: ITeam[];
|
||||
totalItemCount: number | null;
|
||||
totalPageCount: number | null;
|
||||
currentPageNumber: number;
|
||||
pageSize: number;
|
||||
selectedItems: ITeam[];
|
||||
commandBarItems: ICommandBarItemProps[];
|
||||
isPanelOpen: boolean;
|
||||
}
|
||||
items: ITeam[];
|
||||
currentPageNumber: number;
|
||||
pageSize: number;
|
||||
isPanelOpen: boolean;
|
||||
}
|
||||
|
||||
@@ -1,135 +1,124 @@
|
||||
import React, { SyntheticEvent, useEffect, useReducer } from 'react';
|
||||
import { useQuery } from '@apollo/client';
|
||||
import { MessageBar, MessageBarType } from '@fluentui/react/lib/MessageBar';
|
||||
import { initialState, reducer } from './reducer'
|
||||
import { initialState, reducer } from './reducer';
|
||||
import { useAppContext } from '../../hooks/appContext/UseAppContext';
|
||||
import { useSidebarContext } from '../../hooks/sidebarContext/UseSidebarContext';
|
||||
import { GET_TEAMS } from '../../constants/graphQL';
|
||||
import { INotification } from '../../models/INotification';
|
||||
import { Button, Grid, Header, Icon, Loader, Pagination, Table } from 'semantic-ui-react'
|
||||
import {
|
||||
Button,
|
||||
Grid,
|
||||
Header,
|
||||
Icon,
|
||||
Loader,
|
||||
Pagination,
|
||||
Table
|
||||
} from 'semantic-ui-react';
|
||||
import { usePagination } from '../../hooks/usePaginiation/UsePagination';
|
||||
|
||||
const Teams: React.FC<unknown> = () => {
|
||||
const [state, dispatch] = useReducer(reducer, initialState);
|
||||
const appContext = useAppContext();
|
||||
const sidebarContext = useSidebarContext();
|
||||
const currentPageNumber = state.currentPageNumber;
|
||||
const pageSize = state.pageSize;
|
||||
const { data, loading, error, refetch } = useQuery(GET_TEAMS, {
|
||||
variables: {
|
||||
pageNumber: currentPageNumber,
|
||||
pageSize: pageSize
|
||||
}
|
||||
})
|
||||
|
||||
const columns: string[] = [
|
||||
'Name',
|
||||
''
|
||||
]
|
||||
|
||||
const onPageChange = (event: SyntheticEvent, data: any) => {
|
||||
const newCurrentPage: number = data.activePage;
|
||||
|
||||
dispatch({ type: 'SET_CURRENT_PAGE_NUMBER', payload: newCurrentPage });
|
||||
const [state, dispatch] = useReducer(reducer, initialState);
|
||||
const appContext = useAppContext();
|
||||
const sidebarContext = useSidebarContext();
|
||||
const currentPageNumber = state.currentPageNumber;
|
||||
const pageSize = state.pageSize;
|
||||
const { data, loading, error, refetch } = useQuery(GET_TEAMS, {
|
||||
variables: {
|
||||
pageNumber: currentPageNumber,
|
||||
pageSize: pageSize
|
||||
}
|
||||
});
|
||||
const { pagination } = usePagination();
|
||||
|
||||
useEffect(() => {
|
||||
if (data) {
|
||||
dispatch({
|
||||
type: 'SET_ITEMS',
|
||||
payload: {
|
||||
items: data.teams.results,
|
||||
totalItemCount: data.teams.totalItemCount,
|
||||
totalPageCount: data.teams.totalPageCount
|
||||
}
|
||||
})
|
||||
}
|
||||
}, [data])
|
||||
const columns: string[] = ['Name', ''];
|
||||
|
||||
useEffect(() => {
|
||||
refetch({
|
||||
pageNumber: currentPageNumber,
|
||||
pageSize: pageSize
|
||||
})
|
||||
}, [currentPageNumber])
|
||||
const onPageChange = (event: SyntheticEvent, data: any) => {
|
||||
const newCurrentPage: number = data.activePage;
|
||||
|
||||
return (
|
||||
<Grid columns={1}>
|
||||
<Grid.Row>
|
||||
<Header as='h1'>
|
||||
Teams
|
||||
</Header>
|
||||
</Grid.Row>
|
||||
{appContext.state.notification?.isVisible && (
|
||||
<Grid.Row>
|
||||
<Grid.Column>
|
||||
|
||||
</Grid.Column>
|
||||
</Grid.Row>
|
||||
)}
|
||||
<Grid.Row>
|
||||
<Grid.Column>
|
||||
{loading && (
|
||||
<Loader size='massive' active={loading}>Loading...</Loader>
|
||||
)}
|
||||
{!loading &&
|
||||
<Table selectable>
|
||||
<Table.Header>
|
||||
<Table.Row>
|
||||
{columns.map((column: string) => {
|
||||
return (
|
||||
<Table.HeaderCell>
|
||||
{column}
|
||||
</Table.HeaderCell>
|
||||
)
|
||||
})}
|
||||
</Table.Row>
|
||||
</Table.Header>
|
||||
<Table.Body>
|
||||
{state.items.map((item) => {
|
||||
return (
|
||||
<Table.Row
|
||||
key={item.id}
|
||||
>
|
||||
<Table.Cell>
|
||||
{item.name}
|
||||
</Table.Cell>
|
||||
<Table.Cell textAlign='right'>
|
||||
<Button
|
||||
basic
|
||||
icon
|
||||
// onClick={() => onDetails(item.id)}
|
||||
>
|
||||
<Icon name='info circle' />
|
||||
</Button>
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
)
|
||||
})}
|
||||
</Table.Body>
|
||||
<Table.Footer>
|
||||
<Table.Row>
|
||||
<Table.HeaderCell colSpan='2'>
|
||||
<Grid columns={1}>
|
||||
<Grid.Row>
|
||||
<Grid.Column textAlign='right'>
|
||||
<Pagination
|
||||
totalPages={data.teams.totalPageCount}
|
||||
activePage={state.currentPageNumber}
|
||||
onPageChange={onPageChange}
|
||||
size='mini'
|
||||
/>
|
||||
</Grid.Column>
|
||||
</Grid.Row>
|
||||
</Grid>
|
||||
</Table.HeaderCell>
|
||||
</Table.Row>
|
||||
</Table.Footer>
|
||||
</Table>
|
||||
}
|
||||
</Grid.Column>
|
||||
</Grid.Row>
|
||||
</Grid>
|
||||
)
|
||||
}
|
||||
dispatch({ type: 'SET_CURRENT_PAGE_NUMBER', payload: newCurrentPage });
|
||||
};
|
||||
|
||||
export default Teams;
|
||||
useEffect(() => {
|
||||
if (data) {
|
||||
dispatch({ type: 'SET_ITEMS', payload: data.teams });
|
||||
}
|
||||
}, [data]);
|
||||
|
||||
useEffect(() => {
|
||||
refetch({
|
||||
pageNumber: currentPageNumber,
|
||||
pageSize: pageSize
|
||||
});
|
||||
}, [currentPageNumber]);
|
||||
|
||||
return (
|
||||
<Grid columns={1}>
|
||||
<Grid.Row>
|
||||
<Header as='h1'>Teams</Header>
|
||||
</Grid.Row>
|
||||
{appContext.state.notification?.isVisible && (
|
||||
<Grid.Row>
|
||||
<Grid.Column></Grid.Column>
|
||||
</Grid.Row>
|
||||
)}
|
||||
<Grid.Row>
|
||||
<Grid.Column>
|
||||
{loading && (
|
||||
<Loader size='massive' active={loading}>
|
||||
Loading...
|
||||
</Loader>
|
||||
)}
|
||||
{!loading && (
|
||||
<Table selectable>
|
||||
<Table.Header>
|
||||
<Table.Row>
|
||||
{columns.map((column: string) => {
|
||||
return <Table.HeaderCell>{column}</Table.HeaderCell>;
|
||||
})}
|
||||
</Table.Row>
|
||||
</Table.Header>
|
||||
<Table.Body>
|
||||
{state.items.map((item) => {
|
||||
return (
|
||||
<Table.Row key={item.id}>
|
||||
<Table.Cell>{item.name}</Table.Cell>
|
||||
<Table.Cell textAlign='right'>
|
||||
<Button
|
||||
basic
|
||||
icon
|
||||
// onClick={() => onDetails(item.id)}
|
||||
>
|
||||
<Icon name='info circle' />
|
||||
</Button>
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
);
|
||||
})}
|
||||
</Table.Body>
|
||||
<Table.Footer>
|
||||
<Table.Row>
|
||||
<Table.HeaderCell colSpan='2'>
|
||||
<Grid columns={1}>
|
||||
<Grid.Row>
|
||||
<Grid.Column textAlign='right'>
|
||||
<Pagination
|
||||
totalPages={pagination ? pagination.TotalPages : ''}
|
||||
activePage={state.currentPageNumber}
|
||||
onPageChange={onPageChange}
|
||||
size='mini'
|
||||
/>
|
||||
</Grid.Column>
|
||||
</Grid.Row>
|
||||
</Grid>
|
||||
</Table.HeaderCell>
|
||||
</Table.Row>
|
||||
</Table.Footer>
|
||||
</Table>
|
||||
)}
|
||||
</Grid.Column>
|
||||
</Grid.Row>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
|
||||
export default Teams;
|
||||
|
||||
@@ -1,73 +1,47 @@
|
||||
import { ITeamsState } from './ITeamsState';
|
||||
import { ITeam } from '../../models/ITeam';
|
||||
import { ICommandBarItemProps } from '@fluentui/react/lib/CommandBar';
|
||||
import { IObjectWithKey } from '@fluentui/react';
|
||||
|
||||
export type Action =
|
||||
| {
|
||||
type: 'SET_ITEMS';
|
||||
payload: {
|
||||
items: ITeam[];
|
||||
totalItemCount: number;
|
||||
totalPageCount: number;
|
||||
};
|
||||
}
|
||||
| { type: 'SET_CURRENT_PAGE_NUMBER'; payload: number }
|
||||
| { type: 'SET_PAGE_SIZE'; payload: number }
|
||||
| { type: 'SET_SELECTED_ITEM'; payload: IObjectWithKey[] }
|
||||
| { type: 'SET_COMMAND_BAR_ITEMS'; payload: ICommandBarItemProps[] }
|
||||
| { type: 'SET_IS_PANEL_OPEN'; payload: boolean };
|
||||
| { type: 'SET_ITEMS'; payload: ITeam[] }
|
||||
| { type: 'SET_CURRENT_PAGE_NUMBER'; payload: number }
|
||||
| { type: 'SET_PAGE_SIZE'; payload: number }
|
||||
| { type: 'SET_IS_PANEL_OPEN'; payload: boolean };
|
||||
|
||||
export const initialState: ITeamsState = {
|
||||
items: [],
|
||||
totalItemCount: null,
|
||||
totalPageCount: null,
|
||||
currentPageNumber: 1,
|
||||
pageSize: 10,
|
||||
selectedItems: [],
|
||||
commandBarItems: [],
|
||||
isPanelOpen: false
|
||||
}
|
||||
items: [],
|
||||
currentPageNumber: 1,
|
||||
pageSize: 10,
|
||||
isPanelOpen: false
|
||||
};
|
||||
|
||||
export const reducer = (state: ITeamsState, action: Action): ITeamsState => {
|
||||
switch (action.type) {
|
||||
case 'SET_ITEMS': {
|
||||
return {
|
||||
...state,
|
||||
items: action.payload.items,
|
||||
totalItemCount: action.payload.totalItemCount,
|
||||
totalPageCount: action.payload.totalPageCount
|
||||
};
|
||||
}
|
||||
case 'SET_CURRENT_PAGE_NUMBER': {
|
||||
return {
|
||||
...state,
|
||||
currentPageNumber: action.payload
|
||||
};
|
||||
}
|
||||
case 'SET_PAGE_SIZE': {
|
||||
return {
|
||||
...state,
|
||||
pageSize: action.payload
|
||||
};
|
||||
}
|
||||
case 'SET_SELECTED_ITEM': {
|
||||
return {
|
||||
...state,
|
||||
selectedItems: <ITeam[]>action.payload
|
||||
};
|
||||
}
|
||||
case 'SET_COMMAND_BAR_ITEMS': {
|
||||
return {
|
||||
...state,
|
||||
commandBarItems: action.payload
|
||||
};
|
||||
}
|
||||
case 'SET_IS_PANEL_OPEN': {
|
||||
return {
|
||||
...state,
|
||||
isPanelOpen: action.payload
|
||||
};
|
||||
}
|
||||
switch (action.type) {
|
||||
case 'SET_ITEMS': {
|
||||
return {
|
||||
...state,
|
||||
items: action.payload
|
||||
};
|
||||
}
|
||||
}
|
||||
case 'SET_CURRENT_PAGE_NUMBER': {
|
||||
return {
|
||||
...state,
|
||||
currentPageNumber: action.payload
|
||||
};
|
||||
}
|
||||
case 'SET_PAGE_SIZE': {
|
||||
return {
|
||||
...state,
|
||||
pageSize: action.payload
|
||||
};
|
||||
}
|
||||
case 'SET_IS_PANEL_OPEN': {
|
||||
return {
|
||||
...state,
|
||||
isPanelOpen: action.payload
|
||||
};
|
||||
}
|
||||
default: {
|
||||
return state;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
export interface IVenueDetailsProps {
|
||||
venueId: number;
|
||||
}
|
||||
venueId: number;
|
||||
}
|
||||
|
||||
@@ -2,32 +2,32 @@ import React, { useEffect } from 'react';
|
||||
import { IVenueDetailsProps } from './IVenueDetailsProps';
|
||||
import { Grid, Header } from 'semantic-ui-react';
|
||||
import { useQuery } from '@apollo/client';
|
||||
import { GET_VENUE_BY_ID } from '../../constants/graphQL';
|
||||
import { GET_VENUE } from '../../constants/graphQL';
|
||||
|
||||
const VenueDetails: React.FC<IVenueDetailsProps> = ({ venueId }: IVenueDetailsProps) => {
|
||||
const { data, loading, error } = useQuery(GET_VENUE_BY_ID, {
|
||||
variables: {
|
||||
id: venueId
|
||||
}
|
||||
});
|
||||
const VenueDetails: React.FC<IVenueDetailsProps> = ({
|
||||
venueId
|
||||
}: IVenueDetailsProps) => {
|
||||
const { data, loading, error } = useQuery(GET_VENUE, {
|
||||
variables: {
|
||||
id: venueId
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<Grid>
|
||||
<Grid.Row>
|
||||
<Header as='h2'>
|
||||
Venue
|
||||
</Header>
|
||||
</Grid.Row>
|
||||
<Grid.Row>
|
||||
{data &&
|
||||
<ul>
|
||||
<li>{data.venueById.results.name}</li>
|
||||
<li>{data.venueById.results.id}</li>
|
||||
</ul>
|
||||
}
|
||||
</Grid.Row>
|
||||
</Grid>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<Grid>
|
||||
<Grid.Row>
|
||||
<Header as='h2'>Venue</Header>
|
||||
</Grid.Row>
|
||||
<Grid.Row>
|
||||
{data && (
|
||||
<ul>
|
||||
<li>{data.venueById.results.name}</li>
|
||||
<li>{data.venueById.results.id}</li>
|
||||
</ul>
|
||||
)}
|
||||
</Grid.Row>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
|
||||
export default VenueDetails;
|
||||
export default VenueDetails;
|
||||
|
||||
@@ -1,13 +1,8 @@
|
||||
import { ICommandBarItemProps } from '@fluentui/react/lib/CommandBar';
|
||||
import { IVenue } from '../../models/IVenue';
|
||||
|
||||
export interface IVenuesState {
|
||||
items: IVenue[];
|
||||
totalItemCount: number | null;
|
||||
totalPageCount: number | null;
|
||||
currentPageNumber: number;
|
||||
pageSize: number;
|
||||
selectedItems: IVenue[];
|
||||
commandBarItems: ICommandBarItemProps[];
|
||||
isPanelOpen: boolean;
|
||||
}
|
||||
|
||||
@@ -6,8 +6,18 @@ import { useAppContext } from '../../hooks/appContext/UseAppContext';
|
||||
import { useSidebarContext } from '../../hooks/sidebarContext/UseSidebarContext';
|
||||
import { GET_VENUES } from '../../constants/graphQL';
|
||||
import { INotification } from '../../models/INotification';
|
||||
import { Button, Grid, Header, Icon, Loader, Pagination, Sidebar, Table } from 'semantic-ui-react';
|
||||
import {
|
||||
Button,
|
||||
Grid,
|
||||
Header,
|
||||
Icon,
|
||||
Loader,
|
||||
Pagination,
|
||||
Sidebar,
|
||||
Table
|
||||
} from 'semantic-ui-react';
|
||||
import VenueDetails from '../venueDetails/VenueDetails';
|
||||
import { usePagination } from '../../hooks/usePaginiation/UsePagination';
|
||||
|
||||
const Venues: React.FC<unknown> = () => {
|
||||
const [state, dispatch] = useReducer(reducer, initialState);
|
||||
@@ -21,11 +31,9 @@ const Venues: React.FC<unknown> = () => {
|
||||
pageSize: pageSize
|
||||
}
|
||||
});
|
||||
const { pagination } = usePagination();
|
||||
|
||||
const columns: string[] = [
|
||||
'Name',
|
||||
''
|
||||
]
|
||||
const columns: string[] = ['Name', ''];
|
||||
|
||||
const onDismissMessageBar = () => {
|
||||
const notification: INotification = {
|
||||
@@ -43,28 +51,31 @@ const Venues: React.FC<unknown> = () => {
|
||||
};
|
||||
|
||||
const onDetails = (id: number) => {
|
||||
sidebarContext.dispatch({ type: 'SET_SIDEBAR', payload: { sidebar: { visible: true, animation: 'overlay', width: 'very wide', direction: 'right' }, content: <VenueDetails venueId={id} />}})
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
console.log(sidebarContext)
|
||||
}, [sidebarContext])
|
||||
sidebarContext.dispatch({
|
||||
type: 'SET_SIDEBAR',
|
||||
payload: {
|
||||
sidebar: {
|
||||
visible: true,
|
||||
animation: 'overlay',
|
||||
width: 'very wide',
|
||||
direction: 'right'
|
||||
},
|
||||
content: <VenueDetails venueId={id} />
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (data) {
|
||||
dispatch({
|
||||
type: 'SET_ITEMS',
|
||||
payload: {
|
||||
items: data.venues.results,
|
||||
totalItemCount: data.venues.totalItemCount,
|
||||
totalPageCount: data.venues.totalPageCount
|
||||
}
|
||||
payload: data.venues
|
||||
});
|
||||
}
|
||||
}, [data]);
|
||||
|
||||
useEffect(() => {
|
||||
console.log(error);
|
||||
// console.log(error);
|
||||
const notification: INotification = {
|
||||
messageBarType: MessageBarType.error,
|
||||
message: error?.message,
|
||||
@@ -80,66 +91,56 @@ const Venues: React.FC<unknown> = () => {
|
||||
pageNumber: currentPageNumber,
|
||||
pageSize: pageSize
|
||||
});
|
||||
}, [currentPageNumber])
|
||||
}, [currentPageNumber]);
|
||||
|
||||
return (
|
||||
<Grid columns={1}>
|
||||
<Grid.Row>
|
||||
<Header as='h1'>
|
||||
Venues
|
||||
</Header>
|
||||
<Header as='h1'>Venues</Header>
|
||||
</Grid.Row>
|
||||
{appContext.state.notification?.isVisible && (
|
||||
<Grid.Row>
|
||||
<Grid.Column>
|
||||
<MessageBar
|
||||
messageBarType={appContext.state.notification?.messageBarType}
|
||||
isMultiline={appContext.state.notification?.isMultiline}
|
||||
onDismiss={onDismissMessageBar}
|
||||
>
|
||||
{appContext.state.notification?.message}
|
||||
</MessageBar>
|
||||
<MessageBar
|
||||
messageBarType={appContext.state.notification?.messageBarType}
|
||||
isMultiline={appContext.state.notification?.isMultiline}
|
||||
onDismiss={onDismissMessageBar}
|
||||
>
|
||||
{appContext.state.notification?.message}
|
||||
</MessageBar>
|
||||
</Grid.Column>
|
||||
</Grid.Row>
|
||||
)}
|
||||
<Grid.Row>
|
||||
<Grid.Column>
|
||||
{loading && (
|
||||
<Loader size='massive' active={loading}>Loading...</Loader>
|
||||
<Loader size='massive' active={loading}>
|
||||
Loading...
|
||||
</Loader>
|
||||
)}
|
||||
{!loading &&
|
||||
{!loading && (
|
||||
<Table selectable>
|
||||
<Table.Header>
|
||||
<Table.Row>
|
||||
{columns.map((column: string) => {
|
||||
{columns.map((column: string, index: number) => {
|
||||
return (
|
||||
<Table.HeaderCell>
|
||||
{column}
|
||||
</Table.HeaderCell>
|
||||
)
|
||||
<Table.HeaderCell key={index}>{column}</Table.HeaderCell>
|
||||
);
|
||||
})}
|
||||
</Table.Row>
|
||||
</Table.Header>
|
||||
<Table.Body>
|
||||
{state.items.map((item) => {
|
||||
return (
|
||||
<Table.Row
|
||||
key={item.id}
|
||||
>
|
||||
<Table.Cell>
|
||||
{item.name}
|
||||
</Table.Cell>
|
||||
<Table.Row key={item.id}>
|
||||
<Table.Cell>{item.name}</Table.Cell>
|
||||
<Table.Cell textAlign='right'>
|
||||
<Button
|
||||
basic
|
||||
icon
|
||||
onClick={() => onDetails(item.id)}
|
||||
>
|
||||
<Button basic icon onClick={() => onDetails(item.id)}>
|
||||
<Icon name='info circle' />
|
||||
</Button>
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
)
|
||||
);
|
||||
})}
|
||||
</Table.Body>
|
||||
<Table.Footer>
|
||||
@@ -147,11 +148,9 @@ const Venues: React.FC<unknown> = () => {
|
||||
<Table.HeaderCell colSpan='2'>
|
||||
<Grid columns={1}>
|
||||
<Grid.Row>
|
||||
<Grid.Column
|
||||
textAlign='right'
|
||||
>
|
||||
<Grid.Column textAlign='right'>
|
||||
<Pagination
|
||||
totalPages={data?.venues?.totalPageCount}
|
||||
totalPages={pagination ? pagination.TotalPages : ''}
|
||||
activePage={state.currentPageNumber}
|
||||
onPageChange={onPageChange}
|
||||
size='mini'
|
||||
@@ -163,7 +162,7 @@ const Venues: React.FC<unknown> = () => {
|
||||
</Table.Row>
|
||||
</Table.Footer>
|
||||
</Table>
|
||||
}
|
||||
)}
|
||||
</Grid.Column>
|
||||
</Grid.Row>
|
||||
</Grid>
|
||||
|
||||
@@ -1,31 +1,16 @@
|
||||
import { IVenuesState } from './IVenuesState';
|
||||
import { IVenue } from '../../models/IVenue';
|
||||
import { ICommandBarItemProps } from '@fluentui/react/lib/CommandBar';
|
||||
import { IObjectWithKey } from '@fluentui/react';
|
||||
|
||||
export type Action =
|
||||
| {
|
||||
type: 'SET_ITEMS';
|
||||
payload: {
|
||||
items: IVenue[];
|
||||
totalItemCount: number;
|
||||
totalPageCount: number;
|
||||
};
|
||||
}
|
||||
| { type: 'SET_ITEMS'; payload: IVenue[] }
|
||||
| { type: 'SET_CURRENT_PAGE_NUMBER'; payload: number }
|
||||
| { type: 'SET_PAGE_SIZE'; payload: number }
|
||||
| { type: 'SET_SELECTED_ITEM'; payload: IObjectWithKey[] }
|
||||
| { type: 'SET_COMMAND_BAR_ITEMS'; payload: ICommandBarItemProps[] }
|
||||
| { type: 'SET_IS_PANEL_OPEN'; payload: boolean };
|
||||
|
||||
export const initialState: IVenuesState = {
|
||||
items: [],
|
||||
totalItemCount: null,
|
||||
totalPageCount: null,
|
||||
currentPageNumber: 1,
|
||||
pageSize: 10,
|
||||
selectedItems: [],
|
||||
commandBarItems: [],
|
||||
isPanelOpen: false
|
||||
};
|
||||
|
||||
@@ -34,9 +19,7 @@ export const reducer = (state: IVenuesState, action: Action): IVenuesState => {
|
||||
case 'SET_ITEMS': {
|
||||
return {
|
||||
...state,
|
||||
items: action.payload.items,
|
||||
totalItemCount: action.payload.totalItemCount,
|
||||
totalPageCount: action.payload.totalPageCount
|
||||
items: action.payload
|
||||
};
|
||||
}
|
||||
case 'SET_CURRENT_PAGE_NUMBER': {
|
||||
@@ -51,23 +34,14 @@ export const reducer = (state: IVenuesState, action: Action): IVenuesState => {
|
||||
pageSize: action.payload
|
||||
};
|
||||
}
|
||||
case 'SET_SELECTED_ITEM': {
|
||||
return {
|
||||
...state,
|
||||
selectedItems: <IVenue[]>action.payload
|
||||
};
|
||||
}
|
||||
case 'SET_COMMAND_BAR_ITEMS': {
|
||||
return {
|
||||
...state,
|
||||
commandBarItems: action.payload
|
||||
};
|
||||
}
|
||||
case 'SET_IS_PANEL_OPEN': {
|
||||
return {
|
||||
...state,
|
||||
isPanelOpen: action.payload
|
||||
};
|
||||
}
|
||||
default: {
|
||||
return state;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,73 +1,86 @@
|
||||
import { gql } from '@apollo/client';
|
||||
|
||||
export const GET_DIVISIONS = gql`
|
||||
query GetDivisions($pageNumber: Int!, $pageSize: Int!) {
|
||||
divisions(pageNumber: $pageNumber, pageSize: $pageSize) {
|
||||
name
|
||||
link
|
||||
id
|
||||
active
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const GET_LEAGUES = gql`
|
||||
query GetLeagues($pageNumber: Int!, $pageSize: Int!) {
|
||||
leagues(pageNumber: $pageNumber, pageSize: $pageSize) {
|
||||
name
|
||||
link
|
||||
id
|
||||
active
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const GET_SEASONS = gql`
|
||||
query GetSeasons($pageNumber: Int!, $pageSize: Int!) {
|
||||
seasons(pageNumber: $pageNumber, pageSize: $pageSize) {
|
||||
id
|
||||
active
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const GET_SPORTS = gql`
|
||||
query GetSports($pageNumber: Int!, $pageSize: Int!) {
|
||||
sports(pageNumber: $pageNumber, pageSize: $pageSize) {
|
||||
name
|
||||
link
|
||||
id
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const GET_TEAMS = gql`
|
||||
query GetTeams($pageNumber: Int!, $pageSize: Int!) {
|
||||
teams(pageNumber: $pageNumber, pageSize: $pageSize) {
|
||||
pageSize
|
||||
message
|
||||
errors
|
||||
currentPage
|
||||
totalPageCount
|
||||
totalItemCount
|
||||
succeeded
|
||||
results {
|
||||
name
|
||||
link
|
||||
id
|
||||
active
|
||||
}
|
||||
name
|
||||
link
|
||||
id
|
||||
active
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const GET_TEAM = gql`
|
||||
query GetTeam($id: Int!) {
|
||||
teamById(id: $id) {
|
||||
message
|
||||
errors
|
||||
succeeded
|
||||
results {
|
||||
name
|
||||
link
|
||||
id
|
||||
active
|
||||
}
|
||||
team(id: $id) {
|
||||
name
|
||||
link
|
||||
id
|
||||
active
|
||||
}
|
||||
}
|
||||
`
|
||||
`;
|
||||
|
||||
export const GET_VENUES = gql`
|
||||
query GetVenues($pageNumber: Int!, $pageSize: Int!) {
|
||||
venues(pageNumber: $pageNumber, pageSize: $pageSize) {
|
||||
pageSize
|
||||
message
|
||||
errors
|
||||
currentPage
|
||||
totalPageCount
|
||||
totalItemCount
|
||||
succeeded
|
||||
results {
|
||||
name
|
||||
link
|
||||
id
|
||||
active
|
||||
}
|
||||
name
|
||||
link
|
||||
id
|
||||
active
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const GET_VENUE_BY_ID = gql`
|
||||
export const GET_VENUE = gql`
|
||||
query GetVenue($id: Int!) {
|
||||
venueById(id: $id) {
|
||||
message
|
||||
errors
|
||||
succeeded
|
||||
results {
|
||||
name
|
||||
link
|
||||
id
|
||||
active
|
||||
}
|
||||
venue(id: $id) {
|
||||
name
|
||||
link
|
||||
id
|
||||
active
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import { IPagination } from 'src/models/IPagination';
|
||||
import { ISidebar } from 'src/models/ISidebar';
|
||||
import { INotification } from '../../models/INotification';
|
||||
|
||||
export interface IAppContextState {
|
||||
notification: INotification | undefined;
|
||||
isSidebarVisible: boolean;
|
||||
pagination: IPagination | undefined;
|
||||
}
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import { MessageBarType } from '@fluentui/react';
|
||||
import { IPagination } from 'src/models/IPagination';
|
||||
import { INotification } from '../../models/INotification';
|
||||
import { IAppContextState } from './IAppContextState';
|
||||
|
||||
export type Action =
|
||||
export type Action =
|
||||
| { type: 'SET_NOTIFICATION'; payload: INotification }
|
||||
| { type: 'SET_IS_SIDEBAR_VISIBLE', payload: boolean };
|
||||
| { type: 'SET_IS_SIDEBAR_VISIBLE'; payload: boolean }
|
||||
| { type: 'SET_PAGINATION'; payload: IPagination | undefined };
|
||||
|
||||
export const initialState: IAppContextState = {
|
||||
notification: {
|
||||
@@ -13,7 +15,8 @@ export const initialState: IAppContextState = {
|
||||
isMultiline: false,
|
||||
isVisible: true
|
||||
},
|
||||
isSidebarVisible: false
|
||||
isSidebarVisible: false,
|
||||
pagination: undefined
|
||||
};
|
||||
|
||||
export const reducer = (
|
||||
@@ -31,7 +34,13 @@ export const reducer = (
|
||||
return {
|
||||
...state,
|
||||
isSidebarVisible: action.payload
|
||||
}
|
||||
};
|
||||
}
|
||||
case 'SET_PAGINATION': {
|
||||
return {
|
||||
...state,
|
||||
pagination: action.payload
|
||||
};
|
||||
}
|
||||
default: {
|
||||
return state;
|
||||
|
||||
@@ -3,6 +3,6 @@ import { ISidebarContextState } from './ISidebarContextState';
|
||||
import { Action } from './reducer';
|
||||
|
||||
export interface ISidebarContextProps {
|
||||
state: ISidebarContextState;
|
||||
dispatch: React.Dispatch<Action>;
|
||||
}
|
||||
state: ISidebarContextState;
|
||||
dispatch: React.Dispatch<Action>;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React from "react";
|
||||
import React from 'react';
|
||||
|
||||
export interface ISidebarContextProviderProps {
|
||||
children: React.ReactNode;
|
||||
}
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import React from 'react';
|
||||
import { SidebarProps } from 'semantic-ui-react';
|
||||
|
||||
export interface ISidebarContextState {
|
||||
content: React.ReactNode;
|
||||
sidebar: SidebarProps;
|
||||
title: string;
|
||||
}
|
||||
content: React.ReactNode;
|
||||
sidebar: SidebarProps;
|
||||
title: string;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
.sidebar {
|
||||
background-color: #FFFFFF;
|
||||
padding: 30px;
|
||||
}
|
||||
background-color: #ffffff;
|
||||
padding: 30px;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Context, createContext } from 'react';
|
||||
import { ISidebarContextProps } from './ISidebarContextProps';
|
||||
|
||||
export const SidebarContext: Context<ISidebarContextProps> = createContext<ISidebarContextProps>({} as ISidebarContextProps);
|
||||
export const SidebarContext: Context<ISidebarContextProps> =
|
||||
createContext<ISidebarContextProps>({} as ISidebarContextProps);
|
||||
|
||||
@@ -1,53 +1,48 @@
|
||||
import React, { useEffect, useMemo, useReducer } from 'react';
|
||||
import styles from './Sidebar.module.scss';
|
||||
import { SidebarContext } from "./SidebarContext";
|
||||
import { SidebarContext } from './SidebarContext';
|
||||
import { ISidebarContextProps } from './ISidebarContextProps';
|
||||
import { ISidebarContextProviderProps } from './ISidebarContextProviderProps';
|
||||
import { initialState, reducer } from './reducer';
|
||||
import { Button, Grid, Icon, Sidebar } from 'semantic-ui-react';
|
||||
|
||||
const SidebarContextProvider: React.FC<ISidebarContextProviderProps> = (props: ISidebarContextProviderProps) => {
|
||||
const [state, dispatch] = useReducer(reducer, initialState);
|
||||
const contextValue: ISidebarContextProps = useMemo(() => {
|
||||
return {
|
||||
state,
|
||||
dispatch
|
||||
}
|
||||
}, [state, dispatch]);
|
||||
const SidebarContextProvider: React.FC<ISidebarContextProviderProps> = (
|
||||
props: ISidebarContextProviderProps
|
||||
) => {
|
||||
const [state, dispatch] = useReducer(reducer, initialState);
|
||||
const contextValue: ISidebarContextProps = useMemo(() => {
|
||||
return {
|
||||
state,
|
||||
dispatch
|
||||
};
|
||||
}, [state, dispatch]);
|
||||
|
||||
const onCloseSidebar = () => {
|
||||
dispatch({ type: 'SET_SIDEBAR_VISIBLE', payload: !state.sidebar?.visible });
|
||||
}
|
||||
const onCloseSidebar = () => {
|
||||
dispatch({ type: 'SET_SIDEBAR_VISIBLE', payload: !state.sidebar?.visible });
|
||||
};
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Sidebar
|
||||
className={styles.sidebar}
|
||||
{...state.sidebar}
|
||||
>
|
||||
<Grid columns={1}>
|
||||
<Grid.Row>
|
||||
<Grid.Column
|
||||
textAlign='right'
|
||||
>
|
||||
<Button>
|
||||
<Icon name='close' size='large' onClick={onCloseSidebar} />
|
||||
</Button>
|
||||
</Grid.Column>
|
||||
</Grid.Row>
|
||||
<Grid.Row>
|
||||
{state.content}
|
||||
</Grid.Row>
|
||||
<Grid.Row>
|
||||
<Button onClick={onCloseSidebar}>Close</Button>
|
||||
</Grid.Row>
|
||||
</Grid>
|
||||
</Sidebar>
|
||||
<SidebarContext.Provider value={contextValue}>
|
||||
{props.children}
|
||||
</SidebarContext.Provider>
|
||||
</React.Fragment>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Sidebar className={styles.sidebar} {...state.sidebar}>
|
||||
<Grid columns={1}>
|
||||
<Grid.Row>
|
||||
<Grid.Column textAlign='right'>
|
||||
<Button>
|
||||
<Icon name='close' size='large' onClick={onCloseSidebar} />
|
||||
</Button>
|
||||
</Grid.Column>
|
||||
</Grid.Row>
|
||||
<Grid.Row>{state.content}</Grid.Row>
|
||||
<Grid.Row>
|
||||
<Button onClick={onCloseSidebar}>Close</Button>
|
||||
</Grid.Row>
|
||||
</Grid>
|
||||
</Sidebar>
|
||||
<SidebarContext.Provider value={contextValue}>
|
||||
{props.children}
|
||||
</SidebarContext.Provider>
|
||||
</React.Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
export default SidebarContextProvider;
|
||||
export default SidebarContextProvider;
|
||||
|
||||
@@ -1,52 +1,58 @@
|
||||
import React from "react";
|
||||
import { SidebarProps } from "semantic-ui-react";
|
||||
import { ISidebarContextState } from "./ISidebarContextState";
|
||||
import React from 'react';
|
||||
import { SidebarProps } from 'semantic-ui-react';
|
||||
import { ISidebarContextState } from './ISidebarContextState';
|
||||
|
||||
export type Action =
|
||||
| { type: 'SET_SIDEBAR', payload: { sidebar: SidebarProps, content: React.ReactNode }}
|
||||
| { type: 'SET_SIDEBAR_PROPS', payload: SidebarProps}
|
||||
| { type: 'SET_SIDEBAR_CONTENT', payload: React.ReactNode }
|
||||
| { type: 'SET_SIDEBAR_VISIBLE', payload: boolean }
|
||||
export type Action =
|
||||
| {
|
||||
type: 'SET_SIDEBAR';
|
||||
payload: { sidebar: SidebarProps; content: React.ReactNode };
|
||||
}
|
||||
| { type: 'SET_SIDEBAR_PROPS'; payload: SidebarProps }
|
||||
| { type: 'SET_SIDEBAR_CONTENT'; payload: React.ReactNode }
|
||||
| { type: 'SET_SIDEBAR_VISIBLE'; payload: boolean };
|
||||
|
||||
export const initialState: ISidebarContextState = {
|
||||
sidebar: {
|
||||
visible: false
|
||||
},
|
||||
content: undefined
|
||||
}
|
||||
sidebar: {
|
||||
visible: false
|
||||
},
|
||||
content: undefined
|
||||
};
|
||||
|
||||
export const reducer = (state: ISidebarContextState, action: Action): ISidebarContextState => {
|
||||
switch (action.type) {
|
||||
case 'SET_SIDEBAR': {
|
||||
return {
|
||||
...state,
|
||||
sidebar: action.payload.sidebar,
|
||||
content: action.payload.content
|
||||
}
|
||||
}
|
||||
case 'SET_SIDEBAR_PROPS': {
|
||||
return {
|
||||
...state,
|
||||
sidebar: action.payload
|
||||
}
|
||||
}
|
||||
case 'SET_SIDEBAR_CONTENT': {
|
||||
return {
|
||||
...state,
|
||||
content: action.payload
|
||||
}
|
||||
}
|
||||
case 'SET_SIDEBAR_VISIBLE': {
|
||||
return {
|
||||
...state,
|
||||
sidebar: {
|
||||
...state.sidebar,
|
||||
visible: action.payload
|
||||
}
|
||||
}
|
||||
}
|
||||
default: {
|
||||
return state;
|
||||
}
|
||||
export const reducer = (
|
||||
state: ISidebarContextState,
|
||||
action: Action
|
||||
): ISidebarContextState => {
|
||||
switch (action.type) {
|
||||
case 'SET_SIDEBAR': {
|
||||
return {
|
||||
...state,
|
||||
sidebar: action.payload.sidebar,
|
||||
content: action.payload.content
|
||||
};
|
||||
}
|
||||
}
|
||||
case 'SET_SIDEBAR_PROPS': {
|
||||
return {
|
||||
...state,
|
||||
sidebar: action.payload
|
||||
};
|
||||
}
|
||||
case 'SET_SIDEBAR_CONTENT': {
|
||||
return {
|
||||
...state,
|
||||
content: action.payload
|
||||
};
|
||||
}
|
||||
case 'SET_SIDEBAR_VISIBLE': {
|
||||
return {
|
||||
...state,
|
||||
sidebar: {
|
||||
...state.sidebar,
|
||||
visible: action.payload
|
||||
}
|
||||
};
|
||||
}
|
||||
default: {
|
||||
return state;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2,10 +2,10 @@ import { useContext } from 'react';
|
||||
import { SidebarContext } from '../../context/sidebar/SidebarContext';
|
||||
|
||||
export const useSidebarContext = () => {
|
||||
const { state, dispatch } = useContext(SidebarContext);
|
||||
const { state, dispatch } = useContext(SidebarContext);
|
||||
|
||||
return {
|
||||
state,
|
||||
dispatch
|
||||
}
|
||||
}
|
||||
return {
|
||||
state,
|
||||
dispatch
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
export interface IUsePaginationProps {
|
||||
totalCount: number;
|
||||
pageSize: number;
|
||||
siblingCount: number;
|
||||
currentPage: number;
|
||||
}
|
||||
@@ -1,71 +1,45 @@
|
||||
import { useMemo } from 'react';
|
||||
import { IUsePaginationProps } from './IUsePaginationProps';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useAppContext } from '../appContext/UseAppContext';
|
||||
import { IPagination } from '../../models/IPagination';
|
||||
|
||||
export const DOTS = '...';
|
||||
export const usePagination = () => {
|
||||
const [pagination, setPagination] = useState<IPagination | null>(null);
|
||||
|
||||
const range = (start: number, end: number) => {
|
||||
const length = end - start + 1;
|
||||
return Array.from({ length }, (_, idx) => idx + start);
|
||||
};
|
||||
|
||||
export const usePagination = ({
|
||||
totalCount,
|
||||
pageSize,
|
||||
siblingCount = 1,
|
||||
currentPage
|
||||
}: IUsePaginationProps) => {
|
||||
const paginationRange = useMemo(() => {
|
||||
const totalPageCount = Math.ceil(totalCount / pageSize);
|
||||
|
||||
// Pages count is determined as siblingCount + firstPage + lastPage + currentPage + 2*DOTS
|
||||
const totalPageNumbers = siblingCount + 5;
|
||||
|
||||
/*
|
||||
If the number of pages is less than the page numbers we want to show in our
|
||||
paginationComponent, we return the range [1..totalPageCount]
|
||||
*/
|
||||
if (totalPageNumbers >= totalPageCount) {
|
||||
return range(1, totalPageCount);
|
||||
}
|
||||
|
||||
const leftSiblingIndex = Math.max(currentPage - siblingCount, 1);
|
||||
const rightSiblingIndex = Math.min(
|
||||
currentPage + siblingCount,
|
||||
totalPageCount
|
||||
);
|
||||
|
||||
/*
|
||||
We do not want to show dots if there is only one position left
|
||||
after/before the left/right page count as that would lead to a change if our Pagination
|
||||
component size which we do not want
|
||||
*/
|
||||
const shouldShowLeftDots = leftSiblingIndex > 2;
|
||||
const shouldShowRightDots = rightSiblingIndex < totalPageCount - 2;
|
||||
|
||||
const firstPageIndex = 1;
|
||||
const lastPageIndex = totalPageCount;
|
||||
|
||||
if (!shouldShowLeftDots && shouldShowRightDots) {
|
||||
const leftItemCount = 3 + 2 * siblingCount;
|
||||
const leftRange = range(1, leftItemCount);
|
||||
|
||||
return [...leftRange, DOTS, totalPageCount];
|
||||
}
|
||||
|
||||
if (shouldShowLeftDots && !shouldShowRightDots) {
|
||||
const rightItemCount = 3 + 2 * siblingCount;
|
||||
const rightRange = range(
|
||||
totalPageCount - rightItemCount + 1,
|
||||
totalPageCount
|
||||
);
|
||||
return [firstPageIndex, DOTS, ...rightRange];
|
||||
}
|
||||
|
||||
if (shouldShowLeftDots && shouldShowRightDots) {
|
||||
const middleRange = range(leftSiblingIndex, rightSiblingIndex);
|
||||
return [firstPageIndex, DOTS, ...middleRange, DOTS, lastPageIndex];
|
||||
}
|
||||
}, [totalCount, pageSize, siblingCount, currentPage]);
|
||||
|
||||
return paginationRange;
|
||||
const getStoredValue = (): IPagination | null => {
|
||||
const storedPagination: string | null =
|
||||
sessionStorage.getItem('pagination');
|
||||
console.log(storedPagination);
|
||||
let pagination: IPagination;
|
||||
|
||||
if (storedPagination) {
|
||||
return (pagination = JSON.parse(storedPagination));
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
const removeStoredValue = () => {
|
||||
sessionStorage.removeItem('pagination');
|
||||
console.log('blah');
|
||||
};
|
||||
|
||||
const onSessionStorageChanged = () => {
|
||||
setPagination(getStoredValue());
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setPagination(getStoredValue());
|
||||
|
||||
window.addEventListener('storage', onSessionStorageChanged);
|
||||
|
||||
return () => {
|
||||
console.log('blah');
|
||||
window.removeEventListener('storage', onSessionStorageChanged);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return {
|
||||
pagination,
|
||||
removeStoredValue
|
||||
};
|
||||
};
|
||||
|
||||
24
app/src/hooks/useSessionStorage/UseSessionStorage.tsx
Normal file
24
app/src/hooks/useSessionStorage/UseSessionStorage.tsx
Normal file
@@ -0,0 +1,24 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { IPagination } from '../../models/IPagination';
|
||||
|
||||
export const useSessionStorage = (key: string) => {
|
||||
const [storedValue, setStoredValue] = useState<IPagination>(
|
||||
JSON.parse(sessionStorage.getItem(key) || '')
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const onStorage = () => {
|
||||
setStoredValue(JSON.parse(sessionStorage.getItem(key) || ''));
|
||||
};
|
||||
|
||||
window.addEventListener('storage', onStorage);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('storage', onStorage);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return {
|
||||
storedValue
|
||||
};
|
||||
};
|
||||
@@ -1,14 +1,44 @@
|
||||
import React from 'react';
|
||||
import { createRoot, Root } from 'react-dom/client';
|
||||
import { BrowserRouter as Router } from 'react-router-dom';
|
||||
import { ApolloClient, InMemoryCache, ApolloProvider, NormalizedCacheObject } from '@apollo/client';
|
||||
import {
|
||||
ApolloClient,
|
||||
InMemoryCache,
|
||||
ApolloProvider,
|
||||
NormalizedCacheObject,
|
||||
HttpLink,
|
||||
from,
|
||||
ApolloLink
|
||||
} from '@apollo/client';
|
||||
import AppContextProvider from './context/app/AppContextProvider';
|
||||
import App from './components/app/App';
|
||||
import 'semantic-ui-css/semantic.min.css';
|
||||
import SidebarContextProvider from './context/sidebar/SidebarContextProvider';
|
||||
|
||||
const httpLink = new HttpLink({ uri: 'http://localhost:8080/graphql' });
|
||||
|
||||
const afterwareLink = new ApolloLink((operation, forward) => {
|
||||
return forward(operation).map((data) => {
|
||||
const context = operation.getContext();
|
||||
const {
|
||||
response: { headers }
|
||||
} = context;
|
||||
|
||||
if (headers) {
|
||||
const pagination = headers.get('x-pagination');
|
||||
|
||||
if (pagination) {
|
||||
sessionStorage.setItem('pagination', pagination);
|
||||
window.dispatchEvent(new Event('storage'));
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
});
|
||||
});
|
||||
|
||||
const client: ApolloClient<NormalizedCacheObject> = new ApolloClient({
|
||||
uri: 'http://localhost:8081/graphql',
|
||||
link: from([afterwareLink, httpLink]),
|
||||
cache: new InMemoryCache()
|
||||
});
|
||||
|
||||
|
||||
6
app/src/models/IDivision.ts
Normal file
6
app/src/models/IDivision.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
export interface IDivision {
|
||||
active: boolean;
|
||||
id: number;
|
||||
link: string;
|
||||
name: string;
|
||||
}
|
||||
7
app/src/models/ILeague.ts
Normal file
7
app/src/models/ILeague.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
export interface ILeague {
|
||||
active: boolean;
|
||||
id: number;
|
||||
link: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
6
app/src/models/IPagination.ts
Normal file
6
app/src/models/IPagination.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
export interface IPagination {
|
||||
CurrentPage: number;
|
||||
PageSize: number;
|
||||
TotalCount: number;
|
||||
TotalPages: number;
|
||||
}
|
||||
4
app/src/models/ISeason.ts
Normal file
4
app/src/models/ISeason.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export interface ISeason {
|
||||
id: number;
|
||||
active: boolean;
|
||||
}
|
||||
4
app/src/models/ISeasonMessage.ts
Normal file
4
app/src/models/ISeasonMessage.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export interface ISeasonMessage {
|
||||
totalDates: number;
|
||||
datesCompleted: number;
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from "react";
|
||||
import React from 'react';
|
||||
|
||||
export interface ISidebar {
|
||||
component: React.ReactNode | undefined;
|
||||
isVisible: boolean;
|
||||
}
|
||||
component: React.ReactNode | undefined;
|
||||
isVisible: boolean;
|
||||
}
|
||||
|
||||
6
app/src/models/ISport.ts
Normal file
6
app/src/models/ISport.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
export interface ISport {
|
||||
active: boolean;
|
||||
id: number;
|
||||
link: string;
|
||||
name: string;
|
||||
}
|
||||
@@ -1,23 +1,23 @@
|
||||
export interface ITeam {
|
||||
id: number;
|
||||
name: string;
|
||||
abbreviation: string;
|
||||
active: string;
|
||||
allStarStatus: string;
|
||||
clubName: string;
|
||||
divisionId: number;
|
||||
fileCode: string;
|
||||
firstYearOfPlay: number;
|
||||
franchiseName: string;
|
||||
leagueId: number;
|
||||
link: string;
|
||||
locationName: string;
|
||||
season: string;
|
||||
shortName: string;
|
||||
springLeagueId: number;
|
||||
sprintVenueId: number;
|
||||
sportId: number;
|
||||
teamCode: string;
|
||||
teamName: string;
|
||||
venueId: number;
|
||||
}
|
||||
id: number;
|
||||
name: string;
|
||||
abbreviation: string;
|
||||
active: string;
|
||||
allStarStatus: string;
|
||||
clubName: string;
|
||||
divisionId: number;
|
||||
fileCode: string;
|
||||
firstYearOfPlay: number;
|
||||
franchiseName: string;
|
||||
leagueId: number;
|
||||
link: string;
|
||||
locationName: string;
|
||||
season: string;
|
||||
shortName: string;
|
||||
springLeagueId: number;
|
||||
sprintVenueId: number;
|
||||
sportId: number;
|
||||
teamCode: string;
|
||||
teamName: string;
|
||||
venueId: number;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user