switch to pigment

This commit is contained in:
Mario Peters
2025-06-09 13:08:21 +02:00
parent b2bc187874
commit e11f8f5799
50 changed files with 1036 additions and 369 deletions

1010
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "kt-vite",
"version": "3.2.0",
"version": "3.3.0",
"private": true,
"homepage": "https://karateturniere.de",
"type": "module",
@@ -16,13 +16,13 @@
"analyze": "source-map-explorer 'dist/**/*.js'",
"test": "vitest",
"test:e2e": "playwright test",
"i18n": "i18next 'src/**/*.{js,jsx,ts,tsx}' --config i18next-parser.config.cjs"
"i18n": "i18next 'src/**/*.{js,jsx,ts,tsx}' --config i18next-parser.config.mjs"
},
"dependencies": {
"@emotion/react": "^11.14.0",
"@emotion/styled": "^11.14.0",
"@mui/icons-material": "^7.1.1",
"@mui/material": "^7.1.1",
"@mui/material-pigment-css": "^7.1.1",
"@pigment-css/react": "^0.0.30",
"@react-pdf/renderer": "^4.3.0",
"i18next": "^25.2.1",
"i18next-http-backend": "^3.0.2",
@@ -36,6 +36,7 @@
"@eslint/compat": "^1.2.9",
"@eslint/eslintrc": "^3.3.1",
"@eslint/js": "^9.28.0",
"@pigment-css/vite-plugin": "^0.0.30",
"@playwright/test": "^1.52.0",
"@testing-library/jest-dom": "^6.6.3",
"@testing-library/react": "^16.3.0",
@@ -56,4 +57,4 @@
"vite-plugin-eslint": "^1.8.1",
"vitest": "^3.2.2"
}
}
}

View File

@@ -1,6 +1,6 @@
import { lazy, Suspense, useEffect, useState } from 'react'
import { BrowserRouter, Route, Routes } from 'react-router-dom'
import { Button, createTheme, ThemeProvider } from '@mui/material'
import { Button } from '@mui/material'
import { StyledEngineProvider } from '@mui/material/styles'
import ExitToApp from '@mui/icons-material/ExitToApp'
import { useTranslation } from 'react-i18next'
@@ -14,7 +14,7 @@ import Spinner from './components/Spinner/Spinner'
import LoadParticipants from './components/UseFetch/LoadParticipants'
import useFetch from './components/UseFetch/UseFetch'
import LoginDialog from './components/LoginDialog/LoginDialog'
import { getStoredToken, storeToken, checkToken } from './api/account'
import { getStoredToken, storeToken, checkToken } from './api/account.js'
import { UserContext } from './context/UserContext'
const Tournaments = lazy(() => import('./components/Tournaments/Tournaments'))
@@ -29,23 +29,6 @@ const OnePDFList = lazy(() => import('./pages/OnePDFList'))
const Impress = lazy(() => import('./pages/Impress'))
const Dataprotection = lazy(() => import('./pages/Dataprotection'))
const theme = createTheme({
palette: {
primary: {
light: '#757ce8',
main: '#3f50b5',
dark: '#002884',
contrastText: '#fff',
},
secondary: {
light: '#ff7961',
main: '#f50057',
dark: '#c51162',
contrastText: '#000',
},
},
})
export default function App() {
const apiServer = import.meta.env.VITE_API_SERVER
const [participants, setParticipants] = useState(null)
@@ -112,69 +95,67 @@ export default function App() {
return (
<StyledEngineProvider injectFirst>
<ThemeProvider theme={theme}>
<UserContext.Provider value={{ user, setUser, token, setToken, apiServer }}>
<DialogContext.Provider value={dialog}>
<BrowserRouter>
<div className="App">
{/* // TODO: mail Formular für alle, Turnier gemeldeten, abfrage, ob alle mails, oder nur für gemedelte turiere. */}
{/* // TODO: Alle Rechnungen des Turniers generieren. */}
<AppBar openLoginDialog={openLoginDialog} handleToken={handleToken} />
<main className="content">
{token && <LoadParticipants setParticipants={setParticipants} />}
<Suspense fallback={<Spinner />}>
<Routes>
<Route
path="registration/:tid"
element={participants && tournaments && groups && <Registration participants={participants} groups={groups} tournaments={tournaments} />}
/>
<Route path="results/:tid" element={<Results />} />
<Route path="live/:tid" element={<Live />} />
<Route path="stream/:tid" element={<Streams />} />
<Route path="info/:tid" element={<Info />} />
<Route path="mail/:tid" element={<Mail tournaments={tournaments} />} />
<Route path="pdf/lists/:tid/" element={<TournamentPDFLists />} />
<Route path="pdf/lists/:tid/one/:gid" element={<OnePDFList />} />
<Route path="impress" element={<Impress />} />
<Route path="dataprotection" element={<Dataprotection />} />
<Route
path="/"
element={
<>
{tournaments && (
<Tournaments
groups={groups}
tournaments={tournaments}
setTournaments={setTournaments}
participants={participants}
setParticipants={setParticipants}
/>
)}
<br />
<br />
{!participants && (
<>
<h3>{t('headline.participants')}</h3>
<p>{t('no-login')}</p>
<Button onClick={() => openLoginDialog(null)} color="primary" variant="outlined" startIcon={<ExitToApp />}>
{t('login')}
</Button>
</>
)}
{participants && <Participants participants={participants} />}
</>
}
/>
</Routes>
</Suspense>
</main>
<Footer />
<DialogController />
</div>
</BrowserRouter>
</DialogContext.Provider>
</UserContext.Provider>
</ThemeProvider>
<UserContext.Provider value={{ user, setUser, token, setToken, apiServer }}>
<DialogContext.Provider value={dialog}>
<BrowserRouter>
<div className="App">
{/* // TODO: mail Formular für alle, Turnier gemeldeten, abfrage, ob alle mails, oder nur für gemedelte turiere. */}
{/* // TODO: Alle Rechnungen des Turniers generieren. */}
<AppBar openLoginDialog={openLoginDialog} handleToken={handleToken} />
<main className="content">
{token && <LoadParticipants setParticipants={setParticipants} />}
<Suspense fallback={<Spinner />}>
<Routes>
<Route
path="registration/:tid"
element={participants && tournaments && groups && <Registration participants={participants} groups={groups} tournaments={tournaments} />}
/>
<Route path="results/:tid" element={<Results />} />
<Route path="live/:tid" element={<Live />} />
<Route path="stream/:tid" element={<Streams />} />
<Route path="info/:tid" element={<Info />} />
<Route path="mail/:tid" element={<Mail tournaments={tournaments} />} />
<Route path="pdf/lists/:tid/" element={<TournamentPDFLists />} />
<Route path="pdf/lists/:tid/one/:gid" element={<OnePDFList />} />
<Route path="impress" element={<Impress />} />
<Route path="dataprotection" element={<Dataprotection />} />
<Route
path="/"
element={
<>
{tournaments && (
<Tournaments
groups={groups}
tournaments={tournaments}
setTournaments={setTournaments}
participants={participants}
setParticipants={setParticipants}
/>
)}
<br />
<br />
{!participants && (
<>
<h3>{t('headline.participants')}</h3>
<p>{t('no-login')}</p>
<Button onClick={() => openLoginDialog(null)} color="primary" variant="outlined" startIcon={<ExitToApp />}>
{t('login')}
</Button>
</>
)}
{participants && <Participants participants={participants} />}
</>
}
/>
</Routes>
</Suspense>
</main>
<Footer />
<DialogController />
</div>
</BrowserRouter>
</DialogContext.Provider>
</UserContext.Provider>
</StyledEngineProvider>
)
}

View File

@@ -1,9 +1,10 @@
import { useState } from 'react'
import { AccountCircle } from '@mui/icons-material'
import { Link } from 'react-router-dom'
import { styled, AppBar, Toolbar, Typography, IconButton, MenuItem, Menu } from '@mui/material'
import { AppBar, Toolbar, Typography, IconButton, MenuItem, Menu } from '@mui/material'
import { useTranslation } from 'react-i18next'
import { useUser } from '../../context/UserContext'
import { styled } from '@mui/material-pigment-css'
const PREFIX = 'AppBar'
const classes = {

View File

@@ -1,7 +1,7 @@
import InputBase from '@mui/material/InputBase'
import SearchIcon from '@mui/icons-material/Search'
import { styled, alpha } from '@mui/material/styles'
import { styled } from '@mui/material-pigment-css'
import { alpha } from '@mui/material/styles'
const Search = styled('div')(({ theme }) => ({
display: 'flex',
position: 'relative',

View File

@@ -8,7 +8,9 @@ export default function Points(props) {
for (let i = 0; i < num; i++) {
result.push(
<FormControl key={id + i} sx={{ m: 1, maxWidth: 60 }} size="small">
<TextField label={'# ' + (i + 1)} name={id + '/' + i} defaultValue={results ? results[i] : average} size="small" inputProps={{ ref: myRef }} onChange={handlePointsChange} />
<TextField label={'# ' + (i + 1)} name={id + '/' + i} defaultValue={results ? results[i] : average} size="small" onChange={handlePointsChange} slotProps={{
htmlInput: { ref: myRef }
}} />
</FormControl>,
)
}

View File

@@ -1,9 +1,10 @@
import { FormControl, InputLabel, MenuItem, Select, TextField, styled } from '@mui/material'
import { FormControl, InputLabel, MenuItem, Select, TextField } from '@mui/material'
import { useEffect, useRef, useState } from 'react'
import KataSelect from '../Kata/KataSelect'
import useFetch from '../UseFetch/UseFetch'
import Points from './Points'
import { useUser } from '../../context/UserContext'
import { styled } from '@mui/material-pigment-css'
const PREFIX = 'PointsView'

View File

@@ -1,6 +1,6 @@
import CloseIcon from '@mui/icons-material/Close'
import { lazy, useEffect, useState, useRef } from 'react'
import { AppBar, Button, Dialog, IconButton, styled, Toolbar, Typography, TextField } from '@mui/material'
import { AppBar, Button, Dialog, IconButton, Toolbar, Typography, TextField } from '@mui/material'
import PointsView from '../Competition/PointsView'
import GroupInfo from '../Groups/GroupInfo'
import KoView from '../Groups/KoView'
@@ -9,8 +9,9 @@ import { generateRounds } from '../../utilities/Rounds'
const ListPDFTemplate = lazy(() => import('../PDF/ListPDFTemplate'))
import { pdf } from '@react-pdf/renderer'
import { savePdf } from '../../utilities/PDF'
import { changeEncounter, setWinner, addResults, lateRegistration } from '../../api/encounter'
import { changeEncounter, setWinner, addResults, lateRegistration } from '../../api/encounter.js'
import { useUser } from '../../context/UserContext'
import { styled } from '@mui/material-pigment-css'
const PREFIX = 'EncounterDialog'
const classes = {
@@ -173,7 +174,9 @@ export default function EncounterDialog(props) {
</Button>
{user?.admin > 4 && (
<>
<TextField id="tid" inputProps={{ ref: inputRef }} label="tid" type="number" variant="filled" size="small" />
<TextField id="tid" label="tid" type="number" variant="filled" size="small" slotProps={{
htmlInput: { ref: inputRef }
}} />
<Button variant="outlined" color="secondary" onClick={lateRegistrationHandler}>
lateRegistration
</Button>
@@ -185,5 +188,5 @@ export default function EncounterDialog(props) {
{koView && <KoView rounds={rounds} />}
{!koView && <PointsView groupData={groupData} allParticipants={allParticipants} allTeams={allTeams} />}
</StyledDialog>
)
);
}

View File

@@ -4,7 +4,7 @@ import { useTranslation } from 'react-i18next'
import OneGroup from './OneGroup'
import { Add } from '@mui/icons-material'
import { Button, DialogActions, DialogContent, DialogTitle, IconButton } from '@mui/material'
import { addGroups } from '../../api/groups'
import { addGroups } from '../../api/groups.js'
import { useUser } from '../../context/UserContext'
export default function AddGroups({ tid }) {

View File

@@ -1,6 +1,6 @@
import { useContext } from 'react'
import { DialogContext } from '../../context/DialogContext'
import { deleteGroup } from '../../api/groups'
import { deleteGroup } from '../../api/groups.js'
import { UserContext } from '../../context/UserContext'
import { Button, DialogActions, DialogTitle } from '@mui/material'

View File

@@ -1,7 +1,7 @@
import { useContext, useEffect, useState, Suspense, lazy } from 'react'
import { DialogContext } from '../../context/DialogContext'
import { useTranslation } from 'react-i18next'
import { editGroups } from '../../api/groups'
import { editGroups } from '../../api/groups.js'
import { Button, DialogActions, DialogContent, DialogTitle, CircularProgress } from '@mui/material'
import { useUser } from '../../context/UserContext'
const OneGroup = lazy(() => import('./OneGroup'))
@@ -52,10 +52,7 @@ export default function EditGroups({ groups, tid }) {
<DialogTitle id="form-dialog-title">{t('groups.edit')}</DialogTitle>
<DialogContent>
<Suspense fallback={<CircularProgress size={32} />}>
{formData.length > 0 &&
formData.map((group, index) => (
<OneGroup key={group?.id ?? index} myKey={index} formData={formData} setFormData={setFormData} isEditMode={true} />
))}
{formData.length > 0 && formData.map((group, index) => <OneGroup key={group?.id ?? index} myKey={index} formData={formData} setFormData={setFormData} isEditMode={true} />)}
</Suspense>
</DialogContent>
<DialogActions>

View File

@@ -1,4 +1,5 @@
import { styled, Card, CardContent } from '@mui/material'
import { Card, CardContent } from '@mui/material'
import { styled } from '@mui/material-pigment-css'
const StyledCard = styled(Card)({
minWidth: 275,

View File

@@ -1,9 +1,9 @@
import useFetch from '../UseFetch/UseFetch'
import { getAge } from '../../utilities/Date'
import { Chip } from '@mui/material'
import { styled } from '@mui/material/styles'
import { beltColor } from '../../utilities/Belt'
import { useUser } from '../../context/UserContext'
import { styled } from '@mui/material-pigment-css'
const PREFIX = 'GroupsParticipants'
const classes = {

View File

@@ -1,6 +1,6 @@
import { styled } from '@mui/material/styles'
import useFetch from '../UseFetch/UseFetch'
import { useUser } from '../../context/UserContext'
import { styled } from '@mui/material-pigment-css'
const PREFIX = 'GroupTeams'
const classes = {

View File

@@ -2,7 +2,7 @@ import { useState } from 'react'
import useFetch from '../UseFetch/UseFetch'
import EncounterDialog from '../Dialog/EncounterDialog'
import GroupsTable from './GroupsTable'
import { triggerGroup } from '../../api/groups'
import { triggerGroup } from '../../api/groups.js'
import { useUser } from '../../context/UserContext'
export default function Groups({ tournamentGroups, tournamentData, participants }) {

View File

@@ -1,6 +1,6 @@
import { useContext, useState, useCallback } from 'react'
import { useTranslation } from 'react-i18next'
import { Accordion, AccordionSummary, AccordionDetails, Chip, IconButton, Tooltip, styled, Pagination } from '@mui/material'
import { Accordion, AccordionSummary, AccordionDetails, Chip, IconButton, Tooltip, Pagination } from '@mui/material'
import { Person, Group, GridView, Pin, AccountTree, SafetyDivider, List, Expand as ExpandIcon, ExpandMore as ExpandMoreIcon } from '@mui/icons-material'
import { beltColor } from '../../utilities/Belt'
import { countGroups } from '../../utilities/Groups'
@@ -9,9 +9,10 @@ import DeleteGroupDialog from './DeleteGroupDialog'
import GroupParticipants from './GroupParticipants'
import GroupTeams from './GroupTeams'
import SearchBar from '../Common/SearchBar'
import { triggerFinalists, splitGroup, moveToGroup } from '../../api/groups'
import { triggerFinalists, splitGroup, moveToGroup } from '../../api/groups.js'
import { useUser } from '../../context/UserContext'
import { DeleteOutline } from '@mui/icons-material'
import { styled } from '@mui/material-pigment-css'
const PREFIX = 'GroupsTable'
const classes = {

View File

@@ -1,5 +1,6 @@
import KoEncounterItem from './KoEncounterItem'
import { styled, Card, CardContent } from '@mui/material'
import { Card, CardContent } from '@mui/material'
import { styled } from '@mui/material-pigment-css'
const PREFIX = 'KoEncounter'
const classes = {

View File

@@ -1,5 +1,6 @@
import EmojiEventsIcon from '@mui/icons-material/EmojiEvents'
import { styled, IconButton } from '@mui/material'
import { IconButton } from '@mui/material'
import { styled } from '@mui/material-pigment-css'
const PREFIX = 'KoEncounterItem'
const classes = {

View File

@@ -1,4 +1,4 @@
import { styled } from '@mui/material'
import { styled } from '@mui/material-pigment-css'
const PREFIX = 'KoView'
const classes = {

View File

@@ -1,11 +1,12 @@
import { useContext, useMemo } from 'react'
import { DialogActions, DialogContent, DialogTitle, FormControl, IconButton, InputLabel, MenuItem, Select, styled, Button, TextField } from '@mui/material'
import { DialogActions, DialogContent, DialogTitle, FormControl, IconButton, InputLabel, MenuItem, Select, Button, TextField } from '@mui/material'
import { useTranslation } from 'react-i18next'
import { Delete } from '@mui/icons-material'
import { DialogContext } from '../../context/DialogContext'
import AddGroups from './AddGroups'
import { deleteGroup } from '../../api/groups'
import { deleteGroup } from '../../api/groups.js'
import { useUser } from '../../context/UserContext'
import { styled } from '@mui/material-pigment-css'
const PREFIX = 'OneGroup'
const classes = {

View File

@@ -1,9 +1,11 @@
import { useContext, useState } from 'react'
import { DialogContext } from '../../context/DialogContext.jsx'
import { DialogContent, Button, Container, CssBaseline, Grid, Link, TextField } from '@mui/material'
import { DialogContent, Button, CssBaseline, Link, TextField } from '@mui/material'
import { useTranslation } from 'react-i18next'
import { login as loginApi } from '../../api/account.js'
import { useUser } from '../../context/UserContext.jsx'
import Container from '@mui/material-pigment-css/Container'
import Grid from '@mui/material-pigment-css/Grid'
export default function LoginContent({ handleToken, setState }) {
const { apiServer, user } = useUser()

View File

@@ -144,8 +144,10 @@ export const SignUpEditContent = () => {
fullWidth
value={formData.passwort || ''}
onChange={handleChange}
inputProps={{ minLength: 8, maxLength: 30 }}
helperText={pwError ? t('signUp.pwNoMatch') : t('signUp.sign') + ' (8-30)'}
slotProps={{
htmlInput: { minLength: 8, maxLength: 30 },
}}
/>
<TextField
id="pw2"
@@ -159,8 +161,10 @@ export const SignUpEditContent = () => {
fullWidth
value={formData.passwort2 || ''}
onChange={handleChange}
inputProps={{ minLength: 8, maxLength: 30 }}
helperText={pwError ? t('signUp.pwNoMatch') : t('signUp.sign') + ' (8-30)'}
slotProps={{
htmlInput: { minLength: 8, maxLength: 30 },
}}
/>
<TextField margin="dense" name="telefon" variant="standard" label={t('phone')} type="text" fullWidth value={formData.telefon} onChange={handleChange} />
</DialogContent>

View File

@@ -3,7 +3,7 @@ import useFetch from '../UseFetch/UseFetch'
import { DialogContext } from '../../context/DialogContext'
import { Button, TextField, DialogActions, DialogContent, DialogTitle, Radio, RadioGroup, FormControlLabel, FormControl, FormLabel, InputLabel, MenuItem, Select, Autocomplete } from '@mui/material'
import { useTranslation } from 'react-i18next'
import { addParticipant, editParticipant } from '../../api/participants'
import { addParticipant, editParticipant } from '../../api/participants.js'
import { BeltClass } from '../../utilities/Belt'
import { useUser } from '../../context/UserContext'
const BELTS = ['9. Kyu', '8. Kyu', '7. Kyu', '6. Kyu', '5. Kyu', '4. Kyu', '3. Kyu', '2. Kyu', '1. Kyu', 'DAN']
@@ -97,11 +97,13 @@ export default function AddEditParticipant({ edit, setEdit }) {
name="gebDatum"
variant="standard"
label={t('participant.birthDate')}
InputLabelProps={{ shrink: true }}
type="date"
fullWidth
value={formData.gebDatum}
onChange={handleChange}
slotProps={{
inputLabel: { shrink: true },
}}
/>
<FormControl component="fieldset" margin="dense">
<FormLabel component="legend">{t('participant.gender')}</FormLabel>

View File

@@ -1,11 +1,12 @@
import { useContext, useState } from 'react'
import { styled, Button } from '@mui/material'
import { Button } from '@mui/material'
import { useTranslation } from 'react-i18next'
import { DialogContext } from '../../context/DialogContext'
import AddEditParticipant from './AddEditParticipant'
import ParticipantsMobile from './ParticipantsMobile'
import { addParticipant, editParticipant, deleteParticipant } from '../../api/participants'
import { addParticipant, editParticipant, deleteParticipant } from '../../api/participants.js'
import { useUser } from '../../context/UserContext'
import { styled } from '@mui/material-pigment-css'
const PREFIX = 'Participants'
const classes = {

View File

@@ -1,6 +1,6 @@
import { useContext, useState } from 'react'
import { useParams } from 'react-router-dom'
import { Avatar, Chip, FormControlLabel, IconButton, styled, Switch, Pagination } from '@mui/material'
import { Avatar, Chip, FormControlLabel, IconButton, Switch, Pagination } from '@mui/material'
import { DeleteOutline, Edit } from '@mui/icons-material'
import PersonIcon from '@mui/icons-material/Person'
import { beltColor } from '../../utilities/Belt'
@@ -9,6 +9,7 @@ import { DialogContext } from '../../context/DialogContext'
import AddEditParticipant from './AddEditParticipant'
import DeleteDialog from './DeleteDialog'
import SearchBar from '../Common/SearchBar'
import { styled } from '@mui/material-pigment-css'
const PREFIX = 'ParticipantsMobile'
const classes = {

View File

@@ -1,5 +1,5 @@
import { styled } from '@mui/material'
import { useTranslation } from 'react-i18next'
import { styled } from '@mui/material-pigment-css'
const TableWrapper = styled('div')(({ theme }) => ({
width: '100%',

View File

@@ -1,6 +1,7 @@
import { Add, Remove } from '@mui/icons-material'
import PersonIcon from '@mui/icons-material/Person'
import { Avatar, Chip, IconButton, styled } from '@mui/material'
import { Avatar, Chip, IconButton } from '@mui/material'
import { styled } from '@mui/material-pigment-css'
const PREFIX = 'TeamRegistrationMobile'
const classes = {

View File

@@ -1,6 +1,6 @@
import { useState } from 'react'
import { TextField, Button } from '@mui/material'
import { addResults } from '../../api/results'
import { addResults } from '../../api/results.js'
import { useUser } from '../../context/UserContext'
export default function PostResult({ groups, setGroups }) {

View File

@@ -1,4 +1,4 @@
import { styled } from '@mui/material'
import { styled } from '@mui/material-pigment-css'
const PREFIX = 'ResultsEntry'
const classes = {

View File

@@ -1,5 +1,6 @@
import ResultsEntry from './ResultsEntry'
import { Chip, styled, Avatar } from '@mui/material'
import { Chip, Avatar } from '@mui/material'
import { styled } from '@mui/material-pigment-css'
const PREFIX = 'ResultsEntryContainer'
const classes = {
@@ -9,7 +10,7 @@ const classes = {
chip: `${PREFIX}-chip`,
}
const Root = styled('div')(({ theme }) => ({
const Root = styled('div')(() => ({
[`&.${classes.groupResult}`]: {
backgroundColor: 'rgba(0,0,0,0.2)',
margin: '1rem 0',

View File

@@ -1,8 +1,8 @@
import { Box, CircularProgress } from '@mui/material'
import { CircularProgress } from '@mui/material'
export default function Spinner() {
return (
<Box
<div
sx={{
display: 'flex',
minWidth: '100%',
@@ -12,6 +12,6 @@ export default function Spinner() {
}}
>
<CircularProgress size={60} />
</Box>
</div>
)
}

View File

@@ -1,8 +1,9 @@
import { useContext, useEffect, useState } from 'react'
import { FormLabel, InputAdornment, styled, Button, TextField, DialogActions, DialogContent, DialogTitle } from '@mui/material'
import { FormLabel, InputAdornment, Button, TextField, DialogActions, DialogContent, DialogTitle } from '@mui/material'
import { DialogContext } from '../../context/DialogContext'
import { useTranslation } from 'react-i18next'
import { addTournament, editTournament } from '../../api/tournaments'
import { addTournament, editTournament } from '../../api/tournaments.js'
import { styled } from '@mui/material-pigment-css'
const PREFIX = 'AddEditTournament'
const classes = {
@@ -10,7 +11,7 @@ const classes = {
halfSize: `${PREFIX}-halfSize`,
}
const Root = styled('div')(({ theme }) => ({
const Root = styled('div')(() => ({
[`& .${classes.formGroup}`]: {
margin: '1rem 0',
backgroundColor: '#ebebeb',
@@ -109,48 +110,56 @@ export default function AddEditTournament({ token, apiServer, tournament, tourna
className={classes.halfSize}
required
name="veranstaltungsDatum"
InputLabelProps={{ shrink: true }}
label={t('date')}
type="date"
value={toDateInput(formData.veranstaltungsDatum)}
onChange={handleChange}
slotProps={{
inputLabel: { shrink: true },
}}
/>
<TextField
variant="standard"
className={classes.halfSize}
required
name="meldeschluss"
InputLabelProps={{ shrink: true }}
label={t('closing-date')}
type="date"
value={toDateInput(formData.meldeschluss)}
onChange={handleChange}
slotProps={{
inputLabel: { shrink: true },
}}
/>
<TextField
variant="standard"
className={classes.halfSize}
required
InputProps={{
endAdornment: <InputAdornment position="start"></InputAdornment>,
}}
name="startgebuehr"
label={t('single-fee')}
type="text"
value={formData.startgebuehr}
onChange={handleChange}
slotProps={{
input: {
endAdornment: <InputAdornment position="start"></InputAdornment>,
},
}}
/>
<TextField
variant="standard"
className={classes.halfSize}
required
InputProps={{
endAdornment: <InputAdornment position="start"></InputAdornment>,
}}
name="startgebuehrTeam"
label={t('team-fee')}
type="text"
value={formData.startgebuehrTeam}
onChange={handleChange}
slotProps={{
input: {
endAdornment: <InputAdornment position="start"></InputAdornment>,
},
}}
/>
</div>
<div className={classes.formGroup}>

View File

@@ -1,6 +1,6 @@
import { useContext } from 'react'
import { DialogContext } from '../../context/DialogContext'
import { deleteTournament } from '../../api/tournaments'
import { deleteTournament } from '../../api/tournaments.js'
import { Button, DialogActions, DialogTitle } from '@mui/material'
import { useUser } from '../../context/UserContext'

View File

@@ -8,7 +8,7 @@ import EditGroups from '../Groups/EditGroups'
import AddEditTournament from './AddEditTournament'
import DeleteTournamentDialog from './DeleteTournamentDialog'
import TriggerGroupsDialog from './TriggerGroupsDialog'
import { createPools, createFinalGroups } from '../../api/tournaments'
import { createPools, createFinalGroups } from '../../api/tournaments.js'
import { useUser } from '../../context/UserContext'
export default function TournamentMenu({ anchorEl, open, onOpen, onClose, tournament, tournamentGroups, tournaments, setTournaments, handleClose }) {

View File

@@ -4,9 +4,10 @@ import { filterObject } from '../../utilities/Groups'
import { PostAdd, PersonAdd } from '@mui/icons-material'
import AddEditTournament from './AddEditTournament'
import AddEditParticipant from '../Participants/AddEditParticipant'
import { SpeedDial, SpeedDialAction, SpeedDialIcon, styled } from '@mui/material'
import { SpeedDial, SpeedDialAction, SpeedDialIcon } from '@mui/material'
import { DialogContext } from '../../context/DialogContext'
import { useUser } from '../../context/UserContext'
import { styled } from '@mui/material-pigment-css'
const PREFIX = 'Tournaments'
const classes = {

View File

@@ -1,5 +1,5 @@
import { useState } from 'react'
import { Avatar, Button, Card, CardActions, CardContent, CardHeader, Collapse, IconButton, Tooltip, styled, Box } from '@mui/material'
import { Avatar, Button, Card, CardActions, CardContent, CardHeader, Collapse, IconButton, Tooltip } from '@mui/material'
import { grey, red } from '@mui/material/colors'
import {
DateRange as DateRangeIcon,
@@ -15,6 +15,8 @@ import { useTranslation } from 'react-i18next'
import { Link as RouterLink } from 'react-router-dom'
import Groups from '../Groups/Groups'
import TournamentMenu from './TournamentMenu'
import { styled } from '@mui/material-pigment-css'
import { useUser } from '../../context/UserContext'
const PREFIX = 'TournamentsCard'
const classes = {
@@ -183,7 +185,8 @@ const StyledCard = styled(Card)(({ theme }) => ({
},
}))
export default function TournamentsCard({ apiServer, tournament, tournaments, setTournaments, tournamentGroups, token, user, participants }) {
export default function TournamentsCard({ tournament, tournaments, setTournaments, tournamentGroups, participants }) {
const { user } = useUser()
const [expanded, setExpanded] = useState(false)
const [anchorEl, setAnchorEl] = useState(null)
const { t } = useTranslation('common')
@@ -215,13 +218,13 @@ export default function TournamentsCard({ apiServer, tournament, tournaments, se
action={
<div className={classes.titleAction}>
{user?.account && (
<Box sx={{ display: { xs: 'none', sm: 'flex' }, alignItems: 'center' }}>
<div sx={{ display: { xs: 'none', sm: 'flex' }, alignItems: 'center' }}>
<RouterLink to={`registration/${tournament.id}`} className={classes.routerLink}>
<Button color="primary" variant="contained">
{t('tournament.registration')}
</Button>
</RouterLink>
</Box>
</div>
)}
{(user?.admin > 9 || +user?.account === tournament?.account_id) && (
<TournamentMenu
@@ -280,13 +283,13 @@ export default function TournamentsCard({ apiServer, tournament, tournaments, se
</div>
{user?.account && (
<Box sx={{ display: { xs: 'block', sm: 'none' }, px: 2, mt: 1, mb: 1 }}>
<div sx={{ display: { xs: 'block', sm: 'none' }, px: 2, mt: 1, mb: 1 }}>
<RouterLink to={`registration/${tournament.id}`} className={classes.routerLink}>
<Button color="primary" variant="contained" fullWidth>
{t('tournament.registration')}
</Button>
</RouterLink>
</Box>
</div>
)}
<CardActions className={classes.cardAction}>

View File

@@ -1,7 +1,7 @@
import { DialogContent, DialogContentText, Button, DialogActions, DialogTitle } from '@mui/material'
import { useContext } from 'react'
import { DialogContext } from '../../context/DialogContext'
import { triggerGroup } from '../../api/groups'
import { triggerGroup } from '../../api/groups.js'
export default function TriggerGroupsDialog({ apiServer, token, tournamentGroups }) {
const dialog = useContext(DialogContext)

View File

@@ -1,8 +1,9 @@
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'
import '@mui/material-pigment-css/styles.css'
import './index.css'
import './i18n'
import './i18nm.js'
ReactDOM.createRoot(document.getElementById('root')).render(
<React.StrictMode>

View File

@@ -1,14 +1,15 @@
import { Button, styled } from '@mui/material'
import { Button } from '@mui/material'
import ArrowBackIcon from '@mui/icons-material/ArrowBack'
import { useTranslation } from 'react-i18next'
import { Link } from 'react-router-dom'
import { styled } from '@mui/material-pigment-css'
const PREFIX = 'Dataprotection'
const classes = {
routerLink: `${PREFIX}-routerLink`,
}
const Root = styled('div')(({ theme }) => ({
const Root = styled('div')(() => ({
[`& .${classes.routerLink}`]: {
textDecoration: 'inherit',
},

View File

@@ -1,7 +1,8 @@
import { Button, styled } from '@mui/material'
import { Button} from '@mui/material'
import ArrowBackIcon from '@mui/icons-material/ArrowBack'
import { useTranslation } from 'react-i18next'
import { Link } from 'react-router-dom'
import { styled } from '@mui/material-pigment-css'
const PREFIX = 'Impress'
const classes = {

View File

@@ -1,9 +1,10 @@
import { useParams, Link } from 'react-router-dom'
import ArrowBackIcon from '@mui/icons-material/ArrowBack'
import useFetch from '../components/UseFetch/UseFetch'
import { styled, Button } from '@mui/material'
import { Button } from '@mui/material'
import { useTranslation } from 'react-i18next'
import { useUser } from '../context/UserContext'
import { styled } from '@mui/material-pigment-css'
const PREFIX = 'Info'
const classes = {

View File

@@ -1,8 +1,9 @@
import { useEffect, useState, useRef } from 'react'
import { useParams } from 'react-router-dom'
import { styled, Paper } from '@mui/material'
import { Paper } from '@mui/material'
import { useTranslation } from 'react-i18next'
import { useUser } from '../context/UserContext'
import { styled } from '@mui/material-pigment-css'
const PREFIX = 'Live'
const classes = {
@@ -44,7 +45,7 @@ function Encounters({ encounters }) {
}
export default function Live() {
const { token, } = useUser()
const { token } = useUser()
const { t } = useTranslation('common')
const { tid } = useParams()
const [data, setData] = useState({

View File

@@ -1,9 +1,10 @@
import { InputLabel, MenuItem, Select, FormControl, styled, TextField, Button } from '@mui/material'
import { InputLabel, MenuItem, Select, FormControl, TextField, Button } from '@mui/material'
import ArrowForwardIcon from '@mui/icons-material/ArrowForward'
import { useState } from 'react'
import { useParams } from 'react-router-dom'
import { sendMail } from '../api/mail'
import { sendMail } from '../api/mail.js'
import { useUser } from '../context/UserContext'
import { styled } from '@mui/material-pigment-css'
const PREFIX = 'Mail'
const classes = {
@@ -11,7 +12,7 @@ const classes = {
routerLink: `${PREFIX}-routerLink`,
}
const Root = styled('div')(({ theme }) => ({
const Root = styled('div')(() => ({
[`& .${classes.stream}`]: {
backgroundColor: 'rgba(0,0,0,0.2)',
},
@@ -46,11 +47,11 @@ Mario Peters`,
]
function nl2br(str) {
return (str + '').replace(/([^>\r\n]?)(\r\n|\n\r|\r|\n)/g, '$1<br />')
return (str + '').replace(/([^>\r\n]?)(\r\n|\n\r|\r|\n)/g, '$1<br />');
}
function br2nl(str) {
return str.replace(/<\s*\/?br\s*[\/]?>/gi, '\n')
return str.replace(/<\s*\/?br\s*[\/]?>/gi, '\n');
}
export default function Mail({ tournaments }) {

View File

@@ -1,6 +1,6 @@
import { lazy, useEffect, useRef, useState } from 'react'
import { Link, useParams } from 'react-router-dom'
import { Button, IconButton, Snackbar, styled } from '@mui/material'
import { Button, IconButton, Snackbar } from '@mui/material'
import ArrowBackIcon from '@mui/icons-material/ArrowBack'
import CloseIcon from '@mui/icons-material/Close'
import { useTranslation } from 'react-i18next'
@@ -8,8 +8,9 @@ import ParticipantsMobile from '../components/Participants/ParticipantsMobile'
import TeamRegistrationMobile from '../components/Registration/TeamRegistrationMobile'
import Invoice from '../components/Registration/Invoice'
import { filterObject, findGroup, splitGroups } from '../utilities/Groups'
import { getAccount, getRegisteredSingle, getRegisteredTeams, register as registerApi } from '../api/account'
import { getAccount, getRegisteredSingle, getRegisteredTeams, register as registerApi } from '../api/account.js'
import { useUser } from '../context/UserContext'
import { styled } from '@mui/material-pigment-css'
const PDF = lazy(() => import('../components/PDF/PDF'))

View File

@@ -1,12 +1,13 @@
import { useEffect, useState } from 'react'
import { useParams, Link } from 'react-router-dom'
import { styled, Button } from '@mui/material'
import { Button } from '@mui/material'
import ArrowBackIcon from '@mui/icons-material/ArrowBack'
import { useTranslation } from 'react-i18next'
import useFetch from '../components/UseFetch/UseFetch'
import PostResult from '../components/Results/PostResult'
import TournamentResults from '../components/Results/TournamentResults'
import { useUser } from '../context/UserContext'
import { styled } from '@mui/material-pigment-css'
const PREFIX = 'Results'
const classes = {

View File

@@ -1,9 +1,10 @@
import { useParams, Link } from 'react-router-dom'
import ArrowBackIcon from '@mui/icons-material/ArrowBack'
import useFetch from '../components/UseFetch/UseFetch'
import { styled, Button } from '@mui/material'
import { Button } from '@mui/material'
import { useTranslation } from 'react-i18next'
import { useUser } from '../context/UserContext'
import { styled } from '@mui/material-pigment-css'
const PREFIX = 'Streams'
const classes = {
@@ -11,7 +12,7 @@ const classes = {
routerLink: `${PREFIX}-routerLink`,
}
const Root = styled('div')(({ theme }) => ({
const Root = styled('div')(() => ({
[`& .${classes.stream}`]: {
backgroundColor: 'rgba(0,0,0,0.2)',
margin: '1rem',

View File

@@ -1,4 +1,4 @@
import { savePdf as savePdfApi } from '../api/pdf'
import { savePdf as savePdfApi } from '../api/pdf.js'
export const savePdf = (blob, categorie, gid, apiServer, token, tid) => {
const reader = new FileReader()

View File

@@ -1,14 +1,44 @@
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import eslintPlugin from 'vite-plugin-eslint'
import { pigment } from '@pigment-css/vite-plugin'
import { createTheme } from '@mui/material/styles'
export default defineConfig(({ mode }) => {
// build into different folders depending on the `mode`.
const outDir = mode === 'staging' ? './dist/staging/' : './dist/production/'
// Beispiel-Theme mit eigenen Farben und Einstellungen
const pigmentTheme = createTheme({
palette: {
primary: {
light: '#757ce8',
main: '#3f50b5',
dark: '#002884',
contrastText: '#fff',
},
secondary: {
light: '#ff7961',
main: '#f50057',
dark: '#c51162',
contrastText: '#000',
},
},
cssVariables: true, // wichtig für Pigment!
})
/**
* @type {import('@pigment-css/vite-plugin').PigmentOptions}
*/
const pigmentConfig = {
transformLibraries: ['@mui/material'],
theme: pigmentTheme,
}
return {
plugins: [
react(),
pigment(pigmentConfig),
// TODO: aktivieren um linter beim build laufen zu lassen
// eslintPlugin({
// cache: false,