Format every js file to comply with the new eslint rules

This commit is contained in:
Felix Hamme 2019-05-09 14:18:16 +02:00
parent d12af2731f
commit b3243f6a5c
17 changed files with 1239 additions and 1549 deletions

View File

@ -1,13 +1,6 @@
import React from 'react'; import React from 'react';
import { import {
Alert, Alert, Button, Card, CardBody, CardTitle, Input, InputGroup, InputGroupAddon
Button,
Card,
CardBody,
CardTitle,
Input,
InputGroup,
InputGroupAddon
} from 'reactstrap'; } from 'reactstrap';
import '../../static/css/editablestringlist.css'; import '../../static/css/editablestringlist.css';
@ -16,9 +9,7 @@ export default class EditableStringList extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { this.state = {
groupSize: props.groupSize, groupSize: props.groupSize, teams: props.teams, groups: props.groups
teams: props.teams,
groups: props.groups
}; };
this.add = this.add.bind(this); this.add = this.add.bind(this);
this.remove = this.remove.bind(this); this.remove = this.remove.bind(this);
@ -39,8 +30,7 @@ export default class EditableStringList extends React.Component {
lastGroup[lastGroup.length] = text; lastGroup[lastGroup.length] = text;
this.setState({ this.setState({
teams: this.state.teams, teams: this.state.teams, groups: this.state.groups
groups: this.state.groups
}); });
this.props.onTeamsChange(this.state.teams); this.props.onTeamsChange(this.state.teams);
@ -55,8 +45,7 @@ export default class EditableStringList extends React.Component {
} }
this.setState({ this.setState({
teams: this.state.teams, teams: this.state.teams, groups: this.state.groups
groups: this.state.groups
}); });
this.props.onTeamsChange(this.state.teams); this.props.onTeamsChange(this.state.teams);
@ -91,8 +80,7 @@ export default class EditableStringList extends React.Component {
for (let team = 0; team < this.state.groups[group].length; team++) { for (let team = 0; team < this.state.groups[group].length; team++) {
if (this.state.groups[group][team] === text) { if (this.state.groups[group][team] === text) {
return { return {
group: group, group: group, team: team
team: team
}; };
} }
} }
@ -120,8 +108,7 @@ export default class EditableStringList extends React.Component {
} }
this.setState({ this.setState({
groupSize: newSize, groupSize: newSize, groups: rearrangedGroups
groups: rearrangedGroups
}); });
this.props.onGroupsChange(this.state.groups); this.props.onGroupsChange(this.state.groups);
} }
@ -148,35 +135,32 @@ export default class EditableStringList extends React.Component {
if (this.props.groupPhaseEnabled) { if (this.props.groupPhaseEnabled) {
if ((typeof this.state.teams !== 'undefined') && this.state.teams.length > 0) { if ((typeof this.state.teams !== 'undefined') && this.state.teams.length > 0) {
return ( return (<div className="bg-light p-3 text-secondary font-italic">
<div className="bg-light p-3 text-secondary font-italic"> <StringInput submit={this.add} placeholder={this.props.inputPlaceholder}
<StringInput submit={this.add} placeholder={this.props.inputPlaceholder} addButtonText={this.props.addButtonText}/> addButtonText={this.props.addButtonText}/>
<GroupView groups={this.state.groups} removeTeam={this.remove} onGroupSwitched={this.onGroupSwitch}/> <GroupView groups={this.state.groups} removeTeam={this.remove}
</div> onGroupSwitched={this.onGroupSwitch}/>
); </div>);
} else { } else {
return ( return (<div className="bg-light p-3 text-secondary text-center font-italic">
<div className="bg-light p-3 text-secondary text-center font-italic"> <StringInput submit={this.add} placeholder={this.props.inputPlaceholder}
<StringInput submit={this.add} placeholder={this.props.inputPlaceholder} addButtonText={this.props.addButtonText}/> addButtonText={this.props.addButtonText}/>
{this.props.groupPlaceHolder} {this.props.groupPlaceHolder}
</div> </div>);
);
} }
} else { } else {
if ((typeof this.state.teams !== 'undefined') && this.state.teams.length > 0) { if ((typeof this.state.teams !== 'undefined') && this.state.teams.length > 0) {
return ( return (<div className="bg-light p-3 text-secondary font-italic">
<div className="bg-light p-3 text-secondary font-italic"> <StringInput submit={this.add} placeholder={this.props.inputPlaceholder}
<StringInput submit={this.add} placeholder={this.props.inputPlaceholder} addButtonText={this.props.addButtonText}/> addButtonText={this.props.addButtonText}/>
{this.state.teams.map(text => <Item text={text} key={text} removeItem={this.remove}/>)} {this.state.teams.map(text => <Item text={text} key={text} removeItem={this.remove}/>)}
</div> </div>);
);
} else { } else {
return ( return (<div className="bg-light p-3 text-secondary text-center font-italic">
<div className="bg-light p-3 text-secondary text-center font-italic"> <StringInput submit={this.add} placeholder={this.props.inputPlaceholder}
<StringInput submit={this.add} placeholder={this.props.inputPlaceholder} addButtonText={this.props.addButtonText}/> addButtonText={this.props.addButtonText}/>
{this.props.teamPlaceholder} {this.props.teamPlaceholder}
</div> </div>);
);
} }
} }
} }
@ -188,38 +172,28 @@ class GroupView extends React.Component {
} }
render() { render() {
return ( return (<div>
<div> {this.props.groups.map((group, groupindex) => (<Card className="group-card" key={groupindex}>
{this.props.groups.map((group, groupindex) => ( <CardBody>
<Card className="group-card" key={groupindex}> <CardTitle>Group {groupindex + 1}</CardTitle>
<CardBody> {group.map((team, teamindex) => (<div key={team} draggable droppable="droppable"
<CardTitle>Group {groupindex + 1}</CardTitle> className="grouped-team-item"
{group.map((team, teamindex) => ( onDragStart={e => this.onDragStart(e, groupindex, teamindex)}
<div key={team} draggable droppable="droppable" onDragOver={e => this.onDragOver(e)}
className="grouped-team-item" onDrop={e => this.onDrop(e, groupindex, teamindex)}>
onDragStart={e => this.onDragStart(e, groupindex, teamindex)}
onDragOver={e => this.onDragOver(e)}
onDrop={e => this.onDrop(e, groupindex, teamindex)}>
<Item text={team} removeItem={this.props.removeTeam}/> <Item text={team} removeItem={this.props.removeTeam}/>
</div> </div>))}
))} </CardBody>
</CardBody> </Card>))}
</Card> </div>);
))}
</div>
);
} }
onDragStart(e, group, team) { onDragStart(e, group, team) {
e.dataTransfer.setData( e.dataTransfer.setData('text/plain', JSON.stringify({
'text/plain', group: group, team: team
JSON.stringify({ }));
group: group,
team: team
})
);
} }
onDragOver(e) { onDragOver(e) {
@ -231,8 +205,7 @@ class GroupView extends React.Component {
const src = JSON.parse(e.dataTransfer.getData('text')); const src = JSON.parse(e.dataTransfer.getData('text'));
const dest = { const dest = {
group: group, group: group, team: team
team: team
}; };
this.props.onGroupSwitched(src, dest); this.props.onGroupSwitched(src, dest);
@ -252,20 +225,19 @@ class StringInput extends React.Component {
} }
render() { render() {
return ( return (<InputGroup className="mb-3">
<InputGroup className="mb-3"> <Input placeholder={this.props.placeholder} type="text" size="255" value={this.state.value} required
<Input placeholder={this.props.placeholder} type="text" size="255" value={this.state.value} required onChange={this.handleChange} onKeyPress={e => { onChange={this.handleChange} onKeyPress={e => {
if (e.key === 'Enter') { if (e.key === 'Enter') {
this.submit(); this.submit();
return false; return false;
} }
}}/> }}/>
<InputGroupAddon addonType="append"> <InputGroupAddon addonType="append">
<Button color="success" outline={true} <Button color="success" outline={true}
onClick={() => this.submit()}>{this.props.addButtonText}</Button> onClick={() => this.submit()}>{this.props.addButtonText}</Button>
</InputGroupAddon> </InputGroupAddon>
</InputGroup> </InputGroup>);
);
} }
submit() { submit() {
@ -290,10 +262,8 @@ class Item extends React.Component {
} }
render() { render() {
return ( return (<Alert className="team-item m-2" color="info" isOpen={this.state.visible} toggle={this.onDismiss}>
<Alert className="team-item m-2" color="info" isOpen={this.state.visible} toggle={this.onDismiss}> {this.props.text}
{this.props.text} </Alert>);
</Alert>
);
} }
} }

View File

@ -9,37 +9,30 @@ import '../../static/css/errormessages.css';
import {notify} from 'react-notify-toast'; import {notify} from 'react-notify-toast';
export function Login(props) { export function Login(props) {
return ( return (<Container className="py-5">
<Container className="py-5"> <Card className="shadow">
<Card className="shadow"> <CardBody>
<CardBody> <h1 className="custom-font">Login</h1>
<h1 className="custom-font">Login</h1> <Hint hint={props.hint}/>
<Hint hint={props.hint}/> <LoginForm/>
<LoginForm/> <div className="mt-3">
<div className="mt-3"> <a href="/register" className="mr-3">Account anlegen</a>
<a href="/register" className="mr-3">Account anlegen</a> <a href="/register#account-requirement">Warum ist ein Account nötig?</a>
<a href="/register#account-requirement">Warum ist ein Account nötig?</a> </div>
</div> </CardBody>
</CardBody> </Card>
</Card> </Container>);
</Container>
);
} }
class LoginErrorList extends React.Component { class LoginErrorList extends React.Component {
render() { render() {
const {error, errorMessages} = this.props; const {error, errorMessages} = this.props;
if (error) { if (error) {
return ( return (<ul className='mt-3 error-box'>
<ul className='mt-3 error-box'> {errorMessages.map((message, index) => <li key={index}>
{ errorMessages.map((message, index) => {message}
<li key={index}> </li>)}
{message} </ul>);
</li>
) }
</ul>
);
} else { } else {
return null; return null;
} }
@ -51,9 +44,7 @@ const mapStateToErrorMessages = state => {
return {errorMessages, error}; return {errorMessages, error};
}; };
const VisibleLoginErrorList = connect( const VisibleLoginErrorList = connect(mapStateToErrorMessages)(LoginErrorList);
mapStateToErrorMessages
)(LoginErrorList);
class LoginSuccessRedirectComponent extends React.Component { class LoginSuccessRedirectComponent extends React.Component {
render() { render() {
@ -76,32 +67,32 @@ class LoginForm extends React.Component {
super(props); super(props);
this.state = { this.state = {
email: '', email: '', password: ''
password: ''
}; };
} }
tryLogin(event) { tryLogin(event) {
event.preventDefault(); event.preventDefault();
login(this.state.email, this.state.password, username => notify.show('Willkommen, ' + username + '!', 'success', 2500)); login(this.state.email, this.state.password,
username => notify.show('Willkommen, ' + username + '!', 'success', 2500));
} }
render() { render() {
return ( return (<Form onSubmit={this.tryLogin.bind(this)}>
<Form onSubmit={this.tryLogin.bind(this)}> <FormGroup>
<FormGroup> <Label for="username">E-Mail-Adresse</Label>
<Label for="username">E-Mail-Adresse</Label> <Input type="email" name="username" value={this.state.email}
<Input type="email" name="username" value={this.state.email} onChange={ this.handleEmailInput.bind(this) } /> onChange={this.handleEmailInput.bind(this)}/>
</FormGroup> </FormGroup>
<FormGroup> <FormGroup>
<Label for="password">Passwort</Label> <Label for="password">Passwort</Label>
<Input type="password" name="password" value={this.state.password} onChange={ this.handlePasswordInput.bind(this) } /> <Input type="password" name="password" value={this.state.password}
</FormGroup> onChange={this.handlePasswordInput.bind(this)}/>
<input type="submit" className="btn btn-lg btn-success w-100 shadow-sm" value="Anmelden"/> </FormGroup>
<VisibleLoginErrorList/> <input type="submit" className="btn btn-lg btn-success w-100 shadow-sm" value="Anmelden"/>
<LoginSuccessRedirect/> <VisibleLoginErrorList/>
</Form> <LoginSuccessRedirect/>
); </Form>);
} }
handlePasswordInput(input) { handlePasswordInput(input) {
@ -115,9 +106,7 @@ class LoginForm extends React.Component {
function Hint(props) { function Hint(props) {
if (props.hint != null) { if (props.hint != null) {
return ( return (<h3>{props.hint}</h3>);
<h3>{ props.hint }</h3>
);
} else { } else {
return null; return null;
} }

View File

@ -1,14 +1,5 @@
import { import {
Badge, Badge, Button, ButtonGroup, Collapse, Nav, Navbar, NavbarBrand, NavbarToggler, NavItem, NavLink
Button,
ButtonGroup,
Collapse,
Nav,
Navbar,
NavbarBrand,
NavbarToggler,
NavItem,
NavLink
} from 'reactstrap'; } from 'reactstrap';
import {connect} from 'react-redux'; import {connect} from 'react-redux';
import React from 'react'; import React from 'react';
@ -34,26 +25,22 @@ export class TurniereNavigation extends React.Component {
} }
render() { render() {
return ( return (<Navbar color="light" light expand="lg">
<Navbar color="light" light expand="lg"> <NavbarBrand href="/">turnie.re</NavbarBrand>
<NavbarBrand href="/">turnie.re</NavbarBrand> <Betabadge/>
<Betabadge/> <NavbarToggler onClick={this.toggle}/>
<NavbarToggler onClick={this.toggle} /> <Collapse isOpen={!this.state.collapsed} navbar>
<Collapse isOpen={!this.state.collapsed} navbar> <NavLinks/>
<NavLinks/> <LoginLogoutButtons/>
<LoginLogoutButtons/> </Collapse>
</Collapse> </Navbar>);
</Navbar>
);
} }
} }
function Navlink(props) { function Navlink(props) {
return ( return (<NavItem active={true}>
<NavItem active={true}> <NavLink href={props.target}>{props.text}</NavLink>
<NavLink href={props.target}>{props.text}</NavLink> </NavItem>);
</NavItem>
);
} }
class SmartNavLinks extends React.Component { class SmartNavLinks extends React.Component {
@ -80,19 +67,19 @@ class InvisibleLoginLogoutButtons extends React.Component {
const {isSignedIn, username} = this.props; const {isSignedIn, username} = this.props;
if (isSignedIn) { if (isSignedIn) {
return ( return (<ButtonGroup className="nav-item">
<ButtonGroup className="nav-item"> <Button outline color="success" href="/profile"
<Button outline color="success" href="/profile" className="navbar-btn my-2 my-sm-0 px-5">{ username }</Button> className="navbar-btn my-2 my-sm-0 px-5">{username}</Button>
<Button outline color="success" onClick={this.logout.bind(this)} className="navbar-btn my-2 my-sm-0 px-5">Logout</Button> <Button outline color="success" onClick={this.logout.bind(this)}
</ButtonGroup> className="navbar-btn my-2 my-sm-0 px-5">Logout</Button>
); </ButtonGroup>);
} else { } else {
return ( return (<ButtonGroup className="nav-item">
<ButtonGroup className="nav-item"> <Button outline color="success" href="/login"
<Button outline color="success" href="/login" className="navbar-btn my-2 my-sm-0 px-5">Login</Button> className="navbar-btn my-2 my-sm-0 px-5">Login</Button>
<Button outline color="success" href="/register" className="navbar-btn my-2 my-sm-0 px-5">Registrieren</Button> <Button outline color="success" href="/register"
</ButtonGroup> className="navbar-btn my-2 my-sm-0 px-5">Registrieren</Button>
); </ButtonGroup>);
} }
} }
} }
@ -102,10 +89,6 @@ const mapStateToUserinfo = state => {
return {isSignedIn, username}; return {isSignedIn, username};
}; };
const LoginLogoutButtons = connect( const LoginLogoutButtons = connect(mapStateToUserinfo)(InvisibleLoginLogoutButtons);
mapStateToUserinfo
)(InvisibleLoginLogoutButtons);
const NavLinks = connect( const NavLinks = connect(mapStateToUserinfo)(SmartNavLinks);
mapStateToUserinfo
)(SmartNavLinks);

View File

@ -14,15 +14,13 @@ class TurniereApp extends App {
render() { render() {
const {Component, pageProps, reduxStore} = this.props; const {Component, pageProps, reduxStore} = this.props;
return ( return (<Container>
<Container> <Notifications/>
<Notifications /> <Favicon url="../static/icons/favicon.ico"/>
<Favicon url="../static/icons/favicon.ico"/> <Provider store={reduxStore}>
<Provider store={reduxStore}> <Component {...pageProps} />
<Component {...pageProps} /> </Provider>
</Provider> </Container>);
</Container>
);
} }
} }

View File

@ -14,8 +14,6 @@ export default class Error extends React.Component {
} }
render() { render() {
return ( return (<ErrorPageComponent statusCode={this.props.statusCode}/>);
<ErrorPageComponent statusCode={this.props.statusCode}/>
);
} }
} }

View File

@ -5,15 +5,7 @@ import {connect} from 'react-redux';
import posed from 'react-pose'; import posed from 'react-pose';
import { import {
Button, Button, Card, CardBody, Container, CustomInput, Form, FormGroup, Input, Label
Card,
CardBody,
Container,
CustomInput,
Form,
FormGroup,
Input,
Label
} from 'reactstrap'; } from 'reactstrap';
import {TurniereNavigation} from '../js/components/Navigation'; import {TurniereNavigation} from '../js/components/Navigation';
@ -29,34 +21,32 @@ class CreatePage extends React.Component {
render() { render() {
const {isSignedIn} = this.props; const {isSignedIn} = this.props;
return ( return (<UserRestrictor>
<UserRestrictor> <Option condition={isSignedIn}>
<Option condition={isSignedIn}> <div className="main generic-fullpage-bg">
<div className="main generic-fullpage-bg"> <Head>
<Head> <title>Turnier erstellen: turnie.re</title>
<title>Turnier erstellen: turnie.re</title> </Head>
</Head> <TurniereNavigation/>
<TurniereNavigation/> <div>
<div> <CreateTournamentCard/>
<CreateTournamentCard/>
</div>
<Footer/>
</div> </div>
</Option> <Footer/>
<Option condition={true}> </div>
<div className="main generic-fullpage-bg"> </Option>
<Head> <Option condition={true}>
<title>Anmeldung</title> <div className="main generic-fullpage-bg">
</Head> <Head>
<TurniereNavigation/> <title>Anmeldung</title>
<div> </Head>
<Login hint="Sie müssen angemeldet sein, um diesen Inhalt anzuzeigen!"/> <TurniereNavigation/>
</div> <div>
<Footer/> <Login hint="Sie müssen angemeldet sein, um diesen Inhalt anzuzeigen!"/>
</div> </div>
</Option> <Footer/>
</UserRestrictor> </div>
); </Option>
</UserRestrictor>);
} }
} }
@ -65,31 +55,24 @@ function mapStateToCreatePageProperties(state) {
return {isSignedIn}; return {isSignedIn};
} }
export default connect( export default connect(mapStateToCreatePageProperties)(CreatePage);
mapStateToCreatePageProperties
)(CreatePage);
function CreateTournamentCard() { function CreateTournamentCard() {
return ( return (<Container className="py-5">
<Container className="py-5"> <Card className="shadow">
<Card className="shadow"> <CardBody>
<CardBody> <h1 className="custom-font">Turnier erstellen</h1>
<h1 className="custom-font">Turnier erstellen</h1> <CreateTournamentForm/>
<CreateTournamentForm/> </CardBody>
</CardBody> </Card>
</Card> </Container>);
</Container>
);
} }
const GroupphaseFader = posed.div({ const GroupphaseFader = posed.div({
visible: { visible: {
opacity: 1, opacity: 1, height: 150
height: 150 }, hidden: {
}, opacity: 0, height: 0
hidden: {
opacity: 0,
height: 0
} }
}); });
@ -99,14 +82,9 @@ class CreateTournamentForm extends React.Component {
this.state = { this.state = {
groupPhaseEnabled: false, groupPhaseEnabled: false,
name: '', name: '', description: '', public: false,
description: '',
public: false,
groupSize: 4, groupSize: 4, groupAdvance: 1, teams: [], groups: []
groupAdvance: 1,
teams: [],
groups: []
}; };
this.handleGroupPhaseEnabledInput = this.handleGroupPhaseEnabledInput.bind(this); this.handleGroupPhaseEnabledInput = this.handleGroupPhaseEnabledInput.bind(this);
this.teamListUpdate = this.teamListUpdate.bind(this); this.teamListUpdate = this.teamListUpdate.bind(this);
@ -122,53 +100,57 @@ class CreateTournamentForm extends React.Component {
} }
render() { render() {
return ( return (<div>
<div> <Form>
<Form> <FormGroup>
<Label for="name">Name des Turniers</Label>
<Input type="text" name="name" size="255" required value={this.state.name}
onChange={this.handleNameInput}/>
</FormGroup>
<FormGroup>
<Label for="description">Beschreibung (optional)</Label>
<Input type="text" name="description" size="255" value={this.state.description}
onChange={this.handleDescriptionInput}/>
</FormGroup>
<FormGroup>
<CustomInput type="checkbox" id="public"
label="Turnier öffentlich anzeigen (schreibgeschützt)" checked={this.state.public}
onChange={this.handlePublicInput}/>
<CustomInput type="checkbox" id="mix-teams" label="Teams mischen"/>
<CustomInput type="checkbox" id="group-phase" label="Gruppenphase"
checked={this.state.groupPhaseEnabled}
onChange={this.handleGroupPhaseEnabledInput}/>
</FormGroup>
<GroupphaseFader pose={this.state.groupPhaseEnabled ? 'visible' : 'hidden'}
className="groupphasefader">
<FormGroup> <FormGroup>
<Label for="name">Name des Turniers</Label> <Label for="teams-per-group">Anzahl Teams pro Gruppe</Label>
<Input type="text" name="name" size="255" required value={this.state.name} onChange={this.handleNameInput}/> <Input type="number" name="teams-per-group" min="3"
value={this.state.groupSize} onChange={this.handleGroupSizeInput}/>
</FormGroup> </FormGroup>
<FormGroup> <FormGroup>
<Label for="description">Beschreibung (optional)</Label> <Label for="teams-group-to-playoff">Wie viele Teams sollen nach der Gruppenphase
<Input type="text" name="description" size="255" value={this.state.description} onChange={this.handleDescriptionInput}/>
</FormGroup>
<FormGroup>
<CustomInput type="checkbox" id="public"
label="Turnier öffentlich anzeigen (schreibgeschützt)" checked={this.state.public} onChange={this.handlePublicInput}/>
<CustomInput type="checkbox" id="mix-teams" label="Teams mischen"/>
<CustomInput type="checkbox" id="group-phase" label="Gruppenphase"
checked={this.state.groupPhaseEnabled} onChange={this.handleGroupPhaseEnabledInput}/>
</FormGroup>
<GroupphaseFader pose={this.state.groupPhaseEnabled? 'visible' : 'hidden'} className="groupphasefader">
<FormGroup>
<Label for="teams-per-group">Anzahl Teams pro Gruppe</Label>
<Input type="number" name="teams-per-group" min="3"
value={this.state.groupSize} onChange={this.handleGroupSizeInput}/>
</FormGroup>
<FormGroup>
<Label for="teams-group-to-playoff">Wie viele Teams sollen nach der Gruppenphase
weiterkommen?</Label> weiterkommen?</Label>
<Input type="number" name="teams-group-to-playoff" min="1" max={this.state.groupSize - 1} <Input type="number" name="teams-group-to-playoff" min="1" max={this.state.groupSize - 1}
value={this.state.groupAdvance} onChange={this.handleGroupAdvanceInput}/> value={this.state.groupAdvance} onChange={this.handleGroupAdvanceInput}/>
</FormGroup> </FormGroup>
</GroupphaseFader> </GroupphaseFader>
</Form> </Form>
<h3 className="custom-font mt-4">Teams</h3> <h3 className="custom-font mt-4">Teams</h3>
<EditableStringList <EditableStringList
addButtonText="hinzufügen" addButtonText="hinzufügen"
teamPlaceholder="Keine Teams hinzugefügt!" teamPlaceholder="Keine Teams hinzugefügt!"
groupPlaceHolder="Keine Gruppen verfügbar!" groupPlaceHolder="Keine Gruppen verfügbar!"
teams={[]} teams={[]}
groups={[]} groups={[]}
groupPhaseEnabled={this.state.groupPhaseEnabled} groupPhaseEnabled={this.state.groupPhaseEnabled}
groupSize={this.state.groupSize} groupSize={this.state.groupSize}
onTeamsChange={this.teamListUpdate} onTeamsChange={this.teamListUpdate}
onGroupsChange={this.groupListUpdate} onGroupsChange={this.groupListUpdate}
inputPlaceholder="Teamname"/> inputPlaceholder="Teamname"/>
<Button color="success" size="lg" className="w-100 shadow-sm mt-4" onClick={this.create}>Turnier erstellen</Button> <Button color="success" size="lg" className="w-100 shadow-sm mt-4" onClick={this.create}>Turnier
</div> erstellen</Button>
); </div>);
} }
teamListUpdate(list) { teamListUpdate(list) {
@ -183,8 +165,7 @@ class CreateTournamentForm extends React.Component {
const newSize = input.target.value; const newSize = input.target.value;
if (newSize <= this.state.groupAdvance) { if (newSize <= this.state.groupAdvance) {
this.setState({ this.setState({
groupSize: newSize, groupSize: newSize, groupAdvance: newSize - 1
groupAdvance: newSize - 1
}); });
} else { } else {
this.setState({groupSize: newSize}); this.setState({groupSize: newSize});
@ -249,8 +230,7 @@ function createTeamArray(groupphase, groups, teams) {
for (let groupNumber = 0; groupNumber < groups.length; groupNumber++) { for (let groupNumber = 0; groupNumber < groups.length; groupNumber++) {
for (let groupMember = 0; groupMember < groups[groupNumber].length; groupMember++) { for (let groupMember = 0; groupMember < groups[groupNumber].length; groupMember++) {
result[result.length] = { result[result.length] = {
'name': groups[groupNumber][groupMember], 'name': groups[groupNumber][groupMember], 'group': groupNumber
'group': groupNumber
}; };
} }
} }

View File

@ -11,228 +11,196 @@ import 'bootstrap/dist/css/bootstrap.min.css';
import '../static/everypage.css'; import '../static/everypage.css';
function Main() { function Main() {
return ( return (<div className="main">
<div className="main"> <Container className="pb-5">
<Container className="pb-5"> <GeneralFaq/>
<GeneralFaq/> <hr className="mb-5"/>
<hr className="mb-5"/> <AccountFaq/>
<AccountFaq/> <hr className="mb-5"/>
<hr className="mb-5"/> <TournamentFaq/>
<TournamentFaq/> </Container>
</Container> </div>);
</div>
);
} }
function GeneralFaq() { function GeneralFaq() {
return ( return (<div className="running-text">
<div className="running-text"> <h1>Allgemein</h1>
<h1>Allgemein</h1> <Row>
<Row> <Col sm="4">
<Col sm="4"> <h4>Was macht turnie.re?</h4>
<h4>Was macht turnie.re?</h4> <p>
<p> turnie.re ist ein Online-Turnier&shy;planer.</p>
turnie.re ist ein Online-Turnier&shy;planer.</p> <p>
<p> Allein aus den Team-Namen berechnen wir dir einen kompletten Spielplan, den du auch gleich mit allen
Allein aus den Team-Namen berechnen wir dir einen kompletten Spielplan, den du auch gleich Leuten teilen kannst, ohne dir Gedanken machen zu müssen, wer gegen wen spielen muss. Du trägst ein,
mit allen Leuten teilen kannst, ohne dir Gedanken machen zu müssen, wer gegen wen spielen wer gewonnen hat, und turnie.re sagt, wer als nächstes spielt. </p>
muss. Du trägst ein, wer gewonnen hat, und turnie.re sagt, wer als nächstes spielt. </Col>
</p> <Col sm="4">
</Col> <h4>Für welche Sportarten ist turnie.re geeignet?</h4>
<Col sm="4"> <p>
<h4>Für welche Sportarten ist turnie.re geeignet?</h4> turnie.re ist prinzipiell für jede Sportart geeignet. Die einzige Vor&shy;aus&shy;setzung ist,
<p> dass in jedem Spiel zwei Mannschaften oder Spieler gegeinander antreten und dass derjenige mit den
turnie.re ist prinzipiell für jede Sportart geeignet. Die einzige Vor&shy;aus&shy;setzung ist, dass meisten Punkten gewinnt. </p>
in jedem Spiel zwei Mannschaften oder Spieler gegeinander antreten und dass derjenige mit </Col>
den meisten Punkten gewinnt. <Col sm="4">
</p> <h4>Für welche Anzahl an Teams ist turnie.re geeignet?</h4>
</Col> <p>
<Col sm="4"> turnie.re ist unabhängig von der Anzahl der Teams nutzbar. </p>
<h4>Für welche Anzahl an Teams ist turnie.re geeignet?</h4> </Col>
<p> <Col sm="4">
turnie.re ist unabhängig von der Anzahl der Teams nutzbar. <h4>Fallen für die Nutzung von turnie.re Kosten an?</h4>
</p> <p>
</Col> turnie.re ist ein kostenloser Service! Wir erheben keine Kosten und sind nur darauf aus,
<Col sm="4"> dein Turnier-Management so einfach wie möglich zu gestalten. </p>
<h4>Fallen für die Nutzung von turnie.re Kosten an?</h4> </Col>
<p> </Row>
turnie.re ist ein kostenloser Service! Wir erheben keine Kosten und sind nur darauf aus, </div>);
dein Turnier-Management so einfach wie möglich zu gestalten.
</p>
</Col>
</Row>
</div>
);
} }
function AccountFaq() { function AccountFaq() {
return ( return (<div className="running-text">
<div className="running-text"> <h1>Account</h1>
<h1>Account</h1> <Row>
<Row> <Col sm="4">
<Col sm="4"> <h4>Warum brauche ich einen Account für turnie.re?</h4>
<h4>Warum brauche ich einen Account für turnie.re?</h4> <p>
<p> Wir wollen sicherstellen, dass nur berechtigte Nutzer Turnierdaten ändern können. Damit wir dich als
Wir wollen sicherstellen, dass nur berechtigte Nutzer Turnierdaten ändern können. Damit wir berechtigt verifizieren können, benötigst du einen Acoount, sodass wir dir die entsprechenden
dich als berechtigt verifizieren können, benötigst du einen Acoount, sodass wir dir die Bearbeitungsrechte zuteilen können. </p>
entsprechenden Bearbeitungsrechte zuteilen können. </Col>
</p> <Col sm="4">
</Col> <h4>Welche Daten muss ich bei der Accounterstellung angeben?</h4>
<Col sm="4"> <p>
<h4>Welche Daten muss ich bei der Accounterstellung angeben?</h4> Um einen Account anzulegen musst du einen Nutzernamen, eine gültige E-Mailadresse sowie ein Passwort
<p> angeben. </p>
Um einen Account anzulegen musst du einen Nutzernamen, eine gültige E-Mailadresse sowie ein </Col>
Passwort angeben. <Col sm="4">
</p> <h4>Wie werden meine Daten verarbeitet?</h4>
</Col> <p>
<Col sm="4"> Deine Daten werden in unserer Datenbank gespeichert. Eine Weitergabe dieser Daten an Dritte erfolgt
<h4>Wie werden meine Daten verarbeitet?</h4> nicht!
<p> </p>
Deine Daten werden in unserer Datenbank gespeichert. Eine Weitergabe dieser Daten an Dritte <p>
erfolgt nicht! Zusätlich wird dein Passwort verschlüsselt gespeichert, das bedeutet auch wir kennen dein Passwort
</p> nicht und dein Account wird zuverlässig geschützt. </p>
<p> </Col>
Zusätlich wird dein Passwort verschlüsselt gespeichert, das bedeutet auch wir kennen dein <Col sm="4">
Passwort nicht und dein Account wird zuverlässig geschützt. <h4>Wie kann ich meinen Nutzernamen ändern?</h4>
</p> <p>
</Col> Über deinen Nutzernamen, der in der Kopfzeile angezeigt wird, gelangst du auf deine Profilseite.
<Col sm="4"> Hier kannst du deinen Nutzernamen ändern. </p>
<h4>Wie kann ich meinen Nutzernamen ändern?</h4> </Col>
<p> <Col sm="4">
Über deinen Nutzernamen, der in der Kopfzeile angezeigt wird, gelangst du auf deine <h4>Wie kann ich meine E-Mailadresse ändern?</h4>
Profilseite. Hier kannst du deinen Nutzernamen ändern. <p>
</p> Über deinen Nutzernamen, der in der Kopfzeile angezeigt wird, gelangst du auf deine Profilseite.
</Col> Hier kannst du deine E-Mailadresse ändern ändern. </p>
<Col sm="4"> </Col>
<h4>Wie kann ich meine E-Mailadresse ändern?</h4> <Col sm="4">
<p> <h4>Wie kann ich mein Passwort ändern?</h4>
Über deinen Nutzernamen, der in der Kopfzeile angezeigt wird, gelangst du auf deine <p>
Profilseite. Hier kannst du deine E-Mailadresse ändern ändern. Auf deiner Profilseite findest du einen "Passwort ändern" Button. Auf der sich dann öffnenden Seite
</p> kannst du dein Passwort ändern. </p>
</Col> </Col>
<Col sm="4"> </Row>
<h4>Wie kann ich mein Passwort ändern?</h4> </div>);
<p>
Auf deiner Profilseite findest du einen "Passwort ändern" Button. Auf der sich dann
öffnenden Seite kannst du dein Passwort ändern.
</p>
</Col>
</Row>
</div>
);
} }
function TournamentFaq() { function TournamentFaq() {
return ( return (<div className="running-text">
<div className="running-text"> <h1>Turnier</h1>
<h1>Turnier</h1> <Row>
<Row> <Col sm="4">
<Col sm="4"> <h4>Wie erstelle ich ein Turnier?</h4>
<h4>Wie erstelle ich ein Turnier?</h4> <p>
<p> Um ein Turnier zu erstellen musst du dich zuerst anmelden.</p>
Um ein Turnier zu erstellen musst du dich zuerst anmelden.</p> <p>
<p> Über "Turnier erstellen" gelangst du auf die "Turnier erstellen" Seite. Auf dieser kannst du deinem
Über "Turnier erstellen" gelangst du auf die "Turnier erstellen" Seite. Auf dieser kannst du Turnier einen Namen geben und eine (optionale) Beschreibung hinzufügen. Dann kannst du dein
deinem Turnier einen Namen geben und eine (optionale) Beschreibung hinzufügen. Dann kannst Turnier <a href="#public-tournament">öffentlich oder privat</a> erstellen, die Teams für die
du dein Turnier <a href="#public-tournament">öffentlich oder privat</a> erstellen, die Teams Spielpaarungen <a href="#randomize-teams">mischen</a> lassen und eine <a
für die Spielpaarungen <a href="#randomize-teams">mischen</a> lassen und eine <a href="#groupstage">Gruppenphase</a> href="#groupstage">Gruppenphase</a>
hinzufügen. Im Feld "Teams" kannst du die hinzufügen. Im Feld "Teams" kannst du die teilnehmenden <a href="#add-teams">Teams eintragen</a> und
teilnehmenden <a href="#add-teams">Teams hinzufügen. </p>
eintragen</a> und hinzufügen. </p> <p>
<p> Wenn du die Option Gruppenphase aktiviert hast, kannst du zusätzlich noch die Größe der Gruppen
Wenn du die Option Gruppenphase aktiviert hast, kannst du zusätzlich noch die Größe der angeben. </p>
Gruppen angeben. </Col>
</p> <Col sm="4">
</Col> <h4 id="public-tournament">Was ist der Unterschied zwischen einem öffentlichen und einem privaten
<Col sm="4"> Turnier?</h4>
<h4 id="public-tournament">Was ist der Unterschied zwischen einem öffentlichen und einem <p>
privaten Turnier?</h4> Standardmäßig ist ein Turnier privat, das bedeutet, dass nur der Turnierersteller und Zuschauer, die
<p> den entsprechenden Turniercode erhalten haben, das Turnier, seine teilnehmenden Mannschaften, sowie
Standardmäßig ist ein Turnier privat, das bedeutet, dass nur der Turnierersteller und die Spielpaarungen und die jeweiligen Spielstände sehen können. </p>
Zuschauer, die den entsprechenden Turniercode erhalten haben, das Turnier, seine <p>
teilnehmenden Mannschaften, sowie die Spielpaarungen und die jeweiligen Spielstände sehen Wenn du dich entscheidest dein Turnier öffentlich zu erstellen, wird der Turniercode nicht mehr
können. benötigt, um das Turnier und all seine Informationen einzusehen. Das Turnier wird dann in der Liste
</p> der öffentlichen Turniere angezeigt und kann auch über seinen Namen von jedem gefunden werden. </p>
<p> <p>
Wenn du dich entscheidest dein Turnier öffentlich zu erstellen, wird der Turniercode nicht Trotzdem bleibt der Turnierersteller der Einzige, der die Turnierinformationen bearbeiten und
mehr benötigt, um das Turnier und all seine Informationen einzusehen. Das Turnier wird dann Spielstände eintragen kann. </p>
in der Liste der öffentlichen Turniere angezeigt und kann auch über seinen Namen von jedem </Col>
gefunden werden. </p> <Col sm="4">
<p> <h4 id="randomize-teams">Was bedeutet "Teams mischen"?</h4>
Trotzdem bleibt der Turnierersteller der Einzige, der die Turnierinformationen bearbeiten <p>
und Spielstände eintragen kann. Die Spielpaarungen werden anhand der Eingabereihenfolge der Teams erstellt. So spielt z.B. das
</p> zuerst eingegebene Team gegen das als zweites eingegebene Team, das als drittes eingegebene gegen
</Col> das als viertes eingegebene, und so weiter. </p>
<Col sm="4"> <p>
<h4 id="randomize-teams">Was bedeutet "Teams mischen"?</h4> Wenn du das nicht möchtest kannst du die Option "Teams mischen" aktivieren und die Spielpaarungen
<p> werden in einer zufälligen Reihenfolge erstellt. </p>
Die Spielpaarungen werden anhand der Eingabereihenfolge der Teams erstellt. So spielt z.B. </Col>
das zuerst eingegebene Team gegen das als zweites eingegebene Team, das als drittes <Col sm="4">
eingegebene gegen das als viertes eingegebene, und so weiter. </p> <h4 id="groupstage">Was passiert wenn ich die Gruppenphase aktiviere?</h4>
<p> <p>
Wenn du das nicht möchtest kannst du die Option "Teams mischen" aktivieren und die Grundsätzlich erstellt turnie.re dir einen Spielplan für ein Turnier <strong>ohne</strong>
Spielpaarungen werden in einer zufälligen Reihenfolge erstellt. Gruppenphase und <strong>nur</strong> einer K.O.-Phase. Wenn du eine Gruppenphase spielen lassen
</p> willst, kannst du das aber auch tun. Wenn die Gruppenphase aktiviert ist, werden deine eingegeben
</Col> Teams automatisch in Gruppen eingeteilt und auch die Spielpläne für die einzelnen Gruppen berechnet.
<Col sm="4"> </p>
<h4 id="groupstage">Was passiert wenn ich die Gruppenphase aktiviere?</h4> <p>
<p> Bitte beachte, dass die Anzahl der Teams durch die Gruppengröße teilbar sein muss. </p>
Grundsätzlich erstellt turnie.re dir einen Spielplan für ein Turnier <strong>ohne</strong> </Col>
Gruppenphase und <strong>nur</strong> einer K.O.-Phase. Wenn du eine Gruppenphase spielen <Col sm="4">
lassen willst, kannst du das aber auch tun. Wenn die Gruppenphase aktiviert ist, werden <h4 id="add-teams">Wie kann ich Teams hinzufügen?</h4>
deine eingegeben Teams automatisch in Gruppen eingeteilt und auch die Spielpläne für die <p>
einzelnen Gruppen berechnet. </p> Auf der "Turnier erstellen" Seite kannst du im Feld "Teams" deine Teams eintragen. </p>
<p> <p>
Bitte beachte, dass die Anzahl der Teams durch die Gruppengröße teilbar sein muss. Du kannst die Teamnamen einzeln eingeben und dann über drücken der Entertaste oder über den Button
</p> "Team hinzufügen" das Team deinem Turnier hinzufügen. Du kannst aber auch deine Teams als eine mit
</Col> Kommas getrennte Liste eingeben und dann hinzufügen. </p>
<Col sm="4"> </Col>
<h4 id="add-teams">Wie kann ich Teams hinzufügen?</h4> <Col sm="4">
<p> <h4>Wie starte ich ein Spiel?</h4>
Auf der "Turnier erstellen" Seite kannst du im Feld "Teams" deine Teams eintragen. </p> <p>
<p> Auf der Turnierübersicht Seite gibt es für jede Partie einen "Spiel starten" Button. Über diesen
Du kannst die Teamnamen einzeln eingeben und dann über drücken der Entertaste oder über den kannst du einfach das jeweilige Spiel starten. </p>
Button "Team hinzufügen" das Team deinem Turnier hinzufügen. Du kannst aber auch deine Teams </Col>
als eine mit Kommas getrennte Liste eingeben und dann hinzufügen. <Col sm="4">
</p> <h4>Wie trage ich einen Spielstand für eine Partie ein?</h4>
</Col> <p>
<Col sm="4"> Auf der Turnierübersicht Seite gibt es für jede Partie einen "Spielstand ändern" Button. Über diesen
<h4>Wie starte ich ein Spiel?</h4> kannst du einfach den Spielstand eintragen. In dem Popup, das sich öffnet kannst du den aktuellen
<p> Spielstand eintragen und angeben, ob das Spiel noch läuft oder schon beendet ist. </p>
Auf der Turnierübersicht Seite gibt es für jede Partie einen "Spiel starten" Button. Über <h4>Gibt es in der Gruppenphase eine Blitztabelle?</h4>
diesen kannst du einfach das jeweilige Spiel starten. <p>
</p> Ja, die in der Gruppenphase dargestellte Tabelle stellt eine Blitztabelle dar. </p>
</Col> </Col>
<Col sm="4"> </Row>
<h4>Wie trage ich einen Spielstand für eine Partie ein?</h4> </div>);
<p>
Auf der Turnierübersicht Seite gibt es für jede Partie einen "Spielstand ändern" Button.
Über diesen kannst du einfach den Spielstand eintragen. In dem Popup, das sich öffnet kannst
du den aktuellen Spielstand eintragen und angeben, ob das Spiel noch läuft oder schon
beendet ist.
</p>
<h4>Gibt es in der Gruppenphase eine Blitztabelle?</h4>
<p>
Ja, die in der Gruppenphase dargestellte Tabelle stellt eine Blitztabelle dar.
</p>
</Col>
</Row>
</div>
);
} }
export default class FaqPage extends React.Component { export default class FaqPage extends React.Component {
render() { render() {
return ( return (<div>
<div> <Head>
<Head> <title>FAQ: turnie.re</title>
<title>FAQ: turnie.re</title> </Head>
</Head> <TurniereNavigation/>
<TurniereNavigation/> <BigImage text="FAQ"/>
<BigImage text="FAQ"/> <Main/>
<Main/> <Footer/>
<Footer/> </div>);
</div>
);
} }
} }

View File

@ -10,81 +10,94 @@ import 'bootstrap/dist/css/bootstrap.min.css';
import '../static/everypage.css'; import '../static/everypage.css';
function Main() { function Main() {
return ( return (<div className="main running-text">
<div className="main running-text"> <ImprintText/>
<ImprintText/> </div>);
</div>
);
} }
function ImprintText() { function ImprintText() {
return ( return (<Container>
<Container> <h3>
<h3>
Angaben gemäß §5 TMG: Angaben gemäß §5 TMG:
</h3> </h3>
<p> <p>
Jonas Seydel<br/> Jonas Seydel<br/>
August-Euler-Weg 3<br/> August-Euler-Weg 3<br/>
76133 Karlsruhe<br/> 76133 Karlsruhe<br/>
Germany<br/> Germany<br/>
</p> </p>
<p> <p>
<strong>Vertreten durch</strong><br/> <strong>Vertreten durch</strong><br/>
Jonas Seydel Jonas Seydel
</p> </p>
<p> <p>
<strong>Kontakt</strong><br/> <strong>Kontakt</strong><br/>
jon@s-seydel.de jon@s-seydel.de
</p> </p>
<h3>Haftungsausschluss</h3> <h3>Haftungsausschluss</h3>
<h4>Haftung für Inhalte</h4> <h4>Haftung für Inhalte</h4>
<p> <p>
Die Inhalte unserer Seiten wurden mit größter Sorgfalt erstellt. Für die Richtigkeit, Vollständigkeit und Aktualität Die Inhalte unserer Seiten wurden mit größter Sorgfalt erstellt. Für die Richtigkeit, Vollständigkeit
der Inhalte können wir jedoch keine Gewähr übernehmen. Als Diensteanbieter sind wir gemäß § 7 Abs.1 TMG für eigene und Aktualität
Inhalte auf diesen Seiten nach den allgemeinen Gesetzen verantwortlich. Nach §§ 8 bis 10 TMG sind wir als der Inhalte können wir jedoch keine Gewähr übernehmen. Als Diensteanbieter sind wir gemäß § 7 Abs.1 TMG
Diensteanbieter jedoch nicht verpflichtet, übermittelte oder gespeicherte fremde Informationen zu überwachen oder nach für eigene
Umständen zu forschen, die auf eine rechtswidrige Tätigkeit hinweisen. Verpflichtungen zur Entfernung oder Sperrung Inhalte auf diesen Seiten nach den allgemeinen Gesetzen verantwortlich. Nach §§ 8 bis 10 TMG sind wir
der Nutzung von Informationen nach den allgemeinen Gesetzen bleiben hiervon unberührt. Eine diesbezügliche Haftung ist als
jedoch erst ab dem Zeitpunkt der Kenntnis einer konkreten Rechtsverletzung möglich. Bei Bekanntwerden von Diensteanbieter jedoch nicht verpflichtet, übermittelte oder gespeicherte fremde Informationen zu
überwachen oder nach
Umständen zu forschen, die auf eine rechtswidrige Tätigkeit hinweisen. Verpflichtungen zur Entfernung
oder Sperrung
der Nutzung von Informationen nach den allgemeinen Gesetzen bleiben hiervon unberührt. Eine
diesbezügliche Haftung ist
jedoch erst ab dem Zeitpunkt der Kenntnis einer konkreten Rechtsverletzung möglich. Bei Bekanntwerden
von
entsprechenden Rechtsverletzungen werden wir diese Inhalte umgehend entfernen. entsprechenden Rechtsverletzungen werden wir diese Inhalte umgehend entfernen.
</p> </p>
<h4>Haftung für Links</h4> <h4>Haftung für Links</h4>
<p> <p>
Unser Angebot enthält Links zu externen Webseiten Dritter, auf deren Inhalte wir keinen Einfluss haben. Deshalb können Unser Angebot enthält Links zu externen Webseiten Dritter, auf deren Inhalte wir keinen Einfluss haben.
wir für diese fremden Inhalte auch keine Gewähr übernehmen. Für die Inhalte der verlinkten Seiten ist stets der Deshalb können
jeweilige Anbieter oder Betreiber der Seiten verantwortlich. Die verlinkten Seiten wurden zum Zeitpunkt der Verlinkung wir für diese fremden Inhalte auch keine Gewähr übernehmen. Für die Inhalte der verlinkten Seiten ist
auf mögliche Rechtsverstöße überprüft. Rechtswidrige Inhalte waren zum Zeitpunkt der Verlinkung nicht erkennbar. Eine stets der
permanente inhaltliche Kontrolle der verlinkten Seiten ist jedoch ohne konkrete Anhaltspunkte einer Rechtsverletzung jeweilige Anbieter oder Betreiber der Seiten verantwortlich. Die verlinkten Seiten wurden zum Zeitpunkt
der Verlinkung
auf mögliche Rechtsverstöße überprüft. Rechtswidrige Inhalte waren zum Zeitpunkt der Verlinkung nicht
erkennbar. Eine
permanente inhaltliche Kontrolle der verlinkten Seiten ist jedoch ohne konkrete Anhaltspunkte einer
Rechtsverletzung
nicht zumutbar. Bei Bekanntwerden von Rechtsverletzungen werden wir derartige Links umgehend entfernen. nicht zumutbar. Bei Bekanntwerden von Rechtsverletzungen werden wir derartige Links umgehend entfernen.
</p> </p>
<h4>Urheberrecht</h4> <h4>Urheberrecht</h4>
<p> <p>
Die durch die Seitenbetreiber erstellten Inhalte und Werke auf diesen Seiten unterliegen dem deutschen Urheberrecht. Die durch die Seitenbetreiber erstellten Inhalte und Werke auf diesen Seiten unterliegen dem deutschen
Die Vervielfältigung, Bearbeitung, Verbreitung und jede Art der Verwertung außerhalb der Grenzen des Urheberrechtes Urheberrecht.
bedürfen der schriftlichen Zustimmung des jeweiligen Autors bzw. Erstellers. Downloads und Kopien dieser Seite sind Die Vervielfältigung, Bearbeitung, Verbreitung und jede Art der Verwertung außerhalb der Grenzen des
nur für den privaten, nicht kommerziellen Gebrauch gestattet. Soweit die Inhalte auf dieser Seite nicht vom Betreiber Urheberrechtes
erstellt wurden, werden die Urheberrechte Dritter beachtet. Insbesondere werden Inhalte Dritter als solche bedürfen der schriftlichen Zustimmung des jeweiligen Autors bzw. Erstellers. Downloads und Kopien dieser
gekennzeichnet. Sollten Sie trotzdem auf eine Urheberrechtsverletzung aufmerksam werden, bitten wir um einen Seite sind
entsprechenden Hinweis. Bei Bekanntwerden von Rechtsverletzungen werden wir derartige Inhalte umgehend entfernen. nur für den privaten, nicht kommerziellen Gebrauch gestattet. Soweit die Inhalte auf dieser Seite nicht
</p> vom Betreiber
</Container> erstellt wurden, werden die Urheberrechte Dritter beachtet. Insbesondere werden Inhalte Dritter als
); solche
gekennzeichnet. Sollten Sie trotzdem auf eine Urheberrechtsverletzung aufmerksam werden, bitten wir um
einen
entsprechenden Hinweis. Bei Bekanntwerden von Rechtsverletzungen werden wir derartige Inhalte umgehend
entfernen.
</p>
</Container>);
} }
export default class ImprintPage extends React.Component { export default class ImprintPage extends React.Component {
render() { render() {
return ( return (<div>
<div> <Head>
<Head> <title>Impressum: turnie.re</title>
<title>Impressum: turnie.re</title> </Head>
</Head> <TurniereNavigation/>
<TurniereNavigation/> <BigImage text="Impressum / Haftungs&shy;ausschluss"/>
<BigImage text="Impressum / Haftungs&shy;ausschluss"/> <Main/>
<Main/> <Footer/>
<Footer/> </div>);
</div>
);
} }
} }

View File

@ -2,10 +2,7 @@ import Head from 'next/head';
import React from 'react'; import React from 'react';
import {connect} from 'react-redux'; import {connect} from 'react-redux';
import { import {
Alert, Alert, Button, Card, CardBody
Button,
Card,
CardBody
} from 'reactstrap'; } from 'reactstrap';
import {TurniereNavigation} from '../js/components/Navigation'; import {TurniereNavigation} from '../js/components/Navigation';
@ -18,60 +15,49 @@ import '../static/everypage.css';
import '../static/css/index.css'; import '../static/css/index.css';
function Main() { function Main() {
return ( return (<div className="main">
<div className="main"> <Marketing/>
<Marketing/> <MainPromotedLinks/>
<MainPromotedLinks/> <MainBottomSummary/>
<MainBottomSummary/> </div>);
</div>
);
} }
function Marketing() { function Marketing() {
return ( return (<div className="container marketing my-5">
<div className="container marketing my-5"> <div className="row">
<div className="row"> <div className="col-lg-4">
<div className="col-lg-4"> <h2>Für jede Sportart</h2>
<h2>Für jede Sportart</h2> <p>
<p> Egal, um welche Sportart es geht: Solange du mit mehreren Mannschaften ein Turnier veranstalten
Egal, um welche Sportart es geht: Solange du mit mehreren Mannschaften ein Turnier veranstalten willst, kann turnie.re dir ein Turnier berechnen!
willst, kann </p>
turnie.re dir ein Turnier berechnen!
</p>
</div>
<div className="col-lg-4">
<h2>Beliebige Anzahl Teams</h2>
<p>
Egal, wie viele Teams du gerne in deinem Turnier hast, wir regeln das. Füge einfach deine Teams
hinzu
und schon sagen wir dir, wer gegen wen spielt.
</p>
</div>
<div className="col-lg-4">
<h2>Kostenlos</h2>
<p>
turnie.re ist ein kostenloser Service! Wir erheben keine Kosten und sind nur darauf aus, dein
Turnier-Management so einfach wie möglich zu gestalten.
</p>
</div>
</div> </div>
<Betawarning/> <div className="col-lg-4">
<h2>Beliebige Anzahl Teams</h2>
<p>
Egal, wie viele Teams du gerne in deinem Turnier hast, wir regeln das. Füge einfach deine Teams
hinzu und schon sagen wir dir, wer gegen wen spielt. </p>
</div>
<div className="col-lg-4">
<h2>Kostenlos</h2>
<p>
turnie.re ist ein kostenloser Service! Wir erheben keine Kosten und sind nur darauf aus, dein
Turnier-Management so einfach wie möglich zu gestalten. </p>
</div>
</div> </div>
); <Betawarning/>
</div>);
} }
function Betawarning() { function Betawarning() {
return ( return (<Alert color="danger" className="shadow-sm mt-4" fade={false}>
<Alert color="danger" className="shadow-sm mt-4" fade={false}> <h4 className="alert-heading custom-font">Public Beta</h4>
<h4 className="alert-heading custom-font">Public Beta</h4> <p>
<p> Diese Website ist noch in der Entwicklung.<br/>
Diese Website ist noch in der Entwicklung.<br/> Bei Problemen fülle bitte <a href="#" id="bugLink" className="alert-link">dieses </a>
Bei Problemen fülle bitte <a href="#" id="bugLink" className="alert-link">dieses </a> und für Feedback <a href="#" id="feedbackLink" className="alert-link">dieses</a> Formular aus. </p>
und für Feedback <a href="#" id="feedbackLink" className="alert-link">dieses</a> Formular aus. </Alert>);
</p>
</Alert>
);
} }
function MainBottomSummary() { function MainBottomSummary() {
@ -84,17 +70,15 @@ function MainBottomSummary() {
turnie.re berechnet dir ein Turnier. Allein aus den Team-Namen berechnen wir dir einen kompletten turnie.re berechnet dir ein Turnier. Allein aus den Team-Namen berechnen wir dir einen kompletten
Spielplan, Spielplan,
den du auch gleich mit allen Leuten teilen kannst, ohne dir Gedanken machen zu müssen, wer gegen wen den du auch gleich mit allen Leuten teilen kannst, ohne dir Gedanken machen zu müssen, wer gegen wen
spielen spielen muss.<br/>
muss.<br/> Du trägst ein, wer gewonnen hat, und turnie.re sagt, wer als nächstes spielt. </p>
Du trägst ein, wer gewonnen hat, und turnie.re sagt, wer als nächstes spielt.
</p>
</div> </div>
<div className="col-lg-6"> <div className="col-lg-6">
<h2>Ich habe einen Turniercode bekommen. Was nun?</h2> <h2>Ich habe einen Turniercode bekommen. Was nun?</h2>
<p> <p>
Der Turniercode führt dich direkt zu einem Turnier. Gebe dafür den Code Der Turniercode führt dich direkt zu einem Turnier. Gebe dafür den Code <a className="text-success"
<a className="text-success" href="#turniercode-form">oben</a> ein, dann wirst du sofort weitergeleitet. href="#turniercode-form">oben</a> ein,
</p> dann wirst du sofort weitergeleitet. </p>
</div> </div>
</div> </div>
<div className="my-5 text-center"> <div className="my-5 text-center">
@ -114,41 +98,34 @@ function MainPromotedLinks() {
} }
function PromotedLinkTournamentCode() { function PromotedLinkTournamentCode() {
return ( return (<Card className="container shadow-lg mt-3">
<Card className="container shadow-lg mt-3"> <CardBody className="row">
<CardBody className="row"> <form id="turniercode-form" className="col-lg-4" action="/t" method="get">
<form id="turniercode-form" className="col-lg-4" action="/t" method="get"> <input className="form-control" type="search" name="code" placeholder="Turnier-Code"/>
<input className="form-control" type="search" name="code" placeholder="Turnier-Code"/> <Button outline color="success" className="w-100 my-2" type="submit">Turnier-Code öffnen</Button>
<Button outline color="success" className="w-100 my-2" type="submit">Turnier-Code öffnen</Button> </form>
</form> <div className="col-lg-8">
<div className="col-lg-8"> <p>Gib hier einen Turnier Code ein, um direkt zum entsprechenden Turnier zu gelangen.</p>
<p>Gib hier einen Turnier Code ein, um direkt zum entsprechenden Turnier zu gelangen.</p> </div>
</div> </CardBody>
</CardBody> </Card>);
</Card>
);
} }
function PromotedLinkListTournaments() { function PromotedLinkListTournaments() {
return ( return (<Card className="container shadow-lg my-4">
<Card className="container shadow-lg my-4"> <CardBody className="row">
<CardBody className="row"> <div className="col-lg-4 pb-3">
<div className="col-lg-4 pb-3"> <Button outline color="success" className="w-100" href="/list">Alle Turniere anzeigen</Button>
<Button outline color="success" className="w-100" href="/list">Alle Turniere anzeigen</Button> </div>
</div> <div className="col-lg-8">
<div className="col-lg-8"> <p>
<p> Hier findest du alle öffentlichen Turniere. Wenn du ein Turnier suchst, den Turniercode aber nicht
Hier findest du alle öffentlichen Turniere. Wenn du ein Turnier suchst, den Turniercode aber hast, wirst du wahrscheinlich hier fündig. </p>
nicht hast, wirst <p>
du wahrscheinlich hier fündig. Wenn du eingeloggt bist, findest du hier auch deine eigenen Turniere. </p>
</p> </div>
<p> </CardBody>
Wenn du eingeloggt bist, findest du hier auch deine eigenen Turniere. </Card>);
</p>
</div>
</CardBody>
</Card>
);
} }
function PromotedLinkCreateTournament() { function PromotedLinkCreateTournament() {
@ -156,9 +133,8 @@ function PromotedLinkCreateTournament() {
<CardBody className="row"> <CardBody className="row">
<div className="col-lg-8"> <div className="col-lg-8">
<p> <p>
<strong>Einfach ausprobieren:</strong> Einen Turnier-Namen, ein paar Team-Namen, und schon <strong>Einfach ausprobieren:</strong> Einen Turnier-Namen, ein paar Team-Namen, und schon kriegst
kriegst du ein du ein komplettes Turnier!
komplettes Turnier!
</p> </p>
</div> </div>
<div className="col-lg-4"> <div className="col-lg-4">
@ -171,17 +147,15 @@ function PromotedLinkCreateTournament() {
class Index extends React.Component { class Index extends React.Component {
render() { render() {
return ( return (<div>
<div> <Head>
<Head> <title>turnie.re</title>
<title>turnie.re</title> </Head>
</Head> <TurniereNavigation/>
<TurniereNavigation/> <BigImage text="Einfach Turniere organisieren"/>
<BigImage text="Einfach Turniere organisieren"/> <Main/>
<Main/> <Footer/>
<Footer/> </div>);
</div>
);
} }
} }

View File

@ -11,18 +11,16 @@ import {connect} from 'react-redux';
export default class PublicTournamentsPage extends React.Component { export default class PublicTournamentsPage extends React.Component {
render() { render() {
return ( return (<div className="main generic-fullpage-bg">
<div className="main generic-fullpage-bg"> <Head>
<Head> <title>Öffentliche Turniere: turnie.re</title>
<title>Öffentliche Turniere: turnie.re</title> </Head>
</Head> <TurniereNavigation/>
<TurniereNavigation/> <div>
<div> <PublicTournamentPageContent/>
<PublicTournamentPageContent/>
</div>
<Footer/>
</div> </div>
); <Footer/>
</div>);
} }
} }
@ -31,9 +29,7 @@ function mapStateToProperties(state) {
return {isSignedIn}; return {isSignedIn};
} }
const PublicTournamentPageContent = connect( const PublicTournamentPageContent = connect(mapStateToProperties)(PublicTournaments);
mapStateToProperties,
)(PublicTournaments);
function PublicTournaments(props) { function PublicTournaments(props) {
if (props.isSignedIn) { if (props.isSignedIn) {

View File

@ -9,17 +9,15 @@ import '../static/everypage.css';
export default class LoginPage extends React.Component { export default class LoginPage extends React.Component {
render() { render() {
return ( return (<div className="main generic-fullpage-bg">
<div className="main generic-fullpage-bg"> <Head>
<Head> <title>Login: turnie.re</title>
<title>Login: turnie.re</title> </Head>
</Head> <TurniereNavigation/>
<TurniereNavigation/> <div>
<div> <Login/>
<Login/>
</div>
<Footer/>
</div> </div>
); <Footer/>
</div>);
} }
} }

View File

@ -11,500 +11,389 @@ import 'bootstrap/dist/css/bootstrap.min.css';
import '../static/everypage.css'; import '../static/everypage.css';
function Main() { function Main() {
return ( return (<div className="main running-text">
<div className="main running-text"> <PrivacyText/>
<PrivacyText/> </div>);
</div>
);
} }
function PrivacyText() { function PrivacyText() {
return ( return (<Container>
<Container> <p>
<p> Die nachfolgende Datenschutzerklärung gilt für die Nutzung unseres Online-Angebots turnie.re (nachfolgend
Die nachfolgende Datenschutzerklärung gilt für die Nutzung unseres Online-Angebots turnie.re (nachfolgend Website).<br/>
Website).<br/> Wir messen dem Datenschutz große Bedeutung bei. Die Erhebung und Verarbeitung Ihrer personenbezogenen Daten
Wir messen dem Datenschutz große Bedeutung bei. Die Erhebung und Verarbeitung Ihrer personenbezogenen Daten geschieht unter Beachtung der geltenden datenschutzrechtlichen Vorschriften, insbesondere der
geschieht Datenschutzgrundverordnung (DSGVO). </p>
unter Beachtung der geltenden datenschutzrechtlichen Vorschriften, insbesondere der <h3>1 Verantwortlicher</h3>
Datenschutzgrundverordnung <p>
(DSGVO). Verantwortlicher für die Erhebung, Verarbeitung und Nutzung Ihrer personenbezogenen Daten im Sinne von Art.
</p> 4 Nr. 7 DSGVO ist </p>
<h3>1 Verantwortlicher</h3> <p>
<p> Jonas Seydel<br/>
Verantwortlicher für die Erhebung, Verarbeitung und Nutzung Ihrer personenbezogenen Daten im Sinne von Art. August-Euler-Weg 3<br/>
4 Nr. 7 76133 Karlsruhe<br/>
DSGVO ist Germany<br/>
</p> jon@s-seydel.de<br/>
<p> </p>
Jonas Seydel<br/> <p>
August-Euler-Weg 3<br/> Sofern Sie der Erhebung, Verarbeitung oder Nutzung Ihrer Daten durch uns nach Maßgabe dieser
76133 Karlsruhe<br/> Datenschutzbestimmungen insgesamt oder für einzelne Maßnahmen widersprechen wollen, können Sie Ihren
Germany<br/> Widerspruch an den Verantwortlichen richten.<br/>
jon@s-seydel.de<br/> Sie können diese Datenschutzerklärung jederzeit speichern und ausdrucken. </p>
</p> <h3>2 Allgemeine Zwecke der Verarbeitung</h3>
<p> <p>
Sofern Sie der Erhebung, Verarbeitung oder Nutzung Ihrer Daten durch uns nach Maßgabe dieser Wir verwenden personenbezogene Daten zum Zweck des Betriebs der Website. </p>
Datenschutzbestimmungen <h3>3 Welche Daten wir verwenden und warum</h3>
insgesamt oder für einzelne Maßnahmen widersprechen wollen, können Sie Ihren Widerspruch an den <h4>3.1 Hosting</h4>
Verantwortlichen <p>
richten.<br/> Die von uns in Anspruch genommenen Hosting-Leistungen dienen der Zurverfügungstellung der folgenden
Sie können diese Datenschutzerklärung jederzeit speichern und ausdrucken. Leistungen:
</p> Infrastruktur- und Plattformdienstleistungen, Rechenkapazität, Speicherplatz und Datenbankdienste,
<h3>2 Allgemeine Zwecke der Verarbeitung</h3> Sicherheitsleistungen sowie technische Wartungsleistungen, die wir zum Zweck des Betriebs der Website
<p> einsetzen.<br/>
Wir verwenden personenbezogene Daten zum Zweck des Betriebs der Website. Hierbei verarbeiten wir, bzw. unser Hostinganbieter Bestandsdaten, Kontaktdaten, Inhaltsdaten,
</p> Vertragsdaten,
<h3>3 Welche Daten wir verwenden und warum</h3> Nutzungsdaten, Meta- und Kommunikationsdaten von Kunden, Interessenten und Besuchern dieser Website auf
<h4>3.1 Hosting</h4> Grundlage unserer berechtigten Interessen an einer effizienten und sicheren Zurverfügungstellung unserer
<p> Website gem. Art. 6 Abs. 1 S. 1 f) DSGVO i.V.m. Art. 28 DSGVO. </p>
Die von uns in Anspruch genommenen Hosting-Leistungen dienen der Zurverfügungstellung der folgenden <h4>3.2 Zugriffsdaten</h4>
Leistungen: <p>
Infrastruktur- und Plattformdienstleistungen, Rechenkapazität, Speicherplatz und Datenbankdienste, Wir sammeln Informationen über Sie, wenn Sie diese Website nutzen. Wir erfassen automatisch Informationen
Sicherheitsleistungen sowie technische Wartungsleistungen, die wir zum Zweck des Betriebs der Website über Ihr Nutzungsverhalten und Ihre Interaktion mit uns und registrieren Daten zu Ihrem Computer oder
einsetzen.<br/> Mobilgerät. Wir erheben,
Hierbei verarbeiten wir, bzw. unser Hostinganbieter Bestandsdaten, Kontaktdaten, Inhaltsdaten, speichern und nutzen Daten über jeden Zugriff auf unsere Website (sogenannte Serverlogfiles). Zu den
Vertragsdaten, Zugriffsdaten gehören:
Nutzungsdaten, Meta- und Kommunikationsdaten von Kunden, Interessenten und Besuchern dieser Website auf </p>
Grundlage <ul>
unserer berechtigten Interessen an einer effizienten und sicheren Zurverfügungstellung unserer Website gem. <li>Name und URL der abgerufenen Datei</li>
Art. 6 <li>Datum und Uhrzeit des Abrufs</li>
Abs. 1 S. 1 f) DSGVO i.V.m. Art. 28 DSGVO. <li>übertragene Datenmenge</li>
</p> <li>Meldung über erfolgreichen Abruf (HTTP response code)</li>
<h4>3.2 Zugriffsdaten</h4> <li>Browsertyp und Browserversion</li>
<p> <li>Betriebssystem</li>
Wir sammeln Informationen über Sie, wenn Sie diese Website nutzen. Wir erfassen automatisch Informationen <li>Referer URL (d.h. die zuvor besuchte Seite)</li>
über Ihr <li>Websites, die vom System des Nutzers über unsere Website aufgerufen werden</li>
Nutzungsverhalten und Ihre Interaktion mit uns und registrieren Daten zu Ihrem Computer oder Mobilgerät. Wir <li>Internet-Service-Provider des Nutzers</li>
erheben, <li>IP-Adresse und der anfragende Provider</li>
speichern und nutzen Daten über jeden Zugriff auf unsere Website (sogenannte Serverlogfiles). Zu den </ul>
Zugriffsdaten <p>
gehören: Wir nutzen diese Protokolldaten ohne Zuordnung zu Ihrer Person oder sonstiger Profilerstellung für
</p> statistische Auswertungen zum Zweck des Betriebs, der Sicherheit und der Optimierung unserer Website, aber
<ul> auch zur anonymen Erfassung der Anzahl der Besucher auf unserer Website (traffic) sowie zum Umfang und zur
<li>Name und URL der abgerufenen Datei</li> Art der Nutzung unserer Website und Dienste, ebenso zu Abrechnungszwecken, um die Anzahl der von
<li>Datum und Uhrzeit des Abrufs</li> Kooperationspartnern erhaltenen Clicks zu messen. Aufgrund dieser Informationen können wir personalisierte
<li>übertragene Datenmenge</li> und standortbezogene Inhalte zur Verfügung stellen und den Datenverkehr analysieren, Fehler suchen und
<li>Meldung über erfolgreichen Abruf (HTTP response code)</li> beheben und unsere Dienste verbessern.<br/>
<li>Browsertyp und Browserversion</li> Hierin liegt auch unser berechtigtes Interesse gemäß Art 6 Abs. 1 S. 1 f) DSGVO.<br/>
<li>Betriebssystem</li> Wir behalten uns vor, die Protokolldaten nachträglich zu überprüfen, wenn aufgrund konkreter Anhaltspunkte
<li>Referer URL (d.h. die zuvor besuchte Seite)</li> der berechtigte Verdacht einer rechtswidrigen Nutzung besteht. IP-Adressen speichern wir für einen
<li>Websites, die vom System des Nutzers über unsere Website aufgerufen werden</li> begrenzten Zeitraum in den Logfiles, wenn dies für Sicherheitszwecke erforderlich oder für die
<li>Internet-Service-Provider des Nutzers</li> Leistungserbringung oder die Abrechnung einer Leistung nötig ist, z. B. wenn Sie eines unserer Angebote
<li>IP-Adresse und der anfragende Provider</li> nutzen. Nach Abbruch des Vorgangs der Bestellung oder nach Zahlungseingang löschen wir die IP-Adresse, wenn
</ul> diese für Sicherheitszwecke nicht mehr erforderlich ist. IP-Adressen speichern wir auch dann, wenn wir den
<p> konkreten Verdacht einer Straftat im Zusammenhang mit der Nutzung unserer Website haben. Außerdem speichern
Wir nutzen diese Protokolldaten ohne Zuordnung zu Ihrer Person oder sonstiger Profilerstellung für wir als Teil Ihres Accounts das Datum Ihres letzten Besuchs (z.B. bei Registrierung,
statistische Login, Klicken von Links etc.). </p>
Auswertungen zum Zweck des Betriebs, der Sicherheit und der Optimierung unserer Website, aber auch zur <h4>3.3 Cookies</h4>
anonymen <p>
Erfassung der Anzahl der Besucher auf unserer Website (traffic) sowie zum Umfang und zur Art der Nutzung Wir verwenden sogenannte Session-Cookies, um unsere Website zu optimieren. Ein Session-Cookie ist eine
unserer kleine Textdatei, die von den jeweiligen Servern beim Besuch einer Internetseite verschickt und auf Ihrer
Website und Dienste, ebenso zu Abrechnungszwecken, um die Anzahl der von Kooperationspartnern erhaltenen Festplatte zwischengespeichert wird. Diese Datei als solche enthält eine sogenannte Session-ID, mit welcher
Clicks zu sich verschiedene Anfragen Ihres Browsers der gemeinsamen Sitzung zuordnen lassen. Dadurch kann Ihr Rechner
messen. Aufgrund dieser Informationen können wir personalisierte und standortbezogene Inhalte zur Verfügung wiedererkannt werden, wenn Sie auf unsere Website zurückkehren. Diese Cookies werden gelöscht, nachdem Sie
stellen Ihren Browser schließen. Sie dienen z. B. dazu, dass Sie die Warenkorbfunktion über mehrere Seiten hinweg
und den Datenverkehr analysieren, Fehler suchen und beheben und unsere Dienste verbessern.<br/> nutzen können.<br/>
Hierin liegt auch unser berechtigtes Interesse gemäß Art 6 Abs. 1 S. 1 f) DSGVO.<br/> Wir verwenden in geringem Umfang auch persistente Cookies (ebenfalls kleine Textdateien, die auf Ihrem
Wir behalten uns vor, die Protokolldaten nachträglich zu überprüfen, wenn aufgrund konkreter Anhaltspunkte Endgerät abgelegt werden), die auf Ihrem Endgerät verbleiben und es uns ermöglichen, Ihren Browser beim
der nächsten Besuch wiederzuerkennen. Diese Cookies werden auf Ihrer Festplatte gespeichert und löschen sich
berechtigte Verdacht einer rechtswidrigen Nutzung besteht. IP-Adressen speichern wir für einen begrenzten nach der vorgegebenen Zeit von allein. Ihre Lebensdauer beträgt 1 Monat bis 10 Jahre. So können wir Ihnen
Zeitraum in unser Angebot nutzerfreundlicher,
den Logfiles, wenn dies für Sicherheitszwecke erforderlich oder für die Leistungserbringung oder die effektiver und sicherer präsentieren und Ihnen beispielsweise speziell auf Ihre Interessen abgestimmte
Abrechnung einer Informationen auf der Seite anzeigen.<br/>
Leistung nötig ist, z. B. wenn Sie eines unserer Angebote nutzen. Nach Abbruch des Vorgangs der Bestellung Unser berechtigtes Interesse an der Nutzung der Cookies gemäß Art 6 Abs. 1 S. 1 f) DSGVO liegt darin,
oder nach unsere Website nutzerfreundlicher, effektiver und sicherer zu machen.<br/>
Zahlungseingang löschen wir die IP-Adresse, wenn diese für Sicherheitszwecke nicht mehr erforderlich ist. In den Cookies werden etwa folgende Daten und Informationen gespeichert:
IP-Adressen </p>
speichern wir auch dann, wenn wir den konkreten Verdacht einer Straftat im Zusammenhang mit der Nutzung <ul>
unserer <li>Log-In-Informationen</li>
Website haben. Außerdem speichern wir als Teil Ihres Accounts das Datum Ihres letzten Besuchs (z.B. bei <li>Spracheinstellungen</li>
Registrierung, <li>eingegebene Suchbegriffe</li>
Login, Klicken von Links etc.). <li>Informationen über die Anzahl der Aufrufe unserer Website sowie Nutzung einzelner Funktionen unseres
</p> Internetauftritts.
<h4>3.3 Cookies</h4> </li>
<p> </ul>
Wir verwenden sogenannte Session-Cookies, um unsere Website zu optimieren. Ein Session-Cookie ist eine <p>
kleine Bei Aktivierung des Cookies wird diesem eine Identifikationsnummer zugewiesen und eine Zuordnung Ihrer
Textdatei, die von den jeweiligen Servern beim Besuch einer Internetseite verschickt und auf Ihrer personenbezogenen Daten zu dieser Identifikationsnummer wird nicht vorgenommen. Ihr Name, Ihre IP-Adresse
Festplatte oder ähnliche Daten, die eine Zuordnung des Cookies zu Ihnen ermöglichen würden, werden nicht in den Cookie
zwischengespeichert wird. Diese Datei als solche enthält eine sogenannte Session-ID, mit welcher sich eingelegt. Auf Basis der Cookie-Technologie erhalten wir lediglich pseudonymisierte Informationen,
verschiedene beispielsweise darüber,
Anfragen Ihres Browsers der gemeinsamen Sitzung zuordnen lassen. Dadurch kann Ihr Rechner wiedererkannt welche Seiten unseres Shops besucht wurden, welche Produkte angesehen wurden, etc.<br/>
werden, wenn Sie können Ihren Browser so einstellen, dass Sie über das Setzen von Cookies vorab informiert werden und im
Sie auf unsere Website zurückkehren. Diese Cookies werden gelöscht, nachdem Sie Ihren Browser schließen. Sie Einzelfall entscheiden können, ob Sie die Annahme von Cookies für bestimmte Fälle oder generell
dienen z. ausschließen, oder dass Cookies komplett verhindert werden. Dadurch kann die Funktionalität der Website
B. dazu, dass Sie die Warenkorbfunktion über mehrere Seiten hinweg nutzen können.<br/> eingeschränkt werden. </p>
Wir verwenden in geringem Umfang auch persistente Cookies (ebenfalls kleine Textdateien, die auf Ihrem <h4>3.4 Nutzerkonto</h4>
Endgerät <p>Sie können auf unserer Website ein Nutzerkonto anlegen. Wünschen Sie dies, so benötigen wir die beim Login
abgelegt werden), die auf Ihrem Endgerät verbleiben und es uns ermöglichen, Ihren Browser beim nächsten abgefragten personenbezogenen Daten. Beim späteren Einloggen werden nur Ihre Email bzw. Benutzername und das
Besuch von Ihnen gewählte Passwort benötigt.<br/>
wiederzuerkennen. Diese Cookies werden auf Ihrer Festplatte gespeichert und löschen sich nach der Für die Neuregistrierung erheben wir Stammdaten (z. B. Name, Adresse), Kommunikationsdaten (z. B.
vorgegebenen Zeit E-Mail-Adresse)
von allein. Ihre Lebensdauer beträgt 1 Monat bis 10 Jahre. So können wir Ihnen unser Angebot sowie Zugangsdaten (Benutzername u. Passwort).<br/>
nutzerfreundlicher, Sie können ein einmal angelegtes Nutzerkonto jederzeit von uns löschen lassen, ohne dass hierfür andere als
effektiver und sicherer präsentieren und Ihnen beispielsweise speziell auf Ihre Interessen abgestimmte die Übermittlungskosten nach den Basistarifen entstehen. Eine Mitteilung in Textform an die unter Ziffer 1
Informationen genannten Kontaktdaten (z.B. E-Mail, Fax, Brief) reicht hierfür aus. Wir werden dann Ihre gespeicherten
auf der Seite anzeigen.<br/> personenbezogenen Daten löschen, soweit wir diese nicht noch zur Abwicklung von Bestellungen oder aufgrund
Unser berechtigtes Interesse an der Nutzung der Cookies gemäß Art 6 Abs. 1 S. 1 f) DSGVO liegt darin, unsere gesetzlicher Aufbewahrungspflichten speichern müssen.<br/>
Website Rechtgrundlage für die Verarbeitung dieser Daten ist Ihre Einwilligung gemäß Art. 6 Abs. 1 S. 1 a)
nutzerfreundlicher, effektiver und sicherer zu machen.<br/> DSGVO. </p>
In den Cookies werden etwa folgende Daten und Informationen gespeichert: <h4>3.5 E-Mail Kontakt</h4>
</p> <p>
<ul> Wenn Sie mit uns in Kontakt treten (z. B. per Kontaktformular oder E-Mail), verarbeiten wir Ihre Angaben zur
<li>Log-In-Informationen</li> Bearbeitung der Anfrage sowie für den Fall, dass Anschlussfragen entstehen. Erfolgt die Datenverarbeitung
<li>Spracheinstellungen</li> zur Durchführung vorvertraglicher Maßnahmen, die auf Ihre Anfrage hin erfolgen, bzw.,
<li>eingegebene Suchbegriffe</li> wenn Sie bereits unser Kunde sind, zur Durchführung des Vertrages, ist Rechtsgrundlage für diese
<li>Informationen über die Anzahl der Aufrufe unserer Website sowie Nutzung einzelner Funktionen unseres Datenverarbeitung Art. 6 Abs. 1 S. 1 b) DSGVO. Weitere personenbezogene Daten verarbeiten wir nur, wenn Sie
Internetauftritts. dazu einwilligen (Art. 6 Abs. 1 S. 1 a)
</li> DSGVO)
</ul> oder wir ein berechtigtes Interesse an der Verarbeitung Ihrer Daten haben (Art. 6 Abs. 1 S. 1 f) DSGVO). Ein
<p> berechtigtes Interesse liegt z. B. darin, auf Ihre E-Mail zu antworten. </p>
Bei Aktivierung des Cookies wird diesem eine Identifikationsnummer zugewiesen und eine Zuordnung Ihrer <h3>4 Speicherdauer</h3>
personenbezogenen Daten zu dieser Identifikationsnummer wird nicht vorgenommen. Ihr Name, Ihre IP-Adresse <p>
oder Sofern nicht spezifisch angegeben speichern wir personenbezogene Daten nur so lange, wie dies zur Erfüllung
ähnliche Daten, die eine Zuordnung des Cookies zu Ihnen ermöglichen würden, werden nicht in den Cookie der verfolgten Zwecke notwendig ist.<br/>
eingelegt. Auf In einigen Fällen sieht der Gesetzgeber die Aufbewahrung von personenbezogenen Daten vor, etwa im Steuer-
Basis der Cookie-Technologie erhalten wir lediglich pseudonymisierte Informationen, beispielsweise darüber, oder Handelsrecht. In diesen Fällen werden die Daten von uns lediglich für diese gesetzlichen Zwecke weiter
welche gespeichert,
Seiten unseres Shops besucht wurden, welche Produkte angesehen wurden, etc.<br/> aber nicht anderweitig verarbeitet und nach Ablauf der gesetzlichen Aufbewahrungsfrist gelöscht. </p>
Sie können Ihren Browser so einstellen, dass Sie über das Setzen von Cookies vorab informiert werden und im <h3>5 Ihre Rechte als von der Datenverarbeitung Betroffener</h3>
Einzelfall <p>
entscheiden können, ob Sie die Annahme von Cookies für bestimmte Fälle oder generell ausschließen, oder dass Nach den anwendbaren Gesetzen haben Sie verschiedene Rechte bezüglich Ihrer personenbezogenen Daten. Möchten
Cookies Sie diese Rechte geltend machen, so richten Sie Ihre Anfrage bitte per E-Mail oder per Post unter
komplett verhindert werden. Dadurch kann die Funktionalität der Website eingeschränkt werden. eindeutiger Identifizierung Ihrer Person an die in Ziffer 1 genannte Adresse.<br/>
</p> Nachfolgend finden Sie eine Übersicht über Ihre Rechte. </p>
<h4>3.4 Nutzerkonto</h4>
<p>Sie können auf unserer Website ein Nutzerkonto anlegen. Wünschen Sie dies, so benötigen wir die beim Login
abgefragten
personenbezogenen Daten. Beim späteren Einloggen werden nur Ihre Email bzw. Benutzername und das von Ihnen
gewählte
Passwort benötigt.<br/>
Für die Neuregistrierung erheben wir Stammdaten (z. B. Name, Adresse), Kommunikationsdaten (z. B.
E-Mail-Adresse)
sowie Zugangsdaten (Benutzername u. Passwort).<br/>
Sie können ein einmal angelegtes Nutzerkonto jederzeit von uns löschen lassen, ohne dass hierfür andere
als die
Übermittlungskosten nach den Basistarifen entstehen. Eine Mitteilung in Textform an die unter Ziffer 1
genannten
Kontaktdaten (z.B. E-Mail, Fax, Brief) reicht hierfür aus. Wir werden dann Ihre gespeicherten
personenbezogenen Daten
löschen, soweit wir diese nicht noch zur Abwicklung von Bestellungen oder aufgrund gesetzlicher
Aufbewahrungspflichten
speichern müssen.<br/>
Rechtgrundlage für die Verarbeitung dieser Daten ist Ihre Einwilligung gemäß Art. 6 Abs. 1 S. 1 a)
DSGVO.
</p>
<h4>3.5 E-Mail Kontakt</h4>
<p>
Wenn Sie mit uns in Kontakt treten (z. B. per Kontaktformular oder E-Mail), verarbeiten wir Ihre Angaben zur
Bearbeitung der Anfrage sowie für den Fall, dass Anschlussfragen entstehen.
Erfolgt die Datenverarbeitung zur Durchführung vorvertraglicher Maßnahmen, die auf Ihre Anfrage hin
erfolgen, bzw.,
wenn Sie bereits unser Kunde sind, zur Durchführung des Vertrages, ist Rechtsgrundlage für diese
Datenverarbeitung
Art. 6 Abs. 1 S. 1 b) DSGVO.
Weitere personenbezogene Daten verarbeiten wir nur, wenn Sie dazu einwilligen (Art. 6 Abs. 1 S. 1 a) DSGVO)
oder wir
ein berechtigtes Interesse an der Verarbeitung Ihrer Daten haben (Art. 6 Abs. 1 S. 1 f) DSGVO). Ein
berechtigtes
Interesse liegt z. B. darin, auf Ihre E-Mail zu antworten.
</p>
<h3>4 Speicherdauer</h3>
<p>
Sofern nicht spezifisch angegeben speichern wir personenbezogene Daten nur so lange, wie dies zur Erfüllung
der
verfolgten Zwecke notwendig ist.<br/>
In einigen Fällen sieht der Gesetzgeber die Aufbewahrung von personenbezogenen Daten vor, etwa im Steuer-
oder
Handelsrecht. In diesen Fällen werden die Daten von uns lediglich für diese gesetzlichen Zwecke weiter
gespeichert,
aber nicht anderweitig verarbeitet und nach Ablauf der gesetzlichen Aufbewahrungsfrist gelöscht.
</p>
<h3>5 Ihre Rechte als von der Datenverarbeitung Betroffener</h3>
<p>
Nach den anwendbaren Gesetzen haben Sie verschiedene Rechte bezüglich Ihrer personenbezogenen Daten. Möchten
Sie diese
Rechte geltend machen, so richten Sie Ihre Anfrage bitte per E-Mail oder per Post unter eindeutiger
Identifizierung
Ihrer Person an die in Ziffer 1 genannte Adresse.<br/>
Nachfolgend finden Sie eine Übersicht über Ihre Rechte.
</p>
<h4>5.1 Recht auf Bestätigung und Auskunft</h4> <h4>5.1 Recht auf Bestätigung und Auskunft</h4>
<p> <p>
Sie haben das Recht auf eine übersichtliche Auskunft über die Verarbeitung Ihrer personenbezogenen Sie haben das Recht auf eine übersichtliche Auskunft über die Verarbeitung Ihrer personenbezogenen
Daten.<br/> Daten.<br/>
Im Einzelnen:<br/> Im Einzelnen:<br/>
Sie haben jederzeit das Recht, von uns eine Bestätigung darüber zu erhalten, ob Sie betreffende Sie haben jederzeit das Recht, von uns eine Bestätigung darüber zu erhalten, ob Sie betreffende
personenbezogene Daten personenbezogene Daten verarbeitet werden. Ist dies der Fall, so haben Sie das Recht, von uns eine
verarbeitet werden. Ist dies der Fall, so haben Sie das Recht, von uns eine unentgeltliche Auskunft über die unentgeltliche Auskunft über die zu Ihnen gespeicherten personenbezogenen Daten nebst einer Kopie dieser
zu Ihnen Daten zu verlangen. Des Weiteren besteht ein Recht auf folgende Informationen:
gespeicherten personenbezogenen Daten nebst einer Kopie dieser Daten zu verlangen. Des Weiteren besteht ein </p>
Recht auf <ol>
folgende Informationen: <li>die Verarbeitungszwecke;</li>
</p> <li>die Kategorien personenbezogener Daten, die verarbeitet werden;</li>
<ol> <li>die Empfänger oder Kategorien von Empfängern, gegenüber denen die personenbezogenen Daten offengelegt
<li>die Verarbeitungszwecke;</li> worden sind oder noch offengelegt werden, insbesondere bei Empfängern in Drittländern oder bei
<li>die Kategorien personenbezogener Daten, die verarbeitet werden;</li> internationalen Organisationen;
<li>die Empfänger oder Kategorien von Empfängern, gegenüber denen die personenbezogenen Daten offengelegt </li>
worden sind <li>falls möglich, die geplante Dauer, für die die personenbezogenen Daten gespeichert werden, oder,
oder noch offengelegt werden, insbesondere bei Empfängern in Drittländern oder bei internationalen falls dies nicht möglich ist, die Kriterien für die Festlegung dieser Dauer;
Organisationen; </li>
</li> <li>das Bestehen eines Rechts auf Berichtigung oder Löschung der Sie betreffenden personenbezogenen Daten
<li>falls möglich, die geplante Dauer, für die die personenbezogenen Daten gespeichert werden, oder, falls oder auf Einschränkung der Verarbeitung durch den Verantwortlichen oder eines Widerspruchsrechts gegen
dies nicht diese Verarbeitung;
möglich ist, die Kriterien für die Festlegung dieser Dauer; </li>
</li> <li>das Bestehen eines Beschwerderechts bei einer Aufsichtsbehörde;</li>
<li>das Bestehen eines Rechts auf Berichtigung oder Löschung der Sie betreffenden personenbezogenen Daten <li>wenn die personenbezogenen Daten nicht bei Ihnen erhoben werden, alle verfügbaren Informationen über die
oder auf Herkunft der Daten;
Einschränkung der Verarbeitung durch den Verantwortlichen oder eines Widerspruchsrechts gegen diese </li>
Verarbeitung; <li>das Bestehen einer automatisierten Entscheidungsfindung einschließlich Profiling gemäß Art. 22 Abs. 1
</li> und 4 DSGVO und zumindest in diesen Fällen aussagekräftige Informationen über die involvierte Logik
<li>das Bestehen eines Beschwerderechts bei einer Aufsichtsbehörde;</li> sowie die Tragweite und die angestrebten Auswirkungen einer derartigen Verarbeitung für Sie.
<li>wenn die personenbezogenen Daten nicht bei Ihnen erhoben werden, alle verfügbaren Informationen über die </li>
Herkunft </ol>
der Daten; <p>
</li> Werden personenbezogene Daten an ein Drittland oder an eine internationale Organisation übermittelt, so
<li>das Bestehen einer automatisierten Entscheidungsfindung einschließlich Profiling gemäß Art. 22 Abs. 1 haben Sie das Recht, über die geeigneten Garantien gemäß Art. 46 DSGVO im Zusammenhang mit der Übermittlung
und 4 DSGVO unterrichtet zu werden. </p>
und zumindest in diesen Fällen aussagekräftige Informationen über die involvierte Logik sowie die <h4>5.2 Recht auf Berichtigung</h4>
Tragweite <p>
und die angestrebten Auswirkungen einer derartigen Verarbeitung für Sie. Sie haben das Recht, von uns die Berichtigung und ggf. auch Vervollständigung Sie betreffender
</li> personenbezogener Daten zu verlangen.<br/>
</ol> Im Einzelnen:<br/>
<p> Sie haben das Recht, von uns unverzüglich die Berichtigung Sie betreffender unrichtiger personenbezogener
Werden personenbezogene Daten an ein Drittland oder an eine internationale Organisation übermittelt, so Daten zu verlangen. Unter Berücksichtigung der Zwecke der Verarbeitung haben Sie das Recht, die
haben Sie das Vervollständigung unvollständiger personenbezogener Daten auch mittels einer ergänzenden Erklärung zu
Recht, über die geeigneten Garantien gemäß Art. 46 DSGVO im Zusammenhang mit der Übermittlung unterrichtet verlangen.<br/>
zu werden. </p>
</p>
<h4>5.2 Recht auf Berichtigung</h4>
<p>
Sie haben das Recht, von uns die Berichtigung und ggf. auch Vervollständigung Sie betreffender
personenbezogener Daten
zu verlangen.<br/>
Im Einzelnen:<br/>
Sie haben das Recht, von uns unverzüglich die Berichtigung Sie betreffender unrichtiger personenbezogener
Daten zu
verlangen. Unter Berücksichtigung der Zwecke der Verarbeitung haben Sie das Recht, die Vervollständigung
unvollständiger personenbezogener Daten auch mittels einer ergänzenden Erklärung zu verlangen.<br/>
</p>
<h4>5.3 Recht auf Löschung ("Recht auf Vergessenwerden")</h4> <h4>5.3 Recht auf Löschung ("Recht auf Vergessenwerden")</h4>
<p> <p>
In einer Reihe von Fällen sind wir verpflichtet, Sie betreffende personenbezogene Daten zu löschen.<br/> In einer Reihe von Fällen sind wir verpflichtet, Sie betreffende personenbezogene Daten zu löschen.<br/>
Im Einzelnen:<br/> Im Einzelnen:<br/>
Sie haben gemäß Art. 17 Abs. 1 DSGVO das Recht, von uns zu verlangen, dass Sie betreffende personenbezogene Sie haben gemäß Art. 17 Abs. 1 DSGVO das Recht, von uns zu verlangen, dass Sie betreffende personenbezogene
Daten Daten unverzüglich gelöscht werden, und wir sind verpflichtet, personenbezogene Daten unverzüglich zu
unverzüglich gelöscht werden, und wir sind verpflichtet, personenbezogene Daten unverzüglich zu löschen, löschen,
sofern einer sofern einer der folgenden Gründe zutrifft:
der folgenden Gründe zutrifft: </p>
</p> <ol>
<ol> <li>Die personenbezogenen Daten sind für die Zwecke, für die sie erhoben oder auf sonstige Weise verarbeitet
<li>Die personenbezogenen Daten sind für die Zwecke, für die sie erhoben oder auf sonstige Weise verarbeitet wurden,
wurden, nicht mehr notwendig.
nicht mehr notwendig. </li>
</li> <li>Sie widerrufen Ihre Einwilligung, auf die sich die Verarbeitung gemäß Art. 6 Abs. 1 S. 1 a) DSGVO oder
<li>Sie widerrufen Ihre Einwilligung, auf die sich die Verarbeitung gemäß Art. 6 Abs. 1 S. 1 a) DSGVO oder Art. 9 Abs. 2 a) DSGVO stützte, und es fehlt an einer anderweitigen Rechtsgrundlage für die
Art. 9 Abs. Verarbeitung.
2 a) DSGVO stützte, und es fehlt an einer anderweitigen Rechtsgrundlage für die Verarbeitung. </li>
</li> <li>Sie legen gemäß Art. 21 Abs. 1 DSGVO Widerspruch gegen die Verarbeitung ein und es liegen keine
<li>Sie legen gemäß Art. 21 Abs. 1 DSGVO Widerspruch gegen die Verarbeitung ein und es liegen keine vorrangigen berechtigten Gründe für die Verarbeitung vor, oder Sie legen gemäß Art. 21 Abs. 2 DSGVO
vorrangigen Widerspruch gegen die Verarbeitung ein.
berechtigten Gründe für die Verarbeitung vor, oder Sie legen gemäß Art. 21 Abs. 2 DSGVO Widerspruch </li>
gegen die <li>Die personenbezogenen Daten wurden unrechtmäßig verarbeitet.</li>
Verarbeitung ein. <li>Die Löschung der personenbezogenen Daten ist zur Erfüllung einer rechtlichen Verpflichtung nach dem
</li> Unionsrecht oder dem Recht der Mitgliedstaaten erforderlich, dem wir unterliegen.
<li>Die personenbezogenen Daten wurden unrechtmäßig verarbeitet.</li> </li>
<li>Die Löschung der personenbezogenen Daten ist zur Erfüllung einer rechtlichen Verpflichtung nach dem <li>Die personenbezogenen Daten wurden in Bezug auf angebotene Dienste der Informationsgesellschaft gemäß
Unionsrecht Art. 8 Abs. 1 DSGVO erhoben.
oder dem Recht der Mitgliedstaaten erforderlich, dem wir unterliegen. </li>
</li> </ol>
<li>Die personenbezogenen Daten wurden in Bezug auf angebotene Dienste der Informationsgesellschaft gemäß <p>
Art. 8 Abs. Haben wir die personenbezogenen Daten öffentlich gemacht und sind wir gemäß Art. 17 Abs. 1 DSGVO zu deren
1 DSGVO erhoben. Löschung verpflichtet, so treffen wir unter Berücksichtigung der verfügbaren Technologie und der
</li> Implementierungskosten angemessene Maßnahmen, auch technischer Art, um für die Datenverarbeitung
</ol> Verantwortliche, die die personenbezogenen Daten verarbeiten, darüber zu informieren, dass Sie von ihnen die
<p> Löschung aller Links zu diesen personenbezogenen Daten oder von Kopien oder Replikationen dieser
Haben wir die personenbezogenen Daten öffentlich gemacht und sind wir gemäß Art. 17 Abs. 1 DSGVO zu deren personenbezogenen Daten verlangt haben. </p>
Löschung <h4>5.4 Recht auf Einschränkung der Verarbeitung</h4>
verpflichtet, so treffen wir unter Berücksichtigung der verfügbaren Technologie und der <p>
Implementierungskosten In einer Reihe von Fällen sind Sie berechtigt, von uns eine Einschränkung der Verarbeitung Ihrer
angemessene Maßnahmen, auch technischer Art, um für die Datenverarbeitung Verantwortliche, die die personenbezogenen Daten zu verlangen.<br/>
personenbezogenen Im Einzelnen:<br/>
Daten verarbeiten, darüber zu informieren, dass Sie von ihnen die Löschung aller Links zu diesen Sie haben das Recht, von uns die Einschränkung der Verarbeitung zu verlangen, wenn eine der folgenden
personenbezogenen Voraussetzungen gegeben ist:
Daten oder von Kopien oder Replikationen dieser personenbezogenen Daten verlangt haben. </p>
</p> <ol>
<h4>5.4 Recht auf Einschränkung der Verarbeitung</h4> <li>die Richtigkeit der personenbezogenen Daten wird von Ihnen bestritten, und zwar für eine Dauer, die es
<p> uns ermöglicht, die Richtigkeit der personenbezogenen Daten zu überprüfen,
In einer Reihe von Fällen sind Sie berechtigt, von uns eine Einschränkung der Verarbeitung Ihrer </li>
personenbezogenen <li>die Verarbeitung unrechtmäßig ist und Sie die Löschung der personenbezogenen Daten ablehnten und
Daten zu verlangen.<br/> stattdessen die Einschränkung der Nutzung der personenbezogenen Daten verlangt haben;
Im Einzelnen:<br/> </li>
Sie haben das Recht, von uns die Einschränkung der Verarbeitung zu verlangen, wenn eine der folgenden <li>wir die personenbezogenen Daten für die Zwecke der Verarbeitung nicht länger benötigen, Sie die Daten
Voraussetzungen jedoch zur Geltendmachung, Ausübung oder Verteidigung von Rechtsansprüchen benötigen, oder
gegeben ist: </li>
</p> <li>Sie Widerspruch gegen die Verarbeitung gemäß Art. 21 Abs. 1 DSGVO eingelegt haben, solange noch nicht
<ol> feststeht,
<li>die Richtigkeit der personenbezogenen Daten wird von Ihnen bestritten, und zwar für eine Dauer, die es ob die berechtigten Gründe unseres Unternehmens gegenüber den Ihren überwiegen.
uns </li>
ermöglicht, die Richtigkeit der personenbezogenen Daten zu überprüfen, </ol>
</li> <h4>5.5 Recht auf Datenübertragbarkeit</h4>
<li>die Verarbeitung unrechtmäßig ist und Sie die Löschung der personenbezogenen Daten ablehnten und <p>
stattdessen die Sie haben das Recht, Sie betreffende personenbezogene Daten maschinenlesbar zu erhalten, zu übermitteln,
Einschränkung der Nutzung der personenbezogenen Daten verlangt haben; oder von uns übermitteln zu lasen.<br/>
</li> Im Einzelnen:<br/>
<li>wir die personenbezogenen Daten für die Zwecke der Verarbeitung nicht länger benötigen, Sie die Daten Sie haben das Recht, die Sie betreffenden personenbezogenen Daten, die Sie uns bereitgestellt haben, in
jedoch zur einem strukturierten, gängigen und maschinenlesbaren Format zu erhalten, und Sie haben das Recht, diese
Geltendmachung, Ausübung oder Verteidigung von Rechtsansprüchen benötigen, oder Daten einem anderen Verantwortlichen ohne Behinderung durch uns zu übermitteln, sofern </p>
</li> <ol>
<li>Sie Widerspruch gegen die Verarbeitung gemäß Art. 21 Abs. 1 DSGVO eingelegt haben, solange noch nicht <li>die Verarbeitung auf einer Einwilligung gemäß Art. 6 Abs. 1 S. 1 a) DSGVO oder Art. 9 Abs. 2 a)
feststeht, DSGVO oder auf einem Vertrag gemäß Art. 6 Abs. 1 S. 1 b) DSGVO beruht und
ob die berechtigten Gründe unseres Unternehmens gegenüber den Ihren überwiegen. </li>
</li> <li>die Verarbeitung mithilfe automatisierter Verfahren erfolgt.</li>
</ol> </ol>
<h4>5.5 Recht auf Datenübertragbarkeit</h4> <p>
<p> Bei der Ausübung Ihres Rechts auf Datenübertragbarkeit gemäß Absatz 1 haben Sie das Recht, zu erwirken,
Sie haben das Recht, Sie betreffende personenbezogene Daten maschinenlesbar zu erhalten, zu übermitteln, dass die personenbezogenen Daten direkt von uns einem anderen Verantwortlichen übermittelt werden, soweit
oder von uns dies technisch machbar ist. </p>
übermitteln zu lasen.<br/> <h4>5.6 Widerspruchsrecht</h4>
Im Einzelnen:<br/> <p>
Sie haben das Recht, die Sie betreffenden personenbezogenen Daten, die Sie uns bereitgestellt haben, in Sie haben das Recht, auch einer rechtmäßigen Verarbeitung Ihrer personenbezogenen Daten durch uns zu
einem widersprechen,
strukturierten, gängigen und maschinenlesbaren Format zu erhalten, und Sie haben das Recht, diese Daten wenn sich dies aus Ihrer besonderen Situation begründet und unsere Interessen an der Verarbeitung nicht
einem anderen überwiegen.<br/>
Verantwortlichen ohne Behinderung durch uns zu übermitteln, sofern Im Einzelnen:<br/>
</p> Sie haben das Recht, aus Gründen, die sich aus Ihrer besonderen Situation ergeben, jederzeit gegen die
<ol> Verarbeitung Sie betreffender personenbezogener Daten, die aufgrund von Art. 6 Abs. 1 S. 1 e) oder f) DSGVO
<li>die Verarbeitung auf einer Einwilligung gemäß Art. 6 Abs. 1 S. 1 a) DSGVO oder Art. 9 Abs. 2 a) DSGVO erfolgt,
oder auf Widerspruch einzulegen; dies gilt auch für ein auf diese Bestimmungen gestütztes Profiling. Wir verarbeiten
einem Vertrag gemäß Art. 6 Abs. 1 S. 1 b) DSGVO beruht und die personenbezogenen Daten nicht mehr, es sei denn, wir können zwingende schutzwürdige Gründe für die
</li> Verarbeitung nachweisen,
<li>die Verarbeitung mithilfe automatisierter Verfahren erfolgt.</li> die Ihre Interessen, Rechte und Freiheiten überwiegen, oder die Verarbeitung dient der Geltendmachung,
</ol> Ausübung oder Verteidigung von Rechtsansprüchen.<br/>
<p> Werden personenbezogene Daten von uns verarbeitet, um Direktwerbung zu betreiben, so haben Sie das Recht,
Bei der Ausübung Ihres Rechts auf Datenübertragbarkeit gemäß Absatz 1 haben Sie das Recht, zu erwirken, dass jederzeit Widerspruch gegen die Verarbeitung Sie betreffender personenbezogener Daten zum Zwecke derartiger
die Werbung einzulegen;
personenbezogenen Daten direkt von uns einem anderen Verantwortlichen übermittelt werden, soweit dies dies gilt auch für das Profiling, soweit es mit solcher Direktwerbung in Verbindung steht.<br/>
technisch Sie haben das Recht, aus Gründen, die sich aus Ihrer besonderen Situation ergeben, gegen die Sie betreffende
machbar ist. Verarbeitung Sie betreffender personenbezogener Daten, die zu wissenschaftlichen oder historischen
</p> Forschungszwecken oder zu statistischen Zwecken gemäß Art. 89 Abs. 1 DSGVO erfolgt, Widerspruch einzulegen,
<h4>5.6 Widerspruchsrecht</h4> es sei denn,
<p> die Verarbeitung ist zur Erfüllung einer im öffentlichen Interesse liegenden Aufgabe erforderlich.<br/>
Sie haben das Recht, auch einer rechtmäßigen Verarbeitung Ihrer personenbezogenen Daten durch uns zu </p>
widersprechen, <h4>5.7 Automatisierte Entscheidungen einschließlich Profiling</h4>
wenn sich dies aus Ihrer besonderen Situation begründet und unsere Interessen an der Verarbeitung nicht <p>
überwiegen.<br/> Sie haben das Recht, nicht einer ausschließlich auf einer automatisierten Verarbeitung einschließlich
Im Einzelnen:<br/> Profiling
Sie haben das Recht, aus Gründen, die sich aus Ihrer besonderen Situation ergeben, jederzeit gegen die beruhenden Entscheidung unterworfen zu werden, die Ihnen gegenüber rechtliche Wirkung entfaltet oder Sie in
Verarbeitung ähnlicher Weise erheblich beeinträchtigt.<br/>
Sie betreffender personenbezogener Daten, die aufgrund von Art. 6 Abs. 1 S. 1 e) oder f) DSGVO erfolgt, Eine automatisierte Entscheidungsfindung auf der Grundlage der erhobenen personenbezogenen Daten findet
Widerspruch nicht statt. </p>
einzulegen; dies gilt auch für ein auf diese Bestimmungen gestütztes Profiling. Wir verarbeiten die <h4>5.8 Recht auf Widerruf einer datenschutzrechtlichen Einwilligung</h4>
personenbezogenen <p>
Daten nicht mehr, es sei denn, wir können zwingende schutzwürdige Gründe für die Verarbeitung nachweisen, Sie haben das Recht, eine Einwilligung zur Verarbeitung personenbezogener Daten jederzeit zu
die Ihre widerrufen. </p>
Interessen, Rechte und Freiheiten überwiegen, oder die Verarbeitung dient der Geltendmachung, Ausübung oder
Verteidigung von Rechtsansprüchen.<br/>
Werden personenbezogene Daten von uns verarbeitet, um Direktwerbung zu betreiben, so haben Sie das Recht,
jederzeit
Widerspruch gegen die Verarbeitung Sie betreffender personenbezogener Daten zum Zwecke derartiger Werbung
einzulegen;
dies gilt auch für das Profiling, soweit es mit solcher Direktwerbung in Verbindung steht.<br/>
Sie haben das Recht, aus Gründen, die sich aus Ihrer besonderen Situation ergeben, gegen die Sie betreffende
Verarbeitung Sie betreffender personenbezogener Daten, die zu wissenschaftlichen oder historischen
Forschungszwecken
oder zu statistischen Zwecken gemäß Art. 89 Abs. 1 DSGVO erfolgt, Widerspruch einzulegen, es sei denn, die
Verarbeitung ist zur Erfüllung einer im öffentlichen Interesse liegenden Aufgabe erforderlich.<br/>
</p>
<h4>5.7 Automatisierte Entscheidungen einschließlich Profiling</h4>
<p>
Sie haben das Recht, nicht einer ausschließlich auf einer automatisierten Verarbeitung einschließlich
Profiling
beruhenden Entscheidung unterworfen zu werden, die Ihnen gegenüber rechtliche Wirkung entfaltet oder Sie in
ähnlicher
Weise erheblich beeinträchtigt.<br/>
Eine automatisierte Entscheidungsfindung auf der Grundlage der erhobenen personenbezogenen Daten findet
nicht statt.
</p>
<h4>5.8 Recht auf Widerruf einer datenschutzrechtlichen Einwilligung</h4>
<p>
Sie haben das Recht, eine Einwilligung zur Verarbeitung personenbezogener Daten jederzeit zu widerrufen.
</p>
<h4>5.9 Recht auf Beschwerde bei einer Aufsichtsbehörde</h4> <h4>5.9 Recht auf Beschwerde bei einer Aufsichtsbehörde</h4>
<p> <p>
Sie haben das Recht auf Beschwerde bei einer Aufsichtsbehörde, insbesondere in dem Mitgliedstaat Ihres Sie haben das Recht auf Beschwerde bei einer Aufsichtsbehörde, insbesondere in dem Mitgliedstaat Ihres
Aufenthaltsorts, Ihres Arbeitsplatzes oder des Orts des mutmaßlichen Verstoßes, wenn Sie der Ansicht sind, Aufenthaltsorts, Ihres Arbeitsplatzes oder des Orts des mutmaßlichen Verstoßes, wenn Sie der Ansicht sind,
dass die dass die Verarbeitung der Sie betreffenden personenbezogenen Daten rechtswidrig ist. </p>
Verarbeitung der Sie betreffenden personenbezogenen Daten rechtswidrig ist. <h3>6 Datensicherheit</h3>
</p> <p>
<h3>6 Datensicherheit</h3> Wir sind um die Sicherheit Ihrer Daten im Rahmen der geltenden Datenschutzgesetze und technischen
<p> Möglichkeiten maximal bemüht.<br/>
Wir sind um die Sicherheit Ihrer Daten im Rahmen der geltenden Datenschutzgesetze und technischen Ihre persönlichen Daten werden bei uns verschlüsselt übertragen. Dies gilt für Ihre Bestellungen und auch
Möglichkeiten für das Kundenlogin. Wir nutzen das Codierungssystem SSL (Secure Socket Layer), weisen jedoch darauf hin,
maximal bemüht.<br/> dass die Datenübertragung im Internet (z.B. bei der Kommunikation per E-Mail) Sicherheitslücken aufweisen
Ihre persönlichen Daten werden bei uns verschlüsselt übertragen. Dies gilt für Ihre Bestellungen und auch kann. Ein lückenloser Schutz der Daten vor dem Zugriff durch Dritte ist nicht möglich.<br/>
für das Zur Sicherung Ihrer Daten unterhalten wir technische und organisatorische Sicherungsmaßnahmen entsprechend
Kundenlogin. Wir nutzen das Codierungssystem SSL (Secure Socket Layer), weisen jedoch darauf hin, dass die Art. 32 DSGVO, die wir immer wieder dem Stand der Technik anpassen.<br/>
Datenübertragung im Internet (z.B. bei der Kommunikation per E-Mail) Sicherheitslücken aufweisen kann. Ein Wir gewährleisten außerdem nicht, dass unser Angebot zu bestimmten Zeiten zur Verfügung steht;
lückenloser Störungen,
Schutz der Daten vor dem Zugriff durch Dritte ist nicht möglich.<br/> Unterbrechungen oder Ausfälle können nicht ausgeschlossen werden. Die von uns verwendeten Server werden
Zur Sicherung Ihrer Daten unterhalten wir technische und organisatorische Sicherungsmaßnahmen entsprechend regelmäßig sorgfältig gesichert. </p>
Art. 32 <h3>7 Weitergabe von Daten an Dritte, keine Datenübertragung ins Nicht-EU-Ausland</h3>
DSGVO, die wir immer wieder dem Stand der Technik anpassen.<br/> <p>
Wir gewährleisten außerdem nicht, dass unser Angebot zu bestimmten Zeiten zur Verfügung steht; Störungen, Grundsätzlich verwenden wir Ihre personenbezogenen Daten nur innerhalb unseres Unternehmens.<br/>
Unterbrechungen oder Ausfälle können nicht ausgeschlossen werden. Die von uns verwendeten Server werden Wenn und soweit wir Dritte im Rahmen der Erfüllung von Verträgen einschalten (etwa Logistik-Dienstleister),
regelmäßig erhalten diese personenbezogene Daten nur in dem Umfang, in welchem die Übermittlung für die entsprechende
sorgfältig gesichert. Leistung erforderlich ist.<br/>
</p> Für den Fall, dass wir bestimmte Teile der Datenverarbeitung auslagern (Auftragsverarbeitung),
<h3>7 Weitergabe von Daten an Dritte, keine Datenübertragung ins Nicht-EU-Ausland</h3> verpflichten wir Auftragsverarbeiter vertraglich dazu, personenbezogene Daten nur im Einklang mit den
<p> Anforderungen der Datenschutzgesetze zu verwenden und den Schutz der Rechte der betroffenen Person zu
Grundsätzlich verwenden wir Ihre personenbezogenen Daten nur innerhalb unseres Unternehmens.<br/> gewährleisten.<br/>
Wenn und soweit wir Dritte im Rahmen der Erfüllung von Verträgen einschalten (etwa Logistik-Dienstleister), Eine Datenübertragung an Stellen oder Personen außerhalb der EU außerhalb des in dieser Erklärung in Ziffer
erhalten 4 genannten Falls findet nicht statt und ist nicht geplant. </p>
diese personenbezogene Daten nur in dem Umfang, in welchem die Übermittlung für die entsprechende Leistung <h3>8 Datenschutzbeauftragter</h3>
erforderlich ist.<br/> <p>
Für den Fall, dass wir bestimmte Teile der Datenverarbeitung auslagern (Auftragsverarbeitung), Sollten Sie noch Fragen oder Bedenken zum Datenschutz haben, so wenden Sie sich bitte an unseren
verpflichten wir Datenschutzbeauftragten:
Auftragsverarbeiter vertraglich dazu, personenbezogene Daten nur im Einklang mit den Anforderungen der </p>
Datenschutzgesetze zu verwenden und den Schutz der Rechte der betroffenen Person zu gewährleisten.<br/> <p>
Eine Datenübertragung an Stellen oder Personen außerhalb der EU außerhalb des in dieser Erklärung in Ziffer Jonas Seydel<br/>
4 August-Euler-Weg 3<br/>
genannten Falls findet nicht statt und ist nicht geplant. 76133 Karlsruhe<br/>
</p> Germany<br/>
<h3>8 Datenschutzbeauftragter</h3> jon@s-seydel.de </p>
<p> </Container>);
Sollten Sie noch Fragen oder Bedenken zum Datenschutz haben, so wenden Sie sich bitte an unseren
Datenschutzbeauftragten:
</p>
<p>
Jonas Seydel<br/>
August-Euler-Weg 3<br/>
76133 Karlsruhe<br/>
Germany<br/>
jon@s-seydel.de
</p>
</Container>
);
} }
export default class PrivacyPage extends React.Component { export default class PrivacyPage extends React.Component {
render() { render() {
return ( return (<div>
<div> <Head>
<Head> <title>Datenschutzerklärung: turnie.re</title>
<title>Datenschutzerklärung: turnie.re</title> </Head>
</Head> <TurniereNavigation/>
<TurniereNavigation/> <BigImage text="Datenschutzerklärung"/>
<BigImage text="Datenschutzerklärung"/> <Main/>
<Main/> <Footer/>
<Footer/> </div>);
</div>
);
} }
} }

View File

@ -16,33 +16,31 @@ class PrivateTournamentsPage extends React.Component {
render() { render() {
const {isSignedIn} = this.props; const {isSignedIn} = this.props;
return ( return (<UserRestrictor>
<UserRestrictor> <Option condition={isSignedIn}>
<Option condition={isSignedIn}> <div className="main generic-fullpage-bg">
<div className="main generic-fullpage-bg"> <Head>
<Head> <title>Private Turniere: turnie.re</title>
<title>Private Turniere: turnie.re</title> </Head>
</Head> <TurniereNavigation/>
<TurniereNavigation/> <PrivateTournamentsPageContent/>
<PrivateTournamentsPageContent/> <Footer/>
<Footer/> </div>
</Option>
<Option condition={true}>
<div className="main generic-fullpage-bg">
<Head>
<title>Anmeldung</title>
</Head>
<TurniereNavigation/>
<div>
<Login
hint="Sie müssen angemeldet sein, um diesen Inhalt anzuzeigen!"/>
</div> </div>
</Option> <Footer/>
<Option condition={true}> </div>
<div className="main generic-fullpage-bg"> </Option>
<Head> </UserRestrictor>);
<title>Anmeldung</title>
</Head>
<TurniereNavigation/>
<div>
<Login
hint="Sie müssen angemeldet sein, um diesen Inhalt anzuzeigen!"/>
</div>
<Footer/>
</div>
</Option>
</UserRestrictor>
);
} }
} }
@ -51,9 +49,7 @@ function mapStateToProperties(state) {
return {isSignedIn}; return {isSignedIn};
} }
const PrivateTournamentListPage = connect( const PrivateTournamentListPage = connect(mapStateToProperties)(PrivateTournamentsPage);
mapStateToProperties,
)(PrivateTournamentsPage);
export default PrivateTournamentListPage; export default PrivateTournamentListPage;
@ -70,13 +66,11 @@ function PrivateTournamentsPageContent() {
class PrivateTournamentsCard extends React.Component { class PrivateTournamentsCard extends React.Component {
render() { render() {
return ( return (<Card className="shadow">
<Card className="shadow"> <CardBody>
<CardBody> <h1 className="custom-font">Private Turniere</h1>
<h1 className="custom-font">Private Turniere</h1> <TournamentList type='private'/>
<TournamentList type='private'/> </CardBody>
</CardBody> </Card>);
</Card>
);
} }
} }

View File

@ -2,15 +2,7 @@ import Head from 'next/head';
import React from 'react'; import React from 'react';
import {connect} from 'react-redux'; import {connect} from 'react-redux';
import { import {
Button, Button, Card, CardBody, Container, Form, FormGroup, FormText, Input, Label
Card,
CardBody,
Container,
Form,
FormGroup,
FormText,
Input,
Label
} from 'reactstrap'; } from 'reactstrap';
import {TurniereNavigation} from '../js/components/Navigation'; import {TurniereNavigation} from '../js/components/Navigation';
@ -22,37 +14,33 @@ import '../static/everypage.css';
export default class RegisterPage extends React.Component { export default class RegisterPage extends React.Component {
render() { render() {
return ( return (<div className="main generic-fullpage-bg">
<div className="main generic-fullpage-bg"> <Head>
<Head> <title>Registrieren: turnie.re</title>
<title>Registrieren: turnie.re</title> </Head>
</Head> <TurniereNavigation/>
<TurniereNavigation/> <div>
<div> <Register/>
<Register/> <AccountRequirementMarketing/>
<AccountRequirementMarketing/>
</div>
<Footer/>
</div> </div>
); <Footer/>
</div>);
} }
} }
class Register extends React.Component { class Register extends React.Component {
render() { render() {
return ( return (<Container className="py-5">
<Container className="py-5"> <Card className="shadow">
<Card className="shadow"> <CardBody>
<CardBody> <h1 className="custom-font">Account anlegen</h1>
<h1 className="custom-font">Account anlegen</h1> <RegisterForm/>
<RegisterForm/> <div className="mt-3">
<div className="mt-3"> <a href="/login" className="mr-3">Ich habe bereits einen Account!</a>
<a href="/login" className="mr-3">Ich habe bereits einen Account!</a> </div>
</div> </CardBody>
</CardBody> </Card>
</Card> </Container>);
</Container>
);
} }
} }
@ -60,13 +48,9 @@ class RegisterErrorList extends React.Component {
render() { render() {
const {error, errorMessages} = this.props; const {error, errorMessages} = this.props;
if (error) { if (error) {
return ( return (<ul className="mt-3 error-box">
<ul className="mt-3 error-box"> {errorMessages.map((message, index) => <li key={index}>{message}</li>)}
{ errorMessages.map((message, index) => </ul>);
<li key={index}>{message}</li>
) }
</ul>
);
} else { } else {
return null; return null;
} }
@ -78,46 +62,43 @@ const mapStateToErrorMessages = state => {
return {errorMessages, error}; return {errorMessages, error};
}; };
const VisibleRegisterErrorList = connect( const VisibleRegisterErrorList = connect(mapStateToErrorMessages)(RegisterErrorList);
mapStateToErrorMessages
)(RegisterErrorList);
class RegisterForm extends React.Component { class RegisterForm extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { this.state = {
username: '', username: '', email: '', password: ''
email: '',
password: ''
}; };
} }
render() { render() {
return ( return (<Form>
<Form> <FormGroup>
<FormGroup> <Label for="username">Benutzername</Label>
<Label for="username">Benutzername</Label> <Input name="username" value={this.state.username} onChange={this.handleUsernameInput.bind(this)}/>
<Input name="username" value={this.state.username} onChange={ this.handleUsernameInput.bind(this) } /> <FormText>Wenn du anderen dein Turnier zeigst, können sie deinen Benutzernamen sehen.</FormText>
<FormText>Wenn du anderen dein Turnier zeigst, können sie deinen Benutzernamen sehen.</FormText> </FormGroup>
</FormGroup> <FormGroup>
<FormGroup> <Label for="email">E-Mail-Adresse</Label>
<Label for="email">E-Mail-Adresse</Label> <Input type="email" name="email" value={this.state.email}
<Input type="email" name="email" value={this.state.email} onChange={ this.handleEmailInput.bind(this) } /> onChange={this.handleEmailInput.bind(this)}/>
<FormText>Deine E-Mail-Adresse kann nur von dir gesehen werden.</FormText> <FormText>Deine E-Mail-Adresse kann nur von dir gesehen werden.</FormText>
</FormGroup> </FormGroup>
<FormGroup> <FormGroup>
<Label for="password">Passwort</Label> <Label for="password">Passwort</Label>
<Input type="password" name="password" value={this.state.password} onChange={ this.handlePasswordInput.bind(this) } /> <Input type="password" name="password" value={this.state.password}
<FormText>Dein Passwort muss mindestens 12 Zeichen lang sein. Alle Zeichen sind erlaubt.</FormText> onChange={this.handlePasswordInput.bind(this)}/>
</FormGroup> <FormText>Dein Passwort muss mindestens 12 Zeichen lang sein. Alle Zeichen sind erlaubt.</FormText>
<FormText className="mb-2 mt-4"> </FormGroup>
<FormText className="mb-2 mt-4">
Du akzeptierst die <a href="/privacy">Datenschutzbestimmungen</a>, wenn du auf Registrieren klickst. Du akzeptierst die <a href="/privacy">Datenschutzbestimmungen</a>, wenn du auf Registrieren klickst.
</FormText> </FormText>
<Button onClick={ register.bind(this, this.state.username, this.state.email, this.state.password) } color="success" size="lg" className="w-100 shadow-sm">Registrieren</Button> <Button onClick={register.bind(this, this.state.username, this.state.email, this.state.password)}
<VisibleRegisterErrorList/> color="success" size="lg" className="w-100 shadow-sm">Registrieren</Button>
</Form> <VisibleRegisterErrorList/>
); </Form>);
} }
handlePasswordInput(input) { handlePasswordInput(input) {
@ -134,14 +115,12 @@ class RegisterForm extends React.Component {
} }
function AccountRequirementMarketing() { function AccountRequirementMarketing() {
return ( return (<Container>
<Container> <Card id="account-requirement">
<Card id="account-requirement"> <CardBody>
<CardBody> <h3 className="custom-font">Warum ein Account nötig ist</h3>
<h3 className="custom-font">Warum ein Account nötig ist</h3> <p>Du benötigst deinen Account, damit nur du dein Turnier bearbeiten kannst.</p>
<p>Du benötigst deinen Account, damit nur du dein Turnier bearbeiten kannst.</p> </CardBody>
</CardBody> </Card>
</Card> </Container>);
</Container>
);
} }

View File

@ -3,11 +3,7 @@ import React from 'react';
import {connect} from 'react-redux'; import {connect} from 'react-redux';
import {notify} from 'react-notify-toast'; import {notify} from 'react-notify-toast';
import { import {
Container, Container, Button, Card, CardBody, Table
Button,
Card,
CardBody,
Table
} from 'reactstrap'; } from 'reactstrap';
import {requestTournament} from '../js/api'; import {requestTournament} from '../js/api';
@ -53,43 +49,41 @@ class EditTournamentPage extends React.Component {
const {validCode} = this.state; const {validCode} = this.state;
const {tournamentname, ownerUsername, isSignedIn, username} = this.props; const {tournamentname, ownerUsername, isSignedIn, username} = this.props;
return ( return (<UserRestrictor>
<UserRestrictor> <Option condition={validCode && isSignedIn && ownerUsername === username}>
<Option condition={ validCode && isSignedIn && ownerUsername === username }> <div className='pb-5'>
<div className='pb-5'> <Head>
<Head> <title>Turnie.re - Turnier bearbeiten</title>
<title>Turnie.re - Turnier bearbeiten</title> </Head>
</Head> <TurniereNavigation/>
<TurniereNavigation/>
<BigImage text={ tournamentname }/> <BigImage text={tournamentname}/>
<EditTournamentContent ref={edittournamentcontent => { <EditTournamentContent ref={edittournamentcontent => {
this._edittournamentcontent = edittournamentcontent; this._edittournamentcontent = edittournamentcontent;
}}/> }}/>
<Footer/> <Footer/>
</div> </div>
</Option> </Option>
<Option condition={ validCode && isSignedIn }> <Option condition={validCode && isSignedIn}>
<ErrorPageComponent statusCode={ 403 }/> <ErrorPageComponent statusCode={403}/>
</Option> </Option>
<Option condition={ !isSignedIn }> <Option condition={!isSignedIn}>
<div className="main generic-fullpage-bg"> <div className="main generic-fullpage-bg">
<Head> <Head>
<title>Turnie.re - Turnier bearbeiten</title> <title>Turnie.re - Turnier bearbeiten</title>
</Head> </Head>
<TurniereNavigation/> <TurniereNavigation/>
<div> <div>
<Login hint="Sie müssen angemeldet sein, um ein Turnier zu bearbeiten."/> <Login hint="Sie müssen angemeldet sein, um ein Turnier zu bearbeiten."/>
</div>
<Footer/>
</div> </div>
</Option> <Footer/>
<Option condition={true}> </div>
<ErrorPageComponent statusCode={ 404 }/> </Option>
</Option> <Option condition={true}>
</UserRestrictor> <ErrorPageComponent statusCode={404}/>
); </Option>
</UserRestrictor>);
} }
} }
@ -99,23 +93,19 @@ function mapStateToTournamentInfo(state) {
return {tournamentname, ownerUsername, isSignedIn, username}; return {tournamentname, ownerUsername, isSignedIn, username};
} }
export default connect( export default connect(mapStateToTournamentInfo)(EditTournamentPage);
mapStateToTournamentInfo
)(EditTournamentPage);
class EditTournamentContent extends React.Component { class EditTournamentContent extends React.Component {
render() { render() {
return ( return (<div className='mb-5'>
<div className='mb-5'> <ReturnToTournamentButton/>
<ReturnToTournamentButton/> <EditTournamentPropertiesField ref={field => {
<EditTournamentPropertiesField ref={field => { this._edittournamentpropertiesfield = field;
this._edittournamentpropertiesfield = field; }}/>
}}/> <EditTeamField ref={field => {
<EditTeamField ref={field => { this._editteamfield = field;
this._editteamfield = field; }}/>
}}/> </div>);
</div>
);
} }
notifyOfContentUpdate() { notifyOfContentUpdate() {
@ -125,25 +115,21 @@ class EditTournamentContent extends React.Component {
} }
function ReturnToTournamentButton() { function ReturnToTournamentButton() {
return ( return (<Container className="px-0">
<Container className="px-0"> <Button color="secondary" className="mb-5 w-100" href="./">Zurück zum Turnier</Button>
<Button color="secondary" className="mb-5 w-100" href="./">Zurück zum Turnier</Button> </Container>);
</Container>
);
} }
class EditTournamentPropertiesField extends React.Component { class EditTournamentPropertiesField extends React.Component {
render() { render() {
return ( return (<Card className="container">
<Card className="container"> <CardBody>
<CardBody> <h2>Turnier-Eigenschaften ändern</h2>
<h2>Turnier-Eigenschaften ändern</h2> <VisibleEditTournamentForm ref={form => {
<VisibleEditTournamentForm ref={form => { this._visibleedittournamentform = form;
this._visibleedittournamentform = form; }}/>
}}/> </CardBody>
</CardBody> </Card>);
</Card>
);
} }
notifyOfContentUpdate() { notifyOfContentUpdate() {
@ -156,45 +142,45 @@ class EditTournamentForm extends React.Component {
super(props); super(props);
this.state = { this.state = {
name: '', name: '', description: '', isPublic: false
description: '',
isPublic: false
}; };
} }
render() { render() {
const {name, description, isPublic} = this.state; const {name, description, isPublic} = this.state;
return ( return (<div>
<div> <div className="form-group">
<div className="form-group"> <label htmlFor="name">Turnier-Name</label>
<label htmlFor="name">Turnier-Name</label> <input className="form-control" type="text" name="name" id="edittournament-textfield-name"
<input className="form-control" type="text" name="name" id="edittournament-textfield-name" value={ name } placeholder={ name } onChange={ this.handleNameInput.bind(this) } /> value={name} placeholder={name} onChange={this.handleNameInput.bind(this)}/>
</div> </div>
<div className="form-group"> <div className="form-group">
<label htmlFor="name">Turnier-Beschreibung</label> <label htmlFor="name">Turnier-Beschreibung</label>
<input className="form-control" type="text" name="name" id="edittournament-textfield-description" value={ description } placeholder={ description } onChange={ this.handleDescriptionInput.bind(this) } /> <input className="form-control" type="text" name="name" id="edittournament-textfield-description"
</div> value={description} placeholder={description}
<div className="form-group custom-control custom-checkbox"> onChange={this.handleDescriptionInput.bind(this)}/>
<input className="custom-control-input" type="checkbox" name="isPublic" id="edittournament-checkbox-isPublic" value={ isPublic } onChange={ this.handlePublicInput.bind(this) } /> </div>
<label htmlFor="isPublic" className="custom-control-label">Das Turnier öffentlich anzeigen</label> <div className="form-group custom-control custom-checkbox">
</div> <input className="custom-control-input" type="checkbox" name="isPublic"
<div className="form-group"> id="edittournament-checkbox-isPublic" value={isPublic}
<div className="input-group"> onChange={this.handlePublicInput.bind(this)}/>
<Button color="success" className="px-5" id="edittournament-button" onClick={ this.handleClick.bind(this) }>Ändern</Button> <label htmlFor="isPublic" className="custom-control-label">Das Turnier öffentlich anzeigen</label>
</div> </div>
<div className="form-group">
<div className="input-group">
<Button color="success" className="px-5" id="edittournament-button"
onClick={this.handleClick.bind(this)}>Ändern</Button>
</div> </div>
</div> </div>
); </div>);
} }
notifyOfContentUpdate() { notifyOfContentUpdate() {
const {name, description, isPublic} = this.props; const {name, description, isPublic} = this.props;
this.setState({ this.setState({
name: name? name : '', name: name ? name : '', description: description ? description : '', isPublic: isPublic
description: description? description : '',
isPublic: isPublic
}); });
} }
@ -220,23 +206,19 @@ function mapStateToTournamentFormProps(state) {
return {name, description, isPublic}; return {name, description, isPublic};
} }
const VisibleEditTournamentForm = connect( const VisibleEditTournamentForm = connect(mapStateToTournamentFormProps, null, null,
mapStateToTournamentFormProps, {withRef: true})(EditTournamentForm);
null, null, {withRef: true}
)(EditTournamentForm);
class EditTeamField extends React.Component { class EditTeamField extends React.Component {
render() { render() {
return ( return (<Card className="container my-4">
<Card className="container my-4"> <CardBody>
<CardBody> <h2>Team-Namen ändern</h2>
<h2>Team-Namen ändern</h2> <VisibleEditTeamNamesForm ref={form => {
<VisibleEditTeamNamesForm ref={form => { this._visibleeditteamnamesform = form;
this._visibleeditteamnamesform = form; }}/>
}}/> </CardBody>
</CardBody> </Card>);
</Card>
);
} }
notifyOfContentUpdate() { notifyOfContentUpdate() {
@ -256,22 +238,21 @@ class EditTeamNamesForm extends React.Component {
render() { render() {
const {teams} = this.state; const {teams} = this.state;
return ( return (<div>
<div> <Table className="table-striped mt-3">
<Table className="table-striped mt-3"> <tbody>
<tbody> {teams.map((team, index) => <tr key={index}>
{ <td><Button outline size="sm" className="changeTeamnameButton"
teams.map((team, index) => id={'editteam-button-team_' + team.id}
<tr key={index}> onClick={this.handleClick.bind(this, index)}>Ändern</Button></td>
<td><Button outline size="sm" className="changeTeamnameButton" id={ 'editteam-button-team_' + team.id } onClick={ this.handleClick.bind(this, index) }>Ändern</Button></td> <td className="w-100"><input className="form-control" type="text"
<td className="w-100"><input className="form-control" type="text" id={ 'editteam-textfield-team_' + team.id } value={ team.name } placeholder={ team.name } onChange={ this.handleNameInput.bind(this, index) } /></td> id={'editteam-textfield-team_' + team.id} value={team.name}
</tr> placeholder={team.name}
) onChange={this.handleNameInput.bind(this, index)}/></td>
} </tr>)}
</tbody> </tbody>
</Table> </Table>
</div> </div>);
);
} }
notifyOfContentUpdate() { notifyOfContentUpdate() {
@ -306,8 +287,5 @@ function mapStateToTeamFormProps(state) {
return {teams}; return {teams};
} }
const VisibleEditTeamNamesForm = connect( const VisibleEditTeamNamesForm = connect(mapStateToTeamFormProps, null, null, {withRef: true})(EditTeamNamesForm);
mapStateToTeamFormProps,
null, null, {withRef: true}
)(EditTeamNamesForm);

View File

@ -7,15 +7,13 @@ class FullscreenTournamentPage extends React.Component {
} }
render() { render() {
return ( return (<div>
<div> <Head>
<Head> <title>Turnie.re - Turnieranzeige (Vollbild)</title>
<title>Turnie.re - Turnieranzeige (Vollbild)</title> </Head>
</Head> <p>Turnieranzeige (Vollbild)</p>
<p>Turnieranzeige (Vollbild)</p> <p>Code: {this.props.query.code}</p>
<p>Code: {this.props.query.code}</p> </div>);
</div>
);
} }
} }

View File

@ -25,8 +25,7 @@ import {Footer} from '../js/components/Footer';
import {TurniereNavigation} from '../js/components/Navigation'; import {TurniereNavigation} from '../js/components/Navigation';
import {BigImage} from '../js/components/BigImage'; import {BigImage} from '../js/components/BigImage';
import { import {
getRequest, getRequest, getState
getState
} from '../js/api'; } from '../js/api';
import 'bootstrap/dist/css/bootstrap.min.css'; import 'bootstrap/dist/css/bootstrap.min.css';
@ -40,25 +39,24 @@ class PrivateTournamentPage extends React.Component {
const {isSignedIn, username} = this.props; const {isSignedIn, username} = this.props;
// TODO: Change href-prop of the anchor tag to contain the tournament code // TODO: Change href-prop of the anchor tag to contain the tournament code
return ( return (<div className='pb-5'>
<div className='pb-5'> <Container>
<Container> <EditButton id={id} ownerName={ownerUsername} isSignedIn={isSignedIn} username={username}/>
<EditButton id={id} ownerName={ownerUsername} isSignedIn={isSignedIn} username={username}/> <p>{description}</p>
<p>{description}</p> <ListGroup>
<ListGroup> <ListGroupItem>
<ListGroupItem> {isPublic ? 'Das Turnier ist öffentlich.' : 'Das Turnier ist privat.'}
{isPublic ? 'Das Turnier ist öffentlich.' : 'Das Turnier ist privat.'} </ListGroupItem>
</ListGroupItem> <ListGroupItem>Turnier-Code: <b>{code}</b></ListGroupItem>
<ListGroupItem>Turnier-Code: <b>{code}</b></ListGroupItem> <ListGroupItem>von <b>{ownerUsername}</b></ListGroupItem>
<ListGroupItem>von <b>{ownerUsername}</b></ListGroupItem> </ListGroup>
</ListGroup> </Container>
</Container> <div className='stages pt-5'>
<div className='stages pt-5'> {playoffStages.map(stage => <Stage isSignedIn={isSignedIn} isOwner={username === ownerUsername}
{playoffStages.map(stage => level={getLevelName(stage.level)} matches={stage.matches}
<Stage isSignedIn={isSignedIn} isOwner={username === ownerUsername} level={getLevelName(stage.level)} matches={stage.matches} key={stage.level}/>)} key={stage.level}/>)}
</div>
</div> </div>
); </div>);
} }
} }
@ -67,17 +65,13 @@ function mapStateToTournamentPageProperties(state) {
return {isSignedIn, username}; return {isSignedIn, username};
} }
const TournamentPage = connect( const TournamentPage = connect(mapStateToTournamentPageProperties)(PrivateTournamentPage);
mapStateToTournamentPageProperties
)(PrivateTournamentPage);
function EditButton(props) { function EditButton(props) {
const {id, ownerName, isSignedIn, username} = props; const {id, ownerName, isSignedIn, username} = props;
if (isSignedIn && ownerName === username) { if (isSignedIn && ownerName === username) {
return ( return (<a href={'/t/' + id + '/edit'} className='btn btn-outline-secondary'>Turnier bearbeiten</a>);
<a href={'/t/' + id + '/edit'} className='btn btn-outline-secondary'>Turnier bearbeiten</a>
);
} else { } else {
return null; return null;
} }
@ -100,8 +94,8 @@ function Stage(props) {
<h1 className='custom-font'>{props.level}</h1> <h1 className='custom-font'>{props.level}</h1>
<Row> <Row>
{props.matches.map((match => ( {props.matches.map((match => (
<Col className='minw-25' key={match.id}><Match match={match} isSignedIn={isSignedIn} isOwner={isOwner}/></Col> <Col className='minw-25' key={match.id}><Match match={match} isSignedIn={isSignedIn}
)))} isOwner={isOwner}/></Col>)))}
</Row> </Row>
</Container> </Container>
</div>); </div>);
@ -125,7 +119,9 @@ class Match extends React.Component {
} }
render() { render() {
let cardClass; let smallMessage; let borderClass; let cardClass;
let smallMessage;
let borderClass;
// possible states: single_team not_ready not_started in_progress team1_won team2_won undecided // possible states: single_team not_ready not_started in_progress team1_won team2_won undecided
switch (this.props.match.state) { switch (this.props.match.state) {
case 'in_progress': case 'in_progress':
@ -160,17 +156,15 @@ class Match extends React.Component {
smallMessage = 'Spiel beendet, unentschieden'; smallMessage = 'Spiel beendet, unentschieden';
break; break;
} }
return ( return (<div className='mb-3'>
<div className='mb-3'> <Card className='shadow-sm match' onClick={this.toggleModal}>
<Card className='shadow-sm match' onClick={this.toggleModal}> <CardBody className={borderClass + ' border py-2 ' + cardClass}>
<CardBody className={borderClass + ' border py-2 ' + cardClass}> <MatchTable match={this.props.match} borderColor={borderClass}/>
<MatchTable match={this.props.match} borderColor={borderClass}/> </CardBody>
</CardBody> </Card>
</Card> <small className='text-muted'>{smallMessage}</small>
<small className='text-muted'>{smallMessage}</small> <MatchModal title='Match' isOpen={this.state.modal} toggle={this.toggleModal} match={this.props.match}/>
<MatchModal title='Match' isOpen={this.state.modal} toggle={this.toggleModal} match={this.props.match}/> </div>);
</div>
);
} }
} }
@ -203,23 +197,22 @@ function MatchModal(props) {
title = 'Spiel beendet'; title = 'Spiel beendet';
break; break;
} }
return ( return (<Modal isOpen={props.isOpen} toggle={props.toggle}>
<Modal isOpen={props.isOpen} toggle={props.toggle}> <ModalHeader toggle={props.toggle}>{title}</ModalHeader>
<ModalHeader toggle={props.toggle}>{title}</ModalHeader> <ModalBody>
<ModalBody> {props.match.state === 'in_progress' ? <EditableMatchTable match={props.match}/> :
{props.match.state === 'in_progress' ? <EditableMatchTable match={props.match}/> : <MatchTable match={props.match}/>}
<MatchTable match={props.match}/>} </ModalBody>
</ModalBody> <ModalFooter>
<ModalFooter> {actionButton}
{actionButton} <Button color='secondary' onClick={props.toggle}>Abbrechen</Button>
<Button color='secondary' onClick={props.toggle}>Abbrechen</Button> </ModalFooter>
</ModalFooter> </Modal>);
</Modal>
);
} }
function MatchTable(props) { function MatchTable(props) {
let team1Class; let team2Class; let team1Class;
let team2Class;
// possible states: single_team not_ready not_started in_progress team1_won team2_won undecided // possible states: single_team not_ready not_started in_progress team1_won team2_won undecided
switch (props.match.state) { switch (props.match.state) {
case 'in_progress': case 'in_progress':
@ -243,55 +236,49 @@ function MatchTable(props) {
break; break;
} }
if (props.match.state === 'single_team') { if (props.match.state === 'single_team') {
return ( return (<Table className='mb-0'>
<Table className='mb-0'> <tbody>
<tbody> <tr>
<tr> <td className={'border-top-0 ' + team1Class}>{props.match.team1}</td>
<td className={'border-top-0 ' + team1Class}>{props.match.team1}</td> </tr>
</tr> <tr>
<tr> <td className={props.borderColor + ' ' + team2Class}>kein Gegner</td>
<td className={props.borderColor + ' ' + team2Class}>kein Gegner</td> </tr>
</tr> </tbody>
</tbody> </Table>);
</Table>
);
} else { } else {
return ( return (<Table className='mb-0'>
<Table className='mb-0'> <tbody>
<tbody> <tr>
<tr> <th className='stage border-top-0'>{props.match.scoreTeam1}</th>
<th className='stage border-top-0'>{props.match.scoreTeam1}</th> <td className={'border-top-0 ' + team1Class}>{props.match.team1}</td>
<td className={'border-top-0 ' + team1Class}>{props.match.team1}</td> </tr>
</tr> <tr>
<tr> <th className={'stage ' + props.borderColor}>{props.match.scoreTeam2}</th>
<th className={'stage ' + props.borderColor}>{props.match.scoreTeam2}</th> <td className={props.borderColor + ' ' + team2Class}>{props.match.team2}</td>
<td className={props.borderColor + ' ' + team2Class}>{props.match.team2}</td> </tr>
</tr> </tbody>
</tbody> </Table>);
</Table>
);
} }
} }
function EditableMatchTable(props) { function EditableMatchTable(props) {
return ( return (<Table className='mb-0'>
<Table className='mb-0'> <tbody>
<tbody> <tr>
<tr> <td className='scoreInput border-top-0'>
<td className='scoreInput border-top-0'> <ScoreInput score={props.match.scoreTeam1}/>
<ScoreInput score={props.match.scoreTeam1}/> </td>
</td> <td className='align-middle border-top-0'>{props.match.team1}</td>
<td className='align-middle border-top-0'>{props.match.team1}</td> </tr>
</tr> <tr>
<tr> <td className='scoreInput'>
<td className='scoreInput'> <ScoreInput score={props.match.scoreTeam2}/>
<ScoreInput score={props.match.scoreTeam2}/> </td>
</td> <td className='align-middle'>{props.match.team2}</td>
<td className='align-middle'>{props.match.team2}</td> </tr>
</tr> </tbody>
</tbody> </Table>);
</Table>
);
} }
class ScoreInput extends React.Component { class ScoreInput extends React.Component {
@ -317,9 +304,12 @@ class ScoreInput extends React.Component {
render() { render() {
return (<InputGroup> return (<InputGroup>
<InputGroupAddon addonType="prepend"><Button onClick={this.decreaseScore} color='danger' outline={true}>-1</Button></InputGroupAddon> <InputGroupAddon addonType="prepend"><Button onClick={this.decreaseScore} color='danger'
<Input className='font-weight-bold' value={this.state.score} onChange={this.updateScore} type='number' step='1' placeholder='0'/> outline={true}>-1</Button></InputGroupAddon>
<InputGroupAddon addonType="append"><Button onClick={this.increaseScore} color='success'>+1</Button></InputGroupAddon> <Input className='font-weight-bold' value={this.state.score} onChange={this.updateScore} type='number'
step='1' placeholder='0'/>
<InputGroupAddon addonType="append"><Button onClick={this.increaseScore}
color='success'>+1</Button></InputGroupAddon>
</InputGroup>); </InputGroup>);
} }
} }
@ -334,9 +324,7 @@ function convertTournament(apiTournament) {
} else { } else {
// playoff stage // playoff stage
playoffStages.push({ playoffStages.push({
id: stage.id, id: stage.id, level: stage.level, matches: stage.matches.map(match => convertMatch(match))
level: stage.level,
matches: stage.matches.map(match => convertMatch(match))
}); });
} }
} }
@ -363,8 +351,7 @@ function convertGroup(apiGroup) {
function convertMatch(apiMatch) { function convertMatch(apiMatch) {
const result = { const result = {
id: apiMatch.id, id: apiMatch.id, state: apiMatch.state
state: apiMatch.state
}; };
if (apiMatch.match_scores.length === 2) { if (apiMatch.match_scores.length === 2) {
@ -423,17 +410,15 @@ class Main extends React.Component {
const {status, tournament} = this.state; const {status, tournament} = this.state;
if (status === 200) { if (status === 200) {
return ( return (<div>
<div> <Head>
<Head> <title>{tournamentName}: turnie.re</title>
<title>{tournamentName}: turnie.re</title> </Head>
</Head> <TurniereNavigation/>
<TurniereNavigation/> <BigImage text={tournamentName}/>
<BigImage text={tournamentName}/> <TournamentPage tournament={tournament}/>
<TournamentPage tournament={tournament}/> <Footer/>
<Footer/> </div>);
</div>
);
} else { } else {
return <ErrorPageComponent code={status}/>; return <ErrorPageComponent code={status}/>;
} }