From 2fa7ddc8e950b5459a74a7db103fd69926908b55 Mon Sep 17 00:00:00 2001 From: Finn Ickler Date: Mon, 10 Jul 2023 15:16:16 +0200 Subject: [PATCH 01/13] prepare for monolith integration --- Frontend/package.json | 2 +- Frontend/src/build.js | 6 ++- Frontend/src/index.dev.jsx | 97 ++++++++++++++++++++++++++++++++++++++ Frontend/src/index.jsx | 35 ++------------ Frontend/src/watch.mjs | 2 +- Gemfile.lock | 4 ++ config/routes.rb | 10 ++-- 7 files changed, 115 insertions(+), 41 deletions(-) create mode 100644 Frontend/src/index.dev.jsx diff --git a/Frontend/package.json b/Frontend/package.json index 5a17e221..40c5a356 100644 --- a/Frontend/package.json +++ b/Frontend/package.json @@ -14,7 +14,7 @@ "homepage": "https://github.com/thewca/wca-registration/Frontend/README.md", "scripts": { "build:dev": "NODE_ENV=\"development\" ASSET_PATH=\"/dist\" API_URL=\"http://localhost:3001/api/v1\" AUTH_URL=\"http://localhost:3001/jwt\" node src/build.js", - "build:staging": "NODE_ENV=\"production\" ASSET_PATH=\"https://d1qizdh27al0a7.cloudfront.net/staging/dist\" API_URL=\"https://staging.registration.worldcubeassociation.org/api/v1\" AUTH_URL=\"https://staging.registration.worldcubeassociation.org/jwt\" node src/build.js", + "build:staging": "NODE_ENV=\"staging\" ASSET_PATH=\"https://d1qizdh27al0a7.cloudfront.net/staging/dist\" API_URL=\"https://staging.registration.worldcubeassociation.org/api/v1\" AUTH_URL=\"https://staging.registration.worldcubeassociation.org/jwt\" node src/build.js", "build:prod": "NODE_ENV=\"production\" ASSET_PATH=\"https://d1qizdh27al0a7.cloudfront.net/dist\" API_URL=\"https://registration.worldcubeassociation.org/api/v1\" AUTH_URL=\"https://registration.worldcubeassociation.org/jwt\" node src/build.js", "watch": "node src/watch.mjs", "lint": "eslint src --ext .js,.jsx,.ts,.tsx", diff --git a/Frontend/src/build.js b/Frontend/src/build.js index ec201973..73b03682 100644 --- a/Frontend/src/build.js +++ b/Frontend/src/build.js @@ -5,7 +5,11 @@ const statsPlugin = require('./statsplugin') esbuild .build({ - entryPoints: ['src/index.jsx'], + entryPoints: [ + process.env.NODE_ENV === 'production' + ? 'src/index.jsx' + : 'src/index.dev.jsx', + ], bundle: true, outfile: 'dist/bundle.js', metafile: true, diff --git a/Frontend/src/index.dev.jsx b/Frontend/src/index.dev.jsx new file mode 100644 index 00000000..27c13e35 --- /dev/null +++ b/Frontend/src/index.dev.jsx @@ -0,0 +1,97 @@ +// External Styles (this is probably not the best way to load this?) +import 'fomantic-ui-css/semantic.css' +import './global.scss' +import '@thewca/wca-components/dist/index.esm.css' +import React from 'react' +import { createRoot } from 'react-dom/client' +import { createBrowserRouter, Outlet, RouterProvider } from 'react-router-dom' +import { Container } from 'semantic-ui-react' +import HomePage from './pages/home' +import Register from './pages/register' +import RegistrationAdministration from './pages/registration_administration' +import RegistrationEdit from './pages/registration_edit' +import Registrations from './pages/registrations' +import TestLogin from './pages/test/login' +import TestLogout from './pages/test/logout' +import App from './ui/App' +import Competition from './ui/Competition' +import PageFooter from './ui/Footer' +import PageHeader from './ui/Header' +import FlashMessage from './ui/messages/flashMessage' +import PageTabs from './ui/Tabs' + +const router = createBrowserRouter([ + { + path: '/', + element: ( + + + +
+ +
+ +
+ ), + children: [ + { + // Test Route to simulate different users + path: '/login/:login_id', + element: , + }, + { + // Test Route to simulate different users + path: '/logout', + element: , + }, + { + path: '', + element: ( +

+ Choose a Test Competition from the Menu +

+ ), + }, + { + path: '/:competition_id', + element: ( + + + + + + + ), + children: [ + { + path: '/:competition_id', + element: , + }, + { + path: '/:competition_id/register', + element: , + }, + { + path: '/:competition_id/registrations', + element: , + }, + { + path: '/:competition_id/:user_id/edit', + element: , + }, + { + path: '/:competition_id/registrations/edit', + element: , + }, + ], + }, + ], + }, +]) + +// Clear the existing HTML content +document.body.innerHTML = '
' + +// Render your React component instead +const root = createRoot(document.querySelector('#app')) +root.render() diff --git a/Frontend/src/index.jsx b/Frontend/src/index.jsx index 27c13e35..cc0bf77f 100644 --- a/Frontend/src/index.jsx +++ b/Frontend/src/index.jsx @@ -11,12 +11,8 @@ import Register from './pages/register' import RegistrationAdministration from './pages/registration_administration' import RegistrationEdit from './pages/registration_edit' import Registrations from './pages/registrations' -import TestLogin from './pages/test/login' -import TestLogout from './pages/test/logout' import App from './ui/App' import Competition from './ui/Competition' -import PageFooter from './ui/Footer' -import PageHeader from './ui/Header' import FlashMessage from './ui/messages/flashMessage' import PageTabs from './ui/Tabs' @@ -25,33 +21,11 @@ const router = createBrowserRouter([ path: '/', element: ( - -
- -
- +
), children: [ - { - // Test Route to simulate different users - path: '/login/:login_id', - element: , - }, - { - // Test Route to simulate different users - path: '/logout', - element: , - }, - { - path: '', - element: ( -

- Choose a Test Competition from the Menu -

- ), - }, { path: '/:competition_id', element: ( @@ -89,9 +63,6 @@ const router = createBrowserRouter([ }, ]) -// Clear the existing HTML content -document.body.innerHTML = '
' - -// Render your React component instead -const root = createRoot(document.querySelector('#app')) +// Render the React component into the body of the monolith +const root = createRoot(document.querySelector('#registration-app')) root.render() diff --git a/Frontend/src/watch.mjs b/Frontend/src/watch.mjs index d0a132a0..8d032a89 100644 --- a/Frontend/src/watch.mjs +++ b/Frontend/src/watch.mjs @@ -3,7 +3,7 @@ import { sassPlugin, postcssModules } from 'esbuild-sass-plugin' import statsPlugin from './statsplugin.js' const context = await esbuild.context({ - entryPoints: ['src/index.jsx'], + entryPoints: ['src/index.dev.jsx'], bundle: true, outfile: 'dist/bundle.js', jsxFactory: 'React.createElement', diff --git a/Gemfile.lock b/Gemfile.lock index 01771858..4533363e 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -147,6 +147,8 @@ GEM net-smtp (0.3.3) net-protocol nio4r (2.5.9) + nokogiri (1.15.2-aarch64-linux) + racc (~> 1.4) nokogiri (1.15.2-x86_64-linux) racc (~> 1.4) parallel (1.23.0) @@ -244,6 +246,7 @@ GEM parser (>= 3.2.1.0) ruby-prof (1.6.3) ruby-progressbar (1.13.0) + sqlite3 (1.6.3-aarch64-linux) sqlite3 (1.6.3-x86_64-linux) thor (1.2.2) timeout (0.4.0) @@ -266,6 +269,7 @@ GEM zeitwerk (2.6.8) PLATFORMS + aarch64-linux x86_64-linux DEPENDENCIES diff --git a/config/routes.rb b/config/routes.rb index 3068875c..859c0170 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -7,12 +7,10 @@ end get '/healthcheck', to: 'healthcheck#index' - # auth route for testing - # Uncomment this ones we integrate with the monolith - # unless Rails.env.production? - # get '/jwt', to: 'jwt_dev#index' - # end - get '/jwt', to: 'jwt_dev#index' + # auth route for testing, we can remove this for staging when we have fully integrated with the monolith + unless ENV.fetch("CODE_ENVIRONMENT", "development") == "production" + get '/jwt', to: 'jwt_dev#index' + end get '/api/v1/register', to: 'registration#entry' post '/api/v1/register', to: 'registration#create' patch '/api/v1/register', to: 'registration#update' From 0eb9a650582c4f6793371024c6f4c2d771d96f5f Mon Sep 17 00:00:00 2001 From: Finn Ickler Date: Mon, 10 Jul 2023 15:29:25 +0200 Subject: [PATCH 02/13] Change test comps to ones that are actually open --- Frontend/src/ui/Header.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Frontend/src/ui/Header.jsx b/Frontend/src/ui/Header.jsx index a0ea47b1..79197cca 100644 --- a/Frontend/src/ui/Header.jsx +++ b/Frontend/src/ui/Header.jsx @@ -9,13 +9,13 @@ const DROPDOWNS = [ title: 'Registration System', items: [ { - path: '/BudapestSummer2023', + path: '/BanjaLukaCubeDay2023', icon: 'frog', title: 'Test Competition 1', reactRoute: true, }, { - path: '/HessenOpen2023', + path: '/DarmstadtDodecahedronDays2023', icon: 'fish', title: 'Test Competition 2', reactRoute: true, From 544838cf3418a6ec18803f718e7a317ef3664f29 Mon Sep 17 00:00:00 2001 From: Finn Ickler Date: Mon, 10 Jul 2023 15:45:35 +0200 Subject: [PATCH 03/13] Move JWT Auth URL to the monolith --- Frontend/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Frontend/package.json b/Frontend/package.json index 40c5a356..2c6616fe 100644 --- a/Frontend/package.json +++ b/Frontend/package.json @@ -15,7 +15,7 @@ "scripts": { "build:dev": "NODE_ENV=\"development\" ASSET_PATH=\"/dist\" API_URL=\"http://localhost:3001/api/v1\" AUTH_URL=\"http://localhost:3001/jwt\" node src/build.js", "build:staging": "NODE_ENV=\"staging\" ASSET_PATH=\"https://d1qizdh27al0a7.cloudfront.net/staging/dist\" API_URL=\"https://staging.registration.worldcubeassociation.org/api/v1\" AUTH_URL=\"https://staging.registration.worldcubeassociation.org/jwt\" node src/build.js", - "build:prod": "NODE_ENV=\"production\" ASSET_PATH=\"https://d1qizdh27al0a7.cloudfront.net/dist\" API_URL=\"https://registration.worldcubeassociation.org/api/v1\" AUTH_URL=\"https://registration.worldcubeassociation.org/jwt\" node src/build.js", + "build:prod": "NODE_ENV=\"production\" ASSET_PATH=\"https://d1qizdh27al0a7.cloudfront.net/dist\" API_URL=\"https://registration.worldcubeassociation.org/api/v1\" AUTH_URL=\"https://worldcubeassociation.org/api/v1/jwt\" node src/build.js", "watch": "node src/watch.mjs", "lint": "eslint src --ext .js,.jsx,.ts,.tsx", "lint:fix": "eslint src --ext .js,.jsx,.ts,.tsx --fix" From 6f585c8d9b36bcbd8478cd5abfde5262b17a8927 Mon Sep 17 00:00:00 2001 From: Finn Ickler Date: Tue, 11 Jul 2023 14:42:18 +0200 Subject: [PATCH 04/13] Changed to /competitions route --- Frontend/src/index.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Frontend/src/index.jsx b/Frontend/src/index.jsx index cc0bf77f..8f94c310 100644 --- a/Frontend/src/index.jsx +++ b/Frontend/src/index.jsx @@ -18,7 +18,7 @@ import PageTabs from './ui/Tabs' const router = createBrowserRouter([ { - path: '/', + path: '/competitions', element: ( From 294a8f7fcf68f570b12909ca2b9468d60e54ce92 Mon Sep 17 00:00:00 2001 From: Finn Ickler Date: Tue, 11 Jul 2023 15:21:14 +0200 Subject: [PATCH 05/13] Changed links to match the monolith --- .../src/api/competition/get/get_competition_info.ts | 2 +- Frontend/src/api/user/get/get_user_info.ts | 2 +- Frontend/src/index.dev.jsx | 12 ++++++------ Frontend/src/index.jsx | 12 ++++++------ Frontend/src/ui/Header.jsx | 4 ++-- Frontend/src/ui/Tabs.jsx | 12 ++++++++---- 6 files changed, 24 insertions(+), 20 deletions(-) diff --git a/Frontend/src/api/competition/get/get_competition_info.ts b/Frontend/src/api/competition/get/get_competition_info.ts index 9a986cfd..71860add 100644 --- a/Frontend/src/api/competition/get/get_competition_info.ts +++ b/Frontend/src/api/competition/get/get_competition_info.ts @@ -5,6 +5,6 @@ export default async function getCompetitionInfo( competitionId: string ): Promise { return externalServiceFetch( - `https://www.worldcubeassociation.org/api/v0/competitions/${competitionId}` + `https://api.worldcubeassociation.org/competitions/${competitionId}` ) } diff --git a/Frontend/src/api/user/get/get_user_info.ts b/Frontend/src/api/user/get/get_user_info.ts index 94e1b621..d02fca36 100644 --- a/Frontend/src/api/user/get/get_user_info.ts +++ b/Frontend/src/api/user/get/get_user_info.ts @@ -19,6 +19,6 @@ export default async function getCompetitorInfo( userId: string ): Promise { return externalServiceFetch( - `https://www.worldcubeassociation.org/api/v0/users/${userId}` + `https://api.worldcubeassociation.org/users/${userId}` ) } diff --git a/Frontend/src/index.dev.jsx b/Frontend/src/index.dev.jsx index 27c13e35..82ce0487 100644 --- a/Frontend/src/index.dev.jsx +++ b/Frontend/src/index.dev.jsx @@ -53,7 +53,7 @@ const router = createBrowserRouter([ ), }, { - path: '/:competition_id', + path: '/competitions/:competition_id', element: ( @@ -64,23 +64,23 @@ const router = createBrowserRouter([ ), children: [ { - path: '/:competition_id', + path: '/competitions/:competition_id', element: , }, { - path: '/:competition_id/register', + path: '/competitions/:competition_id/register', element: , }, { - path: '/:competition_id/registrations', + path: '/competitions/:competition_id/registrations', element: , }, { - path: '/:competition_id/:user_id/edit', + path: '/competitions/:competition_id/:user_id/edit', element: , }, { - path: '/:competition_id/registrations/edit', + path: '/competitions/:competition_id/registrations/edit', element: , }, ], diff --git a/Frontend/src/index.jsx b/Frontend/src/index.jsx index 8f94c310..d7723013 100644 --- a/Frontend/src/index.jsx +++ b/Frontend/src/index.jsx @@ -27,7 +27,7 @@ const router = createBrowserRouter([ ), children: [ { - path: '/:competition_id', + path: '/competitions/:competition_id', element: ( @@ -38,23 +38,23 @@ const router = createBrowserRouter([ ), children: [ { - path: '/:competition_id', + path: '/competitions/:competition_id', element: , }, { - path: '/:competition_id/register', + path: '/competitions/:competition_id/register', element: , }, { - path: '/:competition_id/registrations', + path: '/competitions/:competition_id/registrations', element: , }, { - path: '/:competition_id/:user_id/edit', + path: '/competitions/:competition_id/:user_id/edit', element: , }, { - path: '/:competition_id/registrations/edit', + path: '/competitions/:competition_id/registrations/edit', element: , }, ], diff --git a/Frontend/src/ui/Header.jsx b/Frontend/src/ui/Header.jsx index 79197cca..dc8167ab 100644 --- a/Frontend/src/ui/Header.jsx +++ b/Frontend/src/ui/Header.jsx @@ -9,13 +9,13 @@ const DROPDOWNS = [ title: 'Registration System', items: [ { - path: '/BanjaLukaCubeDay2023', + path: '/competitions/BanjaLukaCubeDay2023', icon: 'frog', title: 'Test Competition 1', reactRoute: true, }, { - path: '/DarmstadtDodecahedronDays2023', + path: '/competitions/DarmstadtDodecahedronDays2023', icon: 'fish', title: 'Test Competition 2', reactRoute: true, diff --git a/Frontend/src/ui/Tabs.jsx b/Frontend/src/ui/Tabs.jsx index 26c2897a..28e2d93a 100644 --- a/Frontend/src/ui/Tabs.jsx +++ b/Frontend/src/ui/Tabs.jsx @@ -20,7 +20,7 @@ export default function PageTabs() { key="tab-registration" className={styles.tabItem} onClick={() => - navigate(`/${competitionInfo.id}/registrations/edit`) + navigate(`/competitions/${competitionInfo.id}/registrations/edit`) } > @@ -36,7 +36,7 @@ export default function PageTabs() { navigate(`/${competitionInfo.id}`)} + onClick={() => navigate(`/competitions/${competitionInfo.id}`)} > General Info @@ -50,7 +50,9 @@ export default function PageTabs() { navigate(`/${competitionInfo.id}/registrations`)} + onClick={() => + navigate(`/competitions/${competitionInfo.id}/registrations`) + } > Competitors @@ -63,7 +65,9 @@ export default function PageTabs() { navigate(`/${competitionInfo.id}/register`)} + onClick={() => + navigate(`/competitions/${competitionInfo.id}/register`) + } > Register From 7c74a209383dfe9e2c3ed6481419c709620135d9 Mon Sep 17 00:00:00 2001 From: Finn Ickler Date: Wed, 12 Jul 2023 10:32:12 +0200 Subject: [PATCH 06/13] Stop bundling semantic UI twice --- Frontend/src/index.jsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/Frontend/src/index.jsx b/Frontend/src/index.jsx index d7723013..574b5b59 100644 --- a/Frontend/src/index.jsx +++ b/Frontend/src/index.jsx @@ -1,6 +1,4 @@ // External Styles (this is probably not the best way to load this?) -import 'fomantic-ui-css/semantic.css' -import './global.scss' import '@thewca/wca-components/dist/index.esm.css' import React from 'react' import { createRoot } from 'react-dom/client' From c3bb01465a71fefe8d49786ed8edbb15c06945d3 Mon Sep 17 00:00:00 2001 From: Finn Ickler Date: Wed, 12 Jul 2023 14:11:08 +0200 Subject: [PATCH 07/13] Added isOpen check for competition --- Frontend/src/ui/Competition.jsx | 19 +++++++++++++++++-- Frontend/src/ui/competition.module.scss | 3 +++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/Frontend/src/ui/Competition.jsx b/Frontend/src/ui/Competition.jsx index 930292aa..d99d7372 100644 --- a/Frontend/src/ui/Competition.jsx +++ b/Frontend/src/ui/Competition.jsx @@ -8,6 +8,13 @@ import { CompetitionContext } from '../api/helper/context/competition_context' import styles from './competition.module.scss' import LoadingMessage from './messages/loadingMessage' +const isOpen = (competitionInfo) => { + return ( + new Date(competitionInfo.registration_open) < new Date() && + new Date(competitionInfo.registration_close) > new Date() + ) +} + export default function Competition({ children }) { const { competition_id } = useParams() const navigate = useNavigate() @@ -28,7 +35,11 @@ export default function Competition({ children }) {
{competitionInfo.name} |{' '} - Open + {isOpen(competitionInfo) ? ( + Open + ) : ( + Close + )}
{competitionInfo.venue_address} @@ -45,7 +56,11 @@ export default function Competition({ children }) {
diff --git a/Frontend/src/ui/competition.module.scss b/Frontend/src/ui/competition.module.scss index 67ab5b69..f911c96a 100644 --- a/Frontend/src/ui/competition.module.scss +++ b/Frontend/src/ui/competition.module.scss @@ -7,6 +7,9 @@ .open{ color: #007E0D; } +.close{ + color: #7e0026; +} .header{ display: flex; border-radius: 39px; From bc60e0741a900c005d8724317606a3bb48ed401e Mon Sep 17 00:00:00 2001 From: Finn Ickler Date: Wed, 12 Jul 2023 14:50:36 +0200 Subject: [PATCH 08/13] Corrected AUTH_URL --- Frontend/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Frontend/package.json b/Frontend/package.json index 2c6616fe..396ce75c 100644 --- a/Frontend/package.json +++ b/Frontend/package.json @@ -15,7 +15,7 @@ "scripts": { "build:dev": "NODE_ENV=\"development\" ASSET_PATH=\"/dist\" API_URL=\"http://localhost:3001/api/v1\" AUTH_URL=\"http://localhost:3001/jwt\" node src/build.js", "build:staging": "NODE_ENV=\"staging\" ASSET_PATH=\"https://d1qizdh27al0a7.cloudfront.net/staging/dist\" API_URL=\"https://staging.registration.worldcubeassociation.org/api/v1\" AUTH_URL=\"https://staging.registration.worldcubeassociation.org/jwt\" node src/build.js", - "build:prod": "NODE_ENV=\"production\" ASSET_PATH=\"https://d1qizdh27al0a7.cloudfront.net/dist\" API_URL=\"https://registration.worldcubeassociation.org/api/v1\" AUTH_URL=\"https://worldcubeassociation.org/api/v1/jwt\" node src/build.js", + "build:prod": "NODE_ENV=\"production\" ASSET_PATH=\"https://d1qizdh27al0a7.cloudfront.net/dist\" API_URL=\"https://registration.worldcubeassociation.org/api/v1\" AUTH_URL=\"https://test-registration.worldcubeassociation.org/api/v10/auth/jwt\" node src/build.js", "watch": "node src/watch.mjs", "lint": "eslint src --ext .js,.jsx,.ts,.tsx", "lint:fix": "eslint src --ext .js,.jsx,.ts,.tsx --fix" From ada44a9a79b6cd2d95bb08bd336957bee51972ea Mon Sep 17 00:00:00 2001 From: Finn Ickler Date: Wed, 12 Jul 2023 19:54:23 +0200 Subject: [PATCH 09/13] Remove get_permissions mock --- Frontend/src/api/auth/get_permissions.ts | 117 +++--------------- Frontend/src/pages/register/index.jsx | 4 +- .../registration_administration/index.jsx | 6 +- .../src/pages/registration_edit/index.jsx | 6 +- Frontend/src/ui/Tabs.jsx | 4 +- 5 files changed, 25 insertions(+), 112 deletions(-) diff --git a/Frontend/src/api/auth/get_permissions.ts b/Frontend/src/api/auth/get_permissions.ts index 9f6fc988..0d621612 100644 --- a/Frontend/src/api/auth/get_permissions.ts +++ b/Frontend/src/api/auth/get_permissions.ts @@ -1,111 +1,28 @@ -// This function simulates a call to the user permissions route on the monolith. -// This will return your own permissions, not someone else, the argument is -// just here for the mock -import { USER_IS_BANNED, USER_PROFILE_INCOMPLETE } from '../helper/error_codes' +import externalServiceFetch from '../helper/external_service_fetch' -function getPermissions(userId: string) { - switch (userId) { - case '1': - return { - can_attend_competitions: { - scope: '*', - }, - can_organize_competitions: { - scope: ['BudapestSummer2023'], - }, - can_administer_competitions: { - scope: ['BudapestSummer2023'], - }, - } - case '2': - return { - can_attend_competitions: { - scope: '*', - }, - can_organize_competitions: { - scope: [], - }, - can_administer_competitions: { - scope: [], - }, - } - case '6427': - return { - can_attend_competitions: { - scope: '*', - }, - can_organize_competitions: { - scope: [], - }, - can_administer_competitions: { - scope: [], - }, - } - case '15073': - return { - can_attend_competitions: { - scope: '*', - }, - can_organize_competitions: { - scope: '*', - }, - can_administer_competitions: { - scope: '*', - }, - } - case '209943': - return { - can_attend_competitions: { - scope: [], - reasons: USER_IS_BANNED, - }, - can_organize_competitions: { - scope: [], - }, - can_administer_competitions: { - scope: [], - }, - } - case '999999': - return { - can_attend_competitions: { - scope: [], - reasons: USER_PROFILE_INCOMPLETE, - }, - can_organize_competitions: { - scope: [], - }, - can_administer_competitions: { - scope: [], - }, - } - default: - return { - can_attend_competitions: { - scope: [], - }, - can_organize_competitions: { - scope: [], - }, - can_administer_competitions: { - scope: [], - }, - } - } +interface Permissions { + can_attend_competitions: { scope: Scope } + can_organize_competitions: { scope: Scope } + can_administer_competitions: { scope: Scope } } +type Scope = '*' | string[] -export function canAdminCompetition(userId: string, competitionId: string) { - const permissions = getPermissions(userId) +async function getPermissions() { + return externalServiceFetch( + 'https://test-registration.worldcubeassociation.org/api/v10/users/me/permissions' + ) as Promise +} + +export async function canAdminCompetition(competitionId: string) { + const permissions = await getPermissions() return ( permissions.can_administer_competitions.scope === '*' || - (permissions.can_administer_competitions.scope as string[]).includes( - competitionId - ) + permissions.can_administer_competitions.scope.includes(competitionId) ) } -export function canAttendCompetitions(userId: string) { - const permissions = getPermissions(userId) +export async function canAttendCompetitions() { + const permissions = await getPermissions() return permissions.can_attend_competitions.scope === '*' } diff --git a/Frontend/src/pages/register/index.jsx b/Frontend/src/pages/register/index.jsx index 78a76987..58d7a52d 100644 --- a/Frontend/src/pages/register/index.jsx +++ b/Frontend/src/pages/register/index.jsx @@ -11,7 +11,7 @@ import PermissionMessage from '../../ui/messages/permissionMessage' import RegistrationPanel from './components/RegistrationPanel' import styles from './index.module.scss' -export default function Register() { +export default async function Register() { const { user } = useContext(AuthContext) const { competitionInfo } = useContext(CompetitionContext) const loggedIn = user !== null @@ -78,7 +78,7 @@ export default function Register() { ) : ( <>
Hi, {user}
- {canAttendCompetitions(user) ? ( + {(await canAttendCompetitions(user)) ? ( ) : ( diff --git a/Frontend/src/pages/registration_administration/index.jsx b/Frontend/src/pages/registration_administration/index.jsx index af376374..173f8f4a 100644 --- a/Frontend/src/pages/registration_administration/index.jsx +++ b/Frontend/src/pages/registration_administration/index.jsx @@ -3,18 +3,16 @@ import { CAN_ADMINISTER_COMPETITIONS, canAdminCompetition, } from '../../api/auth/get_permissions' -import { AuthContext } from '../../api/helper/context/auth_context' import { CompetitionContext } from '../../api/helper/context/competition_context' import PermissionMessage from '../../ui/messages/permissionMessage' import RegistrationAdministrationList from './components/RegistrationAdministrationList' import styles from './index.module.scss' -export default function RegistrationAdministration() { +export default async function RegistrationAdministration() { const { competitionInfo } = useContext(CompetitionContext) - const { user } = useContext(AuthContext) return (
- {canAdminCompetition(user, competitionInfo.id) ? ( + {(await canAdminCompetition(competitionInfo.id)) ? ( ) : ( diff --git a/Frontend/src/pages/registration_edit/index.jsx b/Frontend/src/pages/registration_edit/index.jsx index f4bffd0b..134ec703 100644 --- a/Frontend/src/pages/registration_edit/index.jsx +++ b/Frontend/src/pages/registration_edit/index.jsx @@ -3,18 +3,16 @@ import { CAN_ADMINISTER_COMPETITIONS, canAdminCompetition, } from '../../api/auth/get_permissions' -import { AuthContext } from '../../api/helper/context/auth_context' import { CompetitionContext } from '../../api/helper/context/competition_context' import PermissionMessage from '../../ui/messages/permissionMessage' import RegistrationEditor from './components/RegistrationEditor' import styles from './index.module.scss' -export default function RegistrationEdit() { +export default async function RegistrationEdit() { const { competitionInfo } = useContext(CompetitionContext) - const { user } = useContext(AuthContext) return (
- {canAdminCompetition(user, competitionInfo.id) ? ( + {(await canAdminCompetition(competitionInfo.id)) ? ( ) : ( diff --git a/Frontend/src/ui/Tabs.jsx b/Frontend/src/ui/Tabs.jsx index 28e2d93a..62e2cc1f 100644 --- a/Frontend/src/ui/Tabs.jsx +++ b/Frontend/src/ui/Tabs.jsx @@ -11,9 +11,9 @@ export default function PageTabs() { const { competitionInfo } = useContext(CompetitionContext) const { user } = useContext(AuthContext) const navigate = useNavigate() - const panes = useMemo(() => { + const panes = useMemo(async () => { const adminPanes = [] - if (canAdminCompetition(user, competitionInfo.id)) { + if (await canAdminCompetition(competitionInfo.id)) { adminPanes.push({ menuItem: ( Date: Wed, 12 Jul 2023 20:56:53 +0200 Subject: [PATCH 10/13] Change external_service_fetch to fetch-sync for now --- Frontend/package.json | 4 +++- Frontend/src/api/auth/get_permissions.ts | 12 ++++++------ Frontend/src/api/helper/external_service_fetch.ts | 7 ++++--- Frontend/src/pages/register/index.jsx | 4 ++-- .../src/pages/registration_administration/index.jsx | 4 ++-- Frontend/src/pages/registration_edit/index.jsx | 4 ++-- Frontend/src/ui/Competition.jsx | 4 +++- Frontend/src/ui/Tabs.jsx | 4 ++-- 8 files changed, 24 insertions(+), 19 deletions(-) diff --git a/Frontend/package.json b/Frontend/package.json index 396ce75c..072ba815 100644 --- a/Frontend/package.json +++ b/Frontend/package.json @@ -34,11 +34,13 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "react-router-dom": "^6.11.2", - "semantic-ui-react": "^2.1.4" + "semantic-ui-react": "^2.1.4", + "sync-fetch": "^0.5.2" }, "devDependencies": { "@tanstack/eslint-plugin-query": "^4.29.9", "@types/node": "^20.2.5", + "@types/sync-fetch": "^0.4.0", "eslint": "^8.40.0", "eslint-kit": "^9.3.0", "prettier": "^2.8.8" diff --git a/Frontend/src/api/auth/get_permissions.ts b/Frontend/src/api/auth/get_permissions.ts index 0d621612..2749351f 100644 --- a/Frontend/src/api/auth/get_permissions.ts +++ b/Frontend/src/api/auth/get_permissions.ts @@ -7,22 +7,22 @@ interface Permissions { } type Scope = '*' | string[] -async function getPermissions() { +function getPermissions() { return externalServiceFetch( 'https://test-registration.worldcubeassociation.org/api/v10/users/me/permissions' - ) as Promise + ) as Permissions } -export async function canAdminCompetition(competitionId: string) { - const permissions = await getPermissions() +export function canAdminCompetition(competitionId: string) { + const permissions = getPermissions() return ( permissions.can_administer_competitions.scope === '*' || permissions.can_administer_competitions.scope.includes(competitionId) ) } -export async function canAttendCompetitions() { - const permissions = await getPermissions() +export function canAttendCompetitions() { + const permissions = getPermissions() return permissions.can_attend_competitions.scope === '*' } diff --git a/Frontend/src/api/helper/external_service_fetch.ts b/Frontend/src/api/helper/external_service_fetch.ts index 716b0172..b3805467 100644 --- a/Frontend/src/api/helper/external_service_fetch.ts +++ b/Frontend/src/api/helper/external_service_fetch.ts @@ -1,8 +1,9 @@ +import fetch from 'sync-fetch' import { BackendError } from './backend_fetch' -export default async function externalServiceFetch(route: string) { - const response = await fetch(route) - const body = await response.json() +export default function externalServiceFetch(route: string) { + const response = fetch(route) + const body = response.json() if (response.ok) { return body } diff --git a/Frontend/src/pages/register/index.jsx b/Frontend/src/pages/register/index.jsx index 58d7a52d..78a76987 100644 --- a/Frontend/src/pages/register/index.jsx +++ b/Frontend/src/pages/register/index.jsx @@ -11,7 +11,7 @@ import PermissionMessage from '../../ui/messages/permissionMessage' import RegistrationPanel from './components/RegistrationPanel' import styles from './index.module.scss' -export default async function Register() { +export default function Register() { const { user } = useContext(AuthContext) const { competitionInfo } = useContext(CompetitionContext) const loggedIn = user !== null @@ -78,7 +78,7 @@ export default async function Register() { ) : ( <>
Hi, {user}
- {(await canAttendCompetitions(user)) ? ( + {canAttendCompetitions(user) ? ( ) : ( diff --git a/Frontend/src/pages/registration_administration/index.jsx b/Frontend/src/pages/registration_administration/index.jsx index 173f8f4a..7e1ba91f 100644 --- a/Frontend/src/pages/registration_administration/index.jsx +++ b/Frontend/src/pages/registration_administration/index.jsx @@ -8,11 +8,11 @@ import PermissionMessage from '../../ui/messages/permissionMessage' import RegistrationAdministrationList from './components/RegistrationAdministrationList' import styles from './index.module.scss' -export default async function RegistrationAdministration() { +export default function RegistrationAdministration() { const { competitionInfo } = useContext(CompetitionContext) return (
- {(await canAdminCompetition(competitionInfo.id)) ? ( + {canAdminCompetition(competitionInfo.id) ? ( ) : ( diff --git a/Frontend/src/pages/registration_edit/index.jsx b/Frontend/src/pages/registration_edit/index.jsx index 134ec703..8fecda6c 100644 --- a/Frontend/src/pages/registration_edit/index.jsx +++ b/Frontend/src/pages/registration_edit/index.jsx @@ -8,11 +8,11 @@ import PermissionMessage from '../../ui/messages/permissionMessage' import RegistrationEditor from './components/RegistrationEditor' import styles from './index.module.scss' -export default async function RegistrationEdit() { +export default function RegistrationEdit() { const { competitionInfo } = useContext(CompetitionContext) return (
- {(await canAdminCompetition(competitionInfo.id)) ? ( + {canAdminCompetition(competitionInfo.id) ? ( ) : ( diff --git a/Frontend/src/ui/Competition.jsx b/Frontend/src/ui/Competition.jsx index 930292aa..34e9b6b9 100644 --- a/Frontend/src/ui/Competition.jsx +++ b/Frontend/src/ui/Competition.jsx @@ -45,7 +45,9 @@ export default function Competition({ children }) {
diff --git a/Frontend/src/ui/Tabs.jsx b/Frontend/src/ui/Tabs.jsx index 62e2cc1f..848bd799 100644 --- a/Frontend/src/ui/Tabs.jsx +++ b/Frontend/src/ui/Tabs.jsx @@ -11,9 +11,9 @@ export default function PageTabs() { const { competitionInfo } = useContext(CompetitionContext) const { user } = useContext(AuthContext) const navigate = useNavigate() - const panes = useMemo(async () => { + const panes = useMemo(() => { const adminPanes = [] - if (await canAdminCompetition(competitionInfo.id)) { + if (canAdminCompetition(competitionInfo.id)) { adminPanes.push({ menuItem: ( Date: Fri, 14 Jul 2023 10:35:57 +0200 Subject: [PATCH 11/13] Bring back permissionsMock for non production --- Frontend/src/api/auth/get_permissions.ts | 11 ++- Frontend/src/api/mocks/get_permissions.ts | 94 +++++++++++++++++++++++ Frontend/src/watch.mjs | 1 + 3 files changed, 103 insertions(+), 3 deletions(-) create mode 100644 Frontend/src/api/mocks/get_permissions.ts diff --git a/Frontend/src/api/auth/get_permissions.ts b/Frontend/src/api/auth/get_permissions.ts index 2749351f..ac3a6c70 100644 --- a/Frontend/src/api/auth/get_permissions.ts +++ b/Frontend/src/api/auth/get_permissions.ts @@ -1,4 +1,6 @@ +import * as process from 'process' import externalServiceFetch from '../helper/external_service_fetch' +import getPermissionsMock from '../mocks/get_permissions' interface Permissions { can_attend_competitions: { scope: Scope } @@ -8,9 +10,12 @@ interface Permissions { type Scope = '*' | string[] function getPermissions() { - return externalServiceFetch( - 'https://test-registration.worldcubeassociation.org/api/v10/users/me/permissions' - ) as Permissions + if (process.env.NODE_ENV === 'production') { + return externalServiceFetch( + 'https://test-registration.worldcubeassociation.org/api/v10/users/me/permissions' + ) as Permissions + } + return getPermissionsMock() } export function canAdminCompetition(competitionId: string) { diff --git a/Frontend/src/api/mocks/get_permissions.ts b/Frontend/src/api/mocks/get_permissions.ts new file mode 100644 index 00000000..e9442636 --- /dev/null +++ b/Frontend/src/api/mocks/get_permissions.ts @@ -0,0 +1,94 @@ +import { USER_KEY } from '../../ui/App' +import { USER_IS_BANNED, USER_PROFILE_INCOMPLETE } from '../helper/error_codes' + +export default function getPermissionsMock() { + const userId = localStorage.getItem(USER_KEY) + switch (userId) { + case '1': + return { + can_attend_competitions: { + scope: '*', + }, + can_organize_competitions: { + scope: ['BudapestSummer2023'], + }, + can_administer_competitions: { + scope: ['BudapestSummer2023'], + }, + } + case '2': + return { + can_attend_competitions: { + scope: '*', + }, + can_organize_competitions: { + scope: [], + }, + can_administer_competitions: { + scope: [], + }, + } + case '6427': + return { + can_attend_competitions: { + scope: '*', + }, + can_organize_competitions: { + scope: [], + }, + can_administer_competitions: { + scope: [], + }, + } + case '15073': + return { + can_attend_competitions: { + scope: '*', + }, + can_organize_competitions: { + scope: '*', + }, + can_administer_competitions: { + scope: '*', + }, + } + case '209943': + return { + can_attend_competitions: { + scope: [], + reasons: USER_IS_BANNED, + }, + can_organize_competitions: { + scope: [], + }, + can_administer_competitions: { + scope: [], + }, + } + case '999999': + return { + can_attend_competitions: { + scope: [], + reasons: USER_PROFILE_INCOMPLETE, + }, + can_organize_competitions: { + scope: [], + }, + can_administer_competitions: { + scope: [], + }, + } + default: + return { + can_attend_competitions: { + scope: [], + }, + can_organize_competitions: { + scope: [], + }, + can_administer_competitions: { + scope: [], + }, + } + } +} diff --git a/Frontend/src/watch.mjs b/Frontend/src/watch.mjs index 8d032a89..c8929495 100644 --- a/Frontend/src/watch.mjs +++ b/Frontend/src/watch.mjs @@ -28,6 +28,7 @@ const context = await esbuild.context({ define: { 'process.env.API_URL': '"http://localhost:3001/api/v1"', 'process.env.AUTH_URL': '"http://localhost:3001/jwt"', + 'process.env.NODE_ENV': '"development"', }, }) From 2d4547ebe3fc2f1d0c86d4c2b00edc8459cda2ae Mon Sep 17 00:00:00 2001 From: Finn Ickler Date: Fri, 14 Jul 2023 17:55:14 +0200 Subject: [PATCH 12/13] Add fields from the new Competition API --- Frontend/package.json | 4 ++ Frontend/src/api/auth/get_permissions.ts | 1 - .../competition/get/get_competition_info.ts | 2 +- Frontend/src/api/types.d.ts | 68 ++++++++++++------- Frontend/src/index.dev.jsx | 5 ++ Frontend/src/index.jsx | 5 ++ .../register/components/RegistrationPanel.jsx | 13 +++- Frontend/src/pages/register/index.jsx | 30 ++++++-- Frontend/src/pages/register/index.module.scss | 4 ++ Frontend/src/ui/Competition.jsx | 40 +++++++---- Frontend/src/ui/CustomTab.jsx | 17 +++++ Frontend/src/ui/Header.jsx | 16 ++++- Frontend/src/ui/Tabs.jsx | 58 ++++++++++------ Frontend/src/ui/customtab.module.scss | 7 ++ 14 files changed, 198 insertions(+), 72 deletions(-) create mode 100644 Frontend/src/ui/CustomTab.jsx create mode 100644 Frontend/src/ui/customtab.module.scss diff --git a/Frontend/package.json b/Frontend/package.json index 072ba815..5884052a 100644 --- a/Frontend/package.json +++ b/Frontend/package.json @@ -21,14 +21,18 @@ "lint:fix": "eslint src --ext .js,.jsx,.ts,.tsx --fix" }, "dependencies": { + "@dinero.js/currencies": "^2.0.0-alpha.14", "@tanstack/react-query": "^4.29.19", "@tanstack/react-query-devtools": "^4.29.19", "@thewca/wca-components": "0.5.0", "@wca/helpers": "^1.1.4", + "dinero.js": "^2.0.0-alpha.14", "esbuild": "^0.18.6", "esbuild-sass-plugin": "^2.10.0", "events": "^3.3.0", "fomantic-ui-css": "^2.9.2", + "marked": "^5.1.1", + "moment": "^2.29.4", "postcss": "^8.4.23", "postcss-modules": "^6.0.0", "react": "^18.2.0", diff --git a/Frontend/src/api/auth/get_permissions.ts b/Frontend/src/api/auth/get_permissions.ts index ac3a6c70..e908cb78 100644 --- a/Frontend/src/api/auth/get_permissions.ts +++ b/Frontend/src/api/auth/get_permissions.ts @@ -1,4 +1,3 @@ -import * as process from 'process' import externalServiceFetch from '../helper/external_service_fetch' import getPermissionsMock from '../mocks/get_permissions' diff --git a/Frontend/src/api/competition/get/get_competition_info.ts b/Frontend/src/api/competition/get/get_competition_info.ts index 71860add..fcf99625 100644 --- a/Frontend/src/api/competition/get/get_competition_info.ts +++ b/Frontend/src/api/competition/get/get_competition_info.ts @@ -5,6 +5,6 @@ export default async function getCompetitionInfo( competitionId: string ): Promise { return externalServiceFetch( - `https://api.worldcubeassociation.org/competitions/${competitionId}` + `https://test-registration.worldcubeassociation.org/api/v10/competitions/${competitionId}` ) } diff --git a/Frontend/src/api/types.d.ts b/Frontend/src/api/types.d.ts index 95bda6c9..b53791e2 100644 --- a/Frontend/src/api/types.d.ts +++ b/Frontend/src/api/types.d.ts @@ -18,31 +18,53 @@ interface UpdateRegistrationBody { guests?: number } -type GetRegistrationBody = Record +interface Tabs { + id: number + competition_id: string + name: string + content: string + display_order: number +} // This needs to be moved to WCA-helpers interface CompetitionInfo { - id: string - name: string - registration_open: string - registration_close: string - announced_at: string - start_date: string - end_date: string - competitor_limit?: number - cancelled_at?: string - url: string - website: string - short_name: string - city: string - venue_address: string - venue_details: string - latitude_degrees: number - longitude_degrees: number - country_iso2: string - event_ids: EventId[] + 'id': string + 'name': string + 'registration_open': string + 'registration_close': string + 'announced_at': string + 'start_date': string + 'end_date': string + 'competitor_limit'?: number + 'cancelled_at'?: string + 'refund_policy_limit_date'?: string + 'event_change_deadline_date'?: string + 'waiting_list_deadline_date'?: string + 'base_entry_fee_lowest_denomination'?: string + 'currency_code'?: string + 'on_the_spot_registration': boolean + 'on_the_spot_entry_fee_lowest_denomination': string + 'extra_registration_requirements': string + 'url': string + 'website': string + 'short_name': string + 'city': string + 'venue_address': string + 'venue_details': string + 'latitude_degrees': number + 'longitude_degrees': number + 'country_iso2': string + 'registration_opened?': boolean + 'event_ids': EventId[] + 'main_event_id': EventId + 'guests_per_registration_limit'?: number + 'guest_entry_status': 'free' | 'restricted' | 'unclear' + 'allow_registration_edits': boolean + 'allow_registration_without_qualification': boolean + 'allow_registration_self_delete_after_acceptance': boolean // TODO: create a User Type - delegates: object[] - organizers: object[] - class: string + 'delegates': object[] + 'organizers': object[] + 'tabs': Tabs[] + 'class': string } diff --git a/Frontend/src/index.dev.jsx b/Frontend/src/index.dev.jsx index 82ce0487..1ab86b3d 100644 --- a/Frontend/src/index.dev.jsx +++ b/Frontend/src/index.dev.jsx @@ -15,6 +15,7 @@ import TestLogin from './pages/test/login' import TestLogout from './pages/test/logout' import App from './ui/App' import Competition from './ui/Competition' +import CustomTab from './ui/CustomTab' import PageFooter from './ui/Footer' import PageHeader from './ui/Header' import FlashMessage from './ui/messages/flashMessage' @@ -71,6 +72,10 @@ const router = createBrowserRouter([ path: '/competitions/:competition_id/register', element: , }, + { + path: '/competitions/:competition_id/tabs/:tab_id', + element: , + }, { path: '/competitions/:competition_id/registrations', element: , diff --git a/Frontend/src/index.jsx b/Frontend/src/index.jsx index 574b5b59..fde83a5a 100644 --- a/Frontend/src/index.jsx +++ b/Frontend/src/index.jsx @@ -11,6 +11,7 @@ import RegistrationEdit from './pages/registration_edit' import Registrations from './pages/registrations' import App from './ui/App' import Competition from './ui/Competition' +import CustomTab from './ui/CustomTab' import FlashMessage from './ui/messages/flashMessage' import PageTabs from './ui/Tabs' @@ -43,6 +44,10 @@ const router = createBrowserRouter([ path: '/competitions/:competition_id/register', element: , }, + { + path: '/competitions/:competition_id/tabs/:tab_id', + element: , + }, { path: '/competitions/:competition_id/registrations', element: , diff --git a/Frontend/src/pages/register/components/RegistrationPanel.jsx b/Frontend/src/pages/register/components/RegistrationPanel.jsx index 01983a7f..2d2a44eb 100644 --- a/Frontend/src/pages/register/components/RegistrationPanel.jsx +++ b/Frontend/src/pages/register/components/RegistrationPanel.jsx @@ -105,7 +105,9 @@ export default function RegistrationPanel() {
- Registration Fee of $$$ | Waitlist: 0 People + Registration Fee of{' '} + {competitionInfo.base_entry_fee_lowest_denomination} | Waitlist: 0 + People
@@ -152,7 +154,9 @@ export default function RegistrationPanel() { value={guests} onChange={(e, data) => setGuests(data.value)} selection - options={[...new Array(10)].map((_, index) => { + options={[ + ...new Array(competitionInfo.guests_per_registration_limit ?? 99), + ].map((_, index) => { return { key: `registration-guest-dropdown-${index}`, text: index, @@ -167,10 +171,13 @@ export default function RegistrationPanel() {
Your Registration Status: {registration.registration_status} + {competitionInfo.allow_registration_edits + ? 'Update Your Registration below' + : 'Registration Editing is disabled'}
{!loggedIn ? (

You have to log in to Register for a Competition

- ) : ( - <> + ) : // eslint-disable-next-line unicorn/no-nested-ternary + competitionInfo['registration_opened?'] ? ( +
Hi, {user}
{canAttendCompetitions(user) ? ( ) : ( )} - +
+ ) : ( +
+ + {moment(competitionInfo.registration_open).diff(moment.now()) < 0 + ? `Competition Registration closed on ${moment( + competitionInfo.registration_close + ).format('ll')}` + : `Competition Registration will open in ${moment( + competitionInfo.registration_open + ).fromNow()} on ${moment( + competitionInfo.registration_open + ).format('lll')}`} + +
)}
) diff --git a/Frontend/src/pages/register/index.module.scss b/Frontend/src/pages/register/index.module.scss index c246a0f6..806557a3 100644 --- a/Frontend/src/pages/register/index.module.scss +++ b/Frontend/src/pages/register/index.module.scss @@ -29,3 +29,7 @@ line-height: 3em; } } +.competition-not-open{ + font-size: $sub-header-size; + padding: 30px; +} \ No newline at end of file diff --git a/Frontend/src/ui/Competition.jsx b/Frontend/src/ui/Competition.jsx index d99d7372..032de796 100644 --- a/Frontend/src/ui/Competition.jsx +++ b/Frontend/src/ui/Competition.jsx @@ -1,5 +1,8 @@ +import * as currencies from '@dinero.js/currencies' import { useQuery } from '@tanstack/react-query' import { CubingIcon, UiIcon } from '@thewca/wca-components' +import { dinero, toDecimal } from 'dinero.js' +import moment from 'moment' import React from 'react' import { useNavigate, useParams } from 'react-router-dom' import { Button, Image } from 'semantic-ui-react' @@ -8,13 +11,6 @@ import { CompetitionContext } from '../api/helper/context/competition_context' import styles from './competition.module.scss' import LoadingMessage from './messages/loadingMessage' -const isOpen = (competitionInfo) => { - return ( - new Date(competitionInfo.registration_open) < new Date() && - new Date(competitionInfo.registration_close) > new Date() - ) -} - export default function Competition({ children }) { const { competition_id } = useParams() const navigate = useNavigate() @@ -35,7 +31,7 @@ export default function Competition({ children }) {
{competitionInfo.name} |{' '} - {isOpen(competitionInfo) ? ( + {competitionInfo['registration_opened?'] ? ( Open ) : ( Close @@ -45,8 +41,16 @@ export default function Competition({ children }) { {competitionInfo.venue_address}
- {new Date(competitionInfo.start_date).toDateString()},{' '} - + {moment(competitionInfo.start_date).format('LL')},{' '} + Add to Google Calendar
@@ -56,7 +60,7 @@ export default function Competition({ children }) {
- Registration Fee of $$$ + + Registration Fee:{' '} + {toDecimal( + dinero({ + amount: + competitionInfo.base_entry_fee_lowest_denomination, + currency: currencies[competitionInfo.currency_code], + }), + ({ value, currency }) => `${currency.code} ${value}` + ) ?? 'No Entry Fee'} +
@@ -83,7 +97,7 @@ export default function Competition({ children }) { Main Event: diff --git a/Frontend/src/ui/CustomTab.jsx b/Frontend/src/ui/CustomTab.jsx new file mode 100644 index 00000000..4f86646b --- /dev/null +++ b/Frontend/src/ui/CustomTab.jsx @@ -0,0 +1,17 @@ +import { marked } from 'marked' +import React, { useContext } from 'react' +import { useParams } from 'react-router-dom' +import { CompetitionContext } from '../api/helper/context/competition_context' +import styles from './customtab.module.scss' + +export default function CustomTab() { + const { tab_id } = useParams() + const { competitionInfo } = useContext(CompetitionContext) + const tab = competitionInfo.tabs.find((tab) => tab.id.toString() === tab_id) + return ( + + ) +} diff --git a/Frontend/src/ui/Header.jsx b/Frontend/src/ui/Header.jsx index dc8167ab..2d76106d 100644 --- a/Frontend/src/ui/Header.jsx +++ b/Frontend/src/ui/Header.jsx @@ -11,13 +11,25 @@ const DROPDOWNS = [ { path: '/competitions/BanjaLukaCubeDay2023', icon: 'frog', - title: 'Test Competition 1', + title: 'Open Competition 1', reactRoute: true, }, { path: '/competitions/DarmstadtDodecahedronDays2023', icon: 'fish', - title: 'Test Competition 2', + title: 'Open Competition 2', + reactRoute: true, + }, + { + path: '/competitions/HessenOpen2023', + icon: 'close', + title: 'Closed Competition', + reactRoute: true, + }, + { + path: '/competitions/BrizZonSylwesterOpen2023', + icon: 'time', + title: 'Not yet open Competition', reactRoute: true, }, ], diff --git a/Frontend/src/ui/Tabs.jsx b/Frontend/src/ui/Tabs.jsx index 848bd799..42feb95b 100644 --- a/Frontend/src/ui/Tabs.jsx +++ b/Frontend/src/ui/Tabs.jsx @@ -3,33 +3,13 @@ import React, { useContext, useMemo } from 'react' import { useNavigate } from 'react-router-dom' import { Menu, Tab } from 'semantic-ui-react' import { canAdminCompetition } from '../api/auth/get_permissions' -import { AuthContext } from '../api/helper/context/auth_context' import { CompetitionContext } from '../api/helper/context/competition_context' import styles from './tabs.module.scss' export default function PageTabs() { const { competitionInfo } = useContext(CompetitionContext) - const { user } = useContext(AuthContext) const navigate = useNavigate() const panes = useMemo(() => { - const adminPanes = [] - if (canAdminCompetition(competitionInfo.id)) { - adminPanes.push({ - menuItem: ( - - navigate(`/competitions/${competitionInfo.id}/registrations/edit`) - } - > - - Registrations - - ), - render: () => {}, - }) - } return [ { menuItem: ( @@ -44,7 +24,25 @@ export default function PageTabs() { ), render: () => {}, }, - ...adminPanes, + ...(canAdminCompetition(competitionInfo.id) + ? { + menuItem: ( + + navigate( + `/competitions/${competitionInfo.id}/registrations/edit` + ) + } + > + + Registrations + + ), + render: () => {}, + } + : []), { menuItem: ( {}, }, + ...competitionInfo.tabs.map((tab) => { + return { + menuItem: ( + + navigate(`/competitions/${competitionInfo.id}/tabs/${tab.id}`) + } + > + {tab.name} + + ), + render: () => {}, + } + }), ] - }, [competitionInfo.id, navigate, user]) + }, [competitionInfo.id, competitionInfo.tabs, navigate]) return ( Date: Fri, 14 Jul 2023 23:08:41 +0200 Subject: [PATCH 13/13] Fixed Competitor not showing up for comps where registration was done --- Frontend/src/ui/Tabs.jsx | 63 ++++++++++++++++++++++------------------ 1 file changed, 35 insertions(+), 28 deletions(-) diff --git a/Frontend/src/ui/Tabs.jsx b/Frontend/src/ui/Tabs.jsx index 42feb95b..85e7b483 100644 --- a/Frontend/src/ui/Tabs.jsx +++ b/Frontend/src/ui/Tabs.jsx @@ -10,40 +10,26 @@ export default function PageTabs() { const { competitionInfo } = useContext(CompetitionContext) const navigate = useNavigate() const panes = useMemo(() => { - return [ - { + const optionalTabs = [] + if (canAdminCompetition(competitionInfo.id)) { + optionalTabs.push({ menuItem: ( navigate(`/competitions/${competitionInfo.id}`)} + onClick={() => + navigate(`/competitions/${competitionInfo.id}/registrations/edit`) + } > - - General Info + + Registrations ), render: () => {}, - }, - ...(canAdminCompetition(competitionInfo.id) - ? { - menuItem: ( - - navigate( - `/competitions/${competitionInfo.id}/registrations/edit` - ) - } - > - - Registrations - - ), - render: () => {}, - } - : []), - { + }) + } + if (new Date(competitionInfo.registration_open) < Date.now()) { + optionalTabs.push({ menuItem: ( ), render: () => {}, + }) + } + return [ + { + menuItem: ( + navigate(`/competitions/${competitionInfo.id}`)} + > + + General Info + + ), + render: () => {}, }, { menuItem: ( @@ -73,6 +74,7 @@ export default function PageTabs() { ), render: () => {}, }, + ...optionalTabs, ...competitionInfo.tabs.map((tab) => { return { menuItem: ( @@ -90,7 +92,12 @@ export default function PageTabs() { } }), ] - }, [competitionInfo.id, competitionInfo.tabs, navigate]) + }, [ + competitionInfo.id, + competitionInfo.registration_open, + competitionInfo.tabs, + navigate, + ]) return (