Skip to content
Snippets Groups Projects
Commit 1d4582c3 authored by borzechof99's avatar borzechof99 :whale2:
Browse files

Merge branch '9-fragenubersicht' into 'master'

Implemented Question List and Edit, Refactoring and Documenting

Closes #9

See merge request swp-unisport/team-warumkeinrust/admin-frontend!4
parents 90ad01ec 7c996aa8
No related branches found
No related tags found
No related merge requests found
......@@ -3,8 +3,13 @@ import * as React from 'react';
import { Admin, Resource } from 'react-admin';
import dataProviderMapper from './dataProviderMapper';
import { sportList, sportEdit, sportCreate } from './sportList';
import { incompleteEdit, incompleteList } from './incompleteList';
import { SportList, SportEdit, SportCreate } from './sportList';
import { IncompleteList, IncompleteEdit } from './incompleteList';
import { QuestionList, QuestionEdit, QuestionCreate } from './questionList';
import QuestionAnswerIcon from '@material-ui/icons/QuestionAnswer';
import SportsFootballIcon from '@material-ui/icons/SportsFootball';
import PlaylistAddCheckIcon from '@material-ui/icons/PlaylistAddCheck';
const App = () => (
<Admin
......@@ -14,17 +19,28 @@ const App = () => (
<Resource
name='sport' // name of the API endpoint
icon={SportsFootballIcon}
options={{ label: 'Sport Management' }} // if we do not rename the resource, the API name will be used
list={sportList}
edit={sportEdit}
create={sportCreate}
list={SportList}
edit={SportEdit}
create={SportCreate}
/>
<Resource
name='sport-incomplete'
icon={PlaylistAddCheckIcon}
options={{ label: 'Incomplete Sports' }}
list={incompleteList}
edit={incompleteEdit}
list={IncompleteList}
edit={IncompleteEdit}
/>
<Resource
name='question'
icon={QuestionAnswerIcon}
options={{ label: 'Question Management' }}
list={QuestionList}
edit={QuestionEdit}
create={QuestionCreate}
/>
</Admin>
);
......
......@@ -17,7 +17,7 @@ import {
const dataProviders = [
{
dataProvider: drfProvider('http://localhost:8000/api/admin'),
resources: ['sport'],
resources: ['sport', 'question'],
},
{
dataProvider: sportIncompleteProvider('http://localhost:8000/api/admin'),
......
......@@ -12,11 +12,48 @@ import {
Toolbar,
FormDataConsumer,
ReferenceField,
ChipField
ChipField,
useNotify,
useRefresh
} from 'react-admin';
import { criterionEditValidator } from './criterionEditValidator.js';
import Typography from '@material-ui/core/Typography'
import Card from '@material-ui/core/Card'
import CardContent from '@material-ui/core/CardContent'
const AsideIncompleteList = () => (
<div style={{ width: 400, margin: '1em' }}>
<Card>
<CardContent>
<Typography variant="h4" align="center">Tipps&Tricks</Typography>
<br />
<ul>
<li>Klicke auf die ID von dem Sport, um den gesamten Sport zu bearbeiten.</li>
<br />
<li>Klicke auf eine Reihe, um diese aufzuklappen. Hier können die bisher noch nicht angegebenen Kriterienwertungen ausfüllt werden.</li>
<br />
<li><b>Die Zahl -1 bedeutet, dass das Kriterium nicht bewertet worden ist.</b></li>
<br />
<li>Wenn ein Sport vollständig bewertet ist, verschwindet er von dieser Liste.</li>
<br />
<li>Nach dem Bearbeiten: Speichern nicht vergessen!</li>
</ul>
</CardContent>
</Card>
</div>
);
// Eliminates the delete function while editing the incomplete list
const IncompleteEditToolbar = props => (
<Toolbar {...props} >
......@@ -25,10 +62,10 @@ const IncompleteEditToolbar = props => (
);
export const incompleteList = props => (
<List {...props}>
export const IncompleteList = props => (
<List {...props} aside={<AsideIncompleteList />}>
{/* rowClick expand means that no edit page is opened, but instead shown below the data row itself without reloading */}
<Datagrid rowClick="expand" expand={incompleteEdit} >
<Datagrid rowClick="expand" expand={IncompleteEdit} >
{/* Reference Field fetches every Sport object if a reference field to it exists.
This means that n GETs are made for one load of the incomplete-list.
......@@ -44,12 +81,31 @@ export const incompleteList = props => (
);
export const incompleteEdit = props => (
<Edit {...props}>
export const IncompleteEdit = props => {
const notify = useNotify();
const refresh = useRefresh();
// Redefining onSuccess for following behaviour:
// Entering criteria values, but some are left as -1? => Page stays on focus with the edit
// Entering all valid criteria values? => Pages refreshes and the row vanishes
const onSuccess = () => {
notify((`Kriterien eingetragen`));
refresh();
}
// mutationMode pessimistic deactivates the optimistic rendering
// Now the request will be sent first and rendered after getting the return code
return (
<Edit {...props} mutationMode="pessimistic" onSuccess={onSuccess}>
<SimpleForm toolbar={<IncompleteEditToolbar />}>
<Typography variant="h5" fullWidth>Fehlende Kriterien ausfüllen</Typography>
{/* Documentation for formatting https://marmelab.com/react-admin/CreateEdit.html#custom-row-container */}
<TextField source="id" />
<TextField source="name" />
<ArrayInput source="criteria">
<ArrayInput source="criteria" label="">
<SimpleFormIterator disableAdd disableRemove>
{/* Documentation is wrong, look here! https://github.com/marmelab/react-admin/issues/2500
......@@ -60,7 +116,7 @@ export const incompleteEdit = props => (
getSource();
return (
<TextField
source={"name"} record={scopedFormData}
source={"name"} record={scopedFormData} label="Kriterienname"
/>
);
}}
......@@ -77,3 +133,4 @@ export const incompleteEdit = props => (
</SimpleForm>
</Edit >
);
};
import * as React from 'react';
import {
List,
Datagrid,
TextField,
Edit,
SimpleForm,
TextInput,
Create
} from 'react-admin';
import Typography from '@material-ui/core/Typography'
import Card from '@material-ui/core/Card'
import CardContent from '@material-ui/core/CardContent'
const AsideQuestionList = () => (
<div style={{ width: 400, margin: '1em' }}>
<Card>
<CardContent>
<Typography variant="h4" align="center">Tipps&Tricks</Typography>
<br />
<ul>
<li>Klicke auf eine Datenreihe, um sie zu bearbeiten.</li>
<br />
<li>Fragen müssen eine deutsche Übersetzung und können eine englische Übersetzung haben.</li>
<br />
<li>Kriterien sind einzigartig. Das heißt, dass ein Kriterium nicht doppelt vergeben werden kann!</li>
</ul>
</CardContent>
</Card>
</div>
);
const AsideQuestionEdit = () => (
<div style={{ width: 400, margin: '1em' }}>
<Card>
<CardContent>
<Typography variant="h4" align="center">Tipps&Tricks</Typography>
<br />
<ul>
<li>Pflichtangaben sind:
<ul>
<li>Deutscher Fragetext</li>
<li>Name des Kriteriums</li>
</ul>
</li>
<br />
<li>Wenn ein Kriterium umbenannt wird, wird es automatisch bei allen Sportarten aktualisiert.</li>
<br />
<li>Kriterien sind einzigartig. Das heißt, dass ein Kriterium nicht doppelt vergeben werden kann!</li>
</ul>
</CardContent>
</Card>
</div>
);
const AsideQuestionCreate = () => (
<div style={{ width: 400, margin: '1em' }}>
<Card>
<CardContent>
<Typography variant="h4" align="center">Tipps&Tricks</Typography>
<br />
<ul>
<li>Pflichtangaben sind:
<ul>
<li>Deutscher Fragetext</li>
<li>Name des Kriteriums</li>
</ul>
</li>
<br />
<li>Kriterien sind einzigartig. Das heißt, dass ein Kriterium nicht doppelt vergeben werden kann!
Hier muss also ein neuer Kriterienname angegeben werden.</li>
</ul>
</CardContent>
</Card>
</div>
);
export const QuestionList = props => (
<List {...props} aside={<AsideQuestionList />}>
<Datagrid rowClick="edit">
<TextField source="text_de" label="Deutscher Fragetext" />
<TextField source="text_en" label="Englischer Fragetext" />
<TextField source="criterion" label="Name des Kriteriums" />
</Datagrid>
</List>
);
// mutationMode pessimistic deactivates the optimistic rendering
// Now the request will be sent first and rendered after getting the return code
export const QuestionEdit = props => (
<Edit {...props} mutationMode="pessimistic" aside={<AsideQuestionEdit />}>
<SimpleForm>
<Typography variant="h5" fullWidth >Frage bearbeiten</Typography>
<TextInput source="text_de" label="Deutscher Fragetext" fullWidth required />
<TextInput source="text_en" label="Englischer Fragetext" fullWidth />
<TextInput source="criterion" label="Name des Kriteriums" required />
</SimpleForm>
</Edit>
);
export const QuestionCreate = props => (
<Create {...props} aside={<AsideQuestionCreate />}>
<SimpleForm redirect="list">
<Typography variant="h5" fullWidth >Frage erstellen</Typography>
<TextInput source="text_de" label="Deutscher Fragetext" fullWidth required />
<TextInput source="text_en" label="Englischer Fragetext" fullWidth />
<TextInput source="criterion" label="Name des Kriteriums" required />
</SimpleForm>
</Create>
);
\ No newline at end of file
......@@ -13,35 +13,127 @@ import {
SimpleFormIterator,
NumberInput,
Create,
FormDataConsumer
} from 'react-admin';
import Typography from '@material-ui/core/Typography'
import Card from '@material-ui/core/Card'
import CardContent from '@material-ui/core/CardContent'
import { criterionEditValidator } from './criterionEditValidator.js';
const AsideSportList = () => (
<div style={{ width: 400, margin: '1em' }}>
<Card>
<CardContent>
<Typography variant="h4" align="center">Tipps&Tricks</Typography>
<br />
<ul>
<li>Klicke auf eine Datenreihe, um den Eintrag zu bearbeiten.</li>
<br />
<li>Neue Sportarten können durch "Create" hinzugefügt werden.</li>
<br />
<li>Die Sportarten können inkl. ihrer Kriterienwertungen über "Export" als .csv-Datei heruntergeladen werden.</li> {/* Das Implementieren */}
</ul>
</CardContent>
</Card>
</div>
);
const AsideSportEdit = () => (
<div style={{ width: 400, margin: '1em' }}>
<Card>
<CardContent>
<Typography variant="h4" align="center">Tipps&Tricks</Typography>
<br />
<ul>
<li>Der Slider "Wird aktuell angeboten" entscheidet, ob der Sport beim Quiz als Ergebnis auftreten kann.</li>
<br />
<li>Wenn "Wird aktuell angeboten" deaktiviert wird,
rutscht der Sport in das Archiv und wird im Sport Management oder der Incomplete List nicht mehr angezeigt.</li>
<br />
<li>Das Feld "Zuletzt genutzt" sagt aus, wann der Sport zu der aktiven Auswahl hinzugefügt worden ist.
Das passiert entweder durch manuelles Aktivieren oder durch das Scrapen von neuen Informationen von <a href="https://www.buchsys.de/fu-berlin/angebote/aktueller_zeitraum/index.html">buchsys.de</a>.</li>
<br />
<li>
<p>Für jedes Kriterium kann ein ganzzahliger Wert zwischen 1 und 9 eingesetzt werden.
Das ist die Gewichtung des Sports in dem jeweiligen Kriterium.
</p>
<p>
Es kann auch eine -1 für das Kriterium eingetragen werden.
<b> Das bedeutet, dass das Kriterium als nicht ausgefüllt gilt und in der Incomplete Sport List erscheinen wird.</b>
</p>
</li>
</ul>
</CardContent>
</Card >
</div >
);
const AsideSportCreate = () => (
<div style={{ width: 400, margin: '1em' }}>
<Card>
<CardContent>
<Typography variant="h4" align="center">Tipps&Tricks</Typography>
<br />
<ul>
<li>Die Kriterien können ausgefüllt werden, nachdem der Sport erstellt wurde.
Du wirst automatisch auf die richtige Seite weitergeleitet.</li>
</ul>
</CardContent>
</Card>
</div>
);
export const sportList = props => (
<List {...props}>
export const SportList = props => (
<List {...props} aside={<AsideSportList />}>
<Datagrid rowClick="edit">
<TextField source="id" />
<TextField source="name" />
<UrlField source="url" />
<BooleanField source="is_filled" />
<BooleanField source="is_filled" label="Kriterien ausgefüllt?" />
</Datagrid>
</List >
);
export const sportEdit = props => (
<Edit {...props}>
export const SportEdit = props => (
<Edit {...props} aside={<AsideSportEdit />}>
<SimpleForm>
<TextInput disabled source="id" />
<TextInput source="name" fullWidth />
<TextInput source="url" fullWidth />
<BooleanInput source="currently_active" />
<DateInput disabled source="last_used" />
<ArrayInput source="criteria">
<Typography variant="h4" fullWidth>Sport bearbeiten</Typography>
<TextInput disabled source="id" label="ID" />
<TextInput source="name" fullWidth required />
<TextInput source="url" label="URL" fullWidth required />
<BooleanInput source="currently_active" label="Wird aktuell angeboten" />
<DateInput disabled source="last_used" label="Zuletzt genutzt" />
<Typography variant="h5" align="left">Kriterien</Typography>
<ArrayInput source="criteria" label="">
<SimpleFormIterator disableAdd disableRemove> {/* Used because you cannot know how many objects will be sent */}
<TextInput disabled source="name" label="Kriterienname" />
{/* Documentation is wrong, look here! https://github.com/marmelab/react-admin/issues/2500
getSource() needs to get called without arguments before the return,
instead of as the source parameter of the TextField with "name" as argument */}
<FormDataConsumer>
{({ getSource, scopedFormData }) => {
getSource();
return (
<TextField
source={"name"} record={scopedFormData} label="Kriterienname"
/>
);
}}
</FormDataConsumer>
{/* criterionEditValidator checks input if it is within 1-9 or -1 and sets it accordingly */}
<NumberInput
source="value"
......@@ -55,11 +147,12 @@ export const sportEdit = props => (
);
// sportCreate cannot know at this point how many and which criteria are used, so they are editable after creating the sport
export const sportCreate = props => (
<Create {...props}>
export const SportCreate = props => (
<Create {...props} aside={<AsideSportCreate />}>
<SimpleForm>
<TextInput source="name" fullWidth />
<TextInput source="url" fullWidth />
<Typography variant="h4" align="left">Sport erstellen</Typography>
<TextInput source="name" fullWidth required />
<TextInput source="url" fullWidth required />
</SimpleForm>
</Create>
);
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment