mirror of
https://github.com/evroon/bracket.git
synced 2026-04-23 00:36:58 -04:00
Frontend improvements (#253)
Install vercel analytics, update dependencies, show alerts in case there is no active stage.
This commit is contained in:
@@ -5,5 +5,6 @@ module.exports = {
|
||||
tabWidth: 2,
|
||||
importOrder: ["^@core/(.*)$", "^@server/(.*)$", "^@ui/(.*)$", "^[./]"],
|
||||
importOrderSeparation: true,
|
||||
importOrderSortSpecifiers: true
|
||||
};
|
||||
importOrderSortSpecifiers: true,
|
||||
plugins: [require.resolve("@trivago/prettier-plugin-sort-imports")]
|
||||
};
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
"@next/bundle-analyzer": "^13.3.1",
|
||||
"@react-icons/all-files": "^4.1.0",
|
||||
"@tabler/icons-react": "^2.17.0",
|
||||
"@vercel/analytics": "^1.0.2",
|
||||
"axios": "^1.4.0",
|
||||
"cookies-next": "^4.0.0",
|
||||
"date-fns": "^2.29.3",
|
||||
@@ -39,33 +40,33 @@
|
||||
"swr": "^2.1.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.21.0",
|
||||
"@next/eslint-plugin-next": "^13.2.3",
|
||||
"@testing-library/dom": "^9.2.0",
|
||||
"@testing-library/jest-dom": "^6.0.0",
|
||||
"@babel/core": "^7.22.17",
|
||||
"@next/eslint-plugin-next": "^13.4.19",
|
||||
"@testing-library/dom": "^9.3.1",
|
||||
"@testing-library/jest-dom": "^6.1.3",
|
||||
"@testing-library/react": "^14.0.0",
|
||||
"@testing-library/user-event": "^14.4.3",
|
||||
"@trivago/prettier-plugin-sort-imports": "^4.1.1",
|
||||
"@types/jest": "^29.5.2",
|
||||
"@types/node": "^20.1.0",
|
||||
"@types/react": "^18.2.0",
|
||||
"@typescript-eslint/eslint-plugin": "^6.2.1",
|
||||
"@typescript-eslint/parser": "^6.3.0",
|
||||
"babel-loader": "^9.1.2",
|
||||
"eslint": "^8.39.0",
|
||||
"@trivago/prettier-plugin-sort-imports": "^4.2.0",
|
||||
"@types/jest": "^29.5.4",
|
||||
"@types/node": "^20.6.0",
|
||||
"@types/react": "^18.2.21",
|
||||
"@typescript-eslint/eslint-plugin": "^6.6.0",
|
||||
"@typescript-eslint/parser": "^6.6.0",
|
||||
"babel-loader": "^9.1.3",
|
||||
"eslint": "^8.49.0",
|
||||
"eslint-config-airbnb": "^19.0.4",
|
||||
"eslint-config-airbnb-typescript": "^17.0.0",
|
||||
"eslint-config-airbnb-typescript": "^17.1.0",
|
||||
"eslint-config-mantine": "^2.0.0",
|
||||
"eslint-plugin-import": "^2.27.5",
|
||||
"eslint-plugin-jest": "^27.2.1",
|
||||
"eslint-plugin-import": "^2.28.1",
|
||||
"eslint-plugin-jest": "^27.2.3",
|
||||
"eslint-plugin-jsx-a11y": "^6.7.1",
|
||||
"eslint-plugin-react": "^7.32.1",
|
||||
"eslint-plugin-react": "^7.33.2",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"eslint-plugin-testing-library": "^6.0.0",
|
||||
"jest": "^29.5.0",
|
||||
"jest-environment-jsdom": "^29.5.0",
|
||||
"prettier": "^3.0.1",
|
||||
"ts-jest": "^29.1.0",
|
||||
"typescript": "^5.0.4"
|
||||
"eslint-plugin-testing-library": "^6.0.1",
|
||||
"jest": "^29.6.4",
|
||||
"jest-environment-jsdom": "^29.6.4",
|
||||
"prettier": "^3.0.3",
|
||||
"ts-jest": "^29.1.1",
|
||||
"typescript": "^5.2.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,6 +49,18 @@ export default function Brackets({
|
||||
activeStageId == null ||
|
||||
(!swrStagesResponse.isLoading && !responseIsValid(swrStagesResponse))
|
||||
) {
|
||||
if (readOnly) {
|
||||
return (
|
||||
<Alert
|
||||
icon={<IconAlertCircle size={16} />}
|
||||
title="No rounds found"
|
||||
color="blue"
|
||||
radius="lg"
|
||||
>
|
||||
Please wait for the organiser to add them.
|
||||
</Alert>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<Alert icon={<IconAlertCircle size={16} />} title="No rounds found" color="blue" radius="lg">
|
||||
Add a round using the top right button.
|
||||
|
||||
@@ -7,6 +7,7 @@ import { StageWithRounds } from '../../interfaces/stage';
|
||||
import { Tournament } from '../../interfaces/tournament';
|
||||
import UpcomingMatchesTable from '../tables/upcoming_matches';
|
||||
import LadderFixed from './settings/ladder_fixed';
|
||||
import SchedulingPlaceholder from './settings/placeholder';
|
||||
import RoundRobin from './settings/round_robin';
|
||||
|
||||
function StageSettings({
|
||||
@@ -16,7 +17,10 @@ function StageSettings({
|
||||
activeStage?: StageWithRounds;
|
||||
schedulerSettings: SchedulerSettings;
|
||||
}) {
|
||||
if (activeStage != null && activeStage.type === 'ROUND_ROBIN') {
|
||||
if (activeStage == null) {
|
||||
return <SchedulingPlaceholder />;
|
||||
}
|
||||
if (activeStage.type === 'ROUND_ROBIN') {
|
||||
return <RoundRobin />;
|
||||
}
|
||||
return <LadderFixed schedulerSettings={schedulerSettings} />;
|
||||
|
||||
11
frontend/src/components/scheduling/settings/placeholder.tsx
Normal file
11
frontend/src/components/scheduling/settings/placeholder.tsx
Normal file
@@ -0,0 +1,11 @@
|
||||
import { Alert } from '@mantine/core';
|
||||
import { IconAlertCircle } from '@tabler/icons-react';
|
||||
import React from 'react';
|
||||
|
||||
export default function SchedulingPlaceholder() {
|
||||
return (
|
||||
<Alert icon={<IconAlertCircle size={16} />} title="No options" color="yellow" radius="lg">
|
||||
There is no active stage.
|
||||
</Alert>
|
||||
);
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import { ColorScheme, ColorSchemeProvider, MantineProvider } from '@mantine/core';
|
||||
import { Notifications } from '@mantine/notifications';
|
||||
import { Analytics } from '@vercel/analytics/react';
|
||||
import { getCookie, setCookie } from 'cookies-next';
|
||||
import NextApp, { AppContext, AppProps } from 'next/app';
|
||||
import Head from 'next/head';
|
||||
@@ -31,6 +32,8 @@ export default function App(props: AppProps & { colorScheme: ColorScheme }) {
|
||||
<Component {...pageProps} />
|
||||
</MantineProvider>
|
||||
</ColorSchemeProvider>
|
||||
|
||||
<Analytics />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
} from '@mantine/core';
|
||||
import { FaGithub } from '@react-icons/all-files/fa/FaGithub';
|
||||
import { IconMoonStars, IconSun } from '@tabler/icons-react';
|
||||
import { useRouter } from 'next/router';
|
||||
import { NextRouter, useRouter } from 'next/router';
|
||||
import React, { Component, ReactNode } from 'react';
|
||||
|
||||
import { Brand } from '../components/navbar/_brand';
|
||||
@@ -26,7 +26,7 @@ const LINKS = [
|
||||
{ link: '/', label: 'Tournaments', links: null },
|
||||
{ link: '/user', label: 'User', links: [{ link: '/user', label: 'Logout', icon: null }] },
|
||||
{
|
||||
link: '/docs',
|
||||
link: null,
|
||||
label: 'More',
|
||||
links: [
|
||||
{ link: 'https://evroon.github.io/bracket/', label: 'Website', icon: null },
|
||||
@@ -78,15 +78,52 @@ const useStyles = createStyles((theme) => ({
|
||||
},
|
||||
}));
|
||||
|
||||
interface HeaderActionLink {
|
||||
link: string | null;
|
||||
label: string;
|
||||
icon?: Component | null;
|
||||
links?: { link: string; label: string; icon?: ReactNode }[] | null;
|
||||
}
|
||||
|
||||
interface HeaderActionProps {
|
||||
links: {
|
||||
link: string;
|
||||
label: string;
|
||||
icon?: Component | null;
|
||||
links?: { link: string; label: string; icon?: ReactNode }[] | null;
|
||||
}[];
|
||||
links: HeaderActionLink[];
|
||||
navbarState: any;
|
||||
}
|
||||
|
||||
function getMenuItemsForLink(link: HeaderActionLink, classes: any, router: NextRouter) {
|
||||
const menuItems = link.links?.map((item) => (
|
||||
<UnstyledButton
|
||||
key={item.label}
|
||||
className={classes.link}
|
||||
onClick={async () => {
|
||||
await router.push(item.link);
|
||||
}}
|
||||
>
|
||||
{item.label}
|
||||
</UnstyledButton>
|
||||
));
|
||||
return (
|
||||
<Menu key={link.label} trigger="hover" transitionProps={{ exitDuration: 0 }} withinPortal>
|
||||
<Menu.Target>
|
||||
<UnstyledButton
|
||||
className={classes.link}
|
||||
onClick={async () => {
|
||||
if (link.link) await router.push(link.link);
|
||||
}}
|
||||
>
|
||||
<>
|
||||
{link.icon}
|
||||
<Text span className={classes.linkLabel}>
|
||||
{link.label}
|
||||
</Text>
|
||||
</>
|
||||
</UnstyledButton>
|
||||
</Menu.Target>
|
||||
<Menu.Dropdown>{menuItems}</Menu.Dropdown>
|
||||
</Menu>
|
||||
);
|
||||
}
|
||||
|
||||
export function HeaderAction({ links, navbarState }: HeaderActionProps) {
|
||||
const { classes } = useStyles();
|
||||
|
||||
@@ -96,37 +133,7 @@ export function HeaderAction({ links, navbarState }: HeaderActionProps) {
|
||||
|
||||
const items = links.map((link) => {
|
||||
if (link.links) {
|
||||
const menuItems = link.links?.map((item) => (
|
||||
<UnstyledButton
|
||||
key={item.label}
|
||||
className={classes.link}
|
||||
onClick={async () => {
|
||||
await router.push(item.link);
|
||||
}}
|
||||
>
|
||||
{item.label}
|
||||
</UnstyledButton>
|
||||
));
|
||||
return (
|
||||
<Menu key={link.label} trigger="hover" transitionProps={{ exitDuration: 0 }} withinPortal>
|
||||
<Menu.Target>
|
||||
<UnstyledButton
|
||||
className={classes.link}
|
||||
onClick={async () => {
|
||||
await router.push(link.link);
|
||||
}}
|
||||
>
|
||||
<>
|
||||
{link.icon}
|
||||
<Text span className={classes.linkLabel}>
|
||||
{link.label}
|
||||
</Text>
|
||||
</>
|
||||
</UnstyledButton>
|
||||
</Menu.Target>
|
||||
<Menu.Dropdown>{menuItems}</Menu.Dropdown>
|
||||
</Menu>
|
||||
);
|
||||
return getMenuItemsForLink(link, classes, router);
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -134,7 +141,7 @@ export function HeaderAction({ links, navbarState }: HeaderActionProps) {
|
||||
key={link.label}
|
||||
className={classes.link}
|
||||
onClick={async () => {
|
||||
await router.push(link.link);
|
||||
if (link.link) await router.push(link.link);
|
||||
}}
|
||||
>
|
||||
{link.label}
|
||||
|
||||
1736
frontend/yarn.lock
1736
frontend/yarn.lock
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user