Skip to content
Snippets Groups Projects
Commit 30cb8de3 authored by Jonathan Weth's avatar Jonathan Weth :keyboard:
Browse files

Add dyn selector [WORK COPY]

parent 02cea3ed
No related branches found
No related tags found
1 merge request!86Merge school-apps
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="JavaScriptLibraryMappings">
<file url="file://$PROJECT_DIR$" libraries="{jquery-3.2.1}" />
<file url="file://$PROJECT_DIR$" libraries="{jquery-3.2.1, react-dom.production, react.production}" />
</component>
</project>
\ No newline at end of file
......@@ -21,6 +21,8 @@
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="jquery-3.2.1" level="application" />
<orderEntry type="module" module-name="bwinf-36-2" />
<orderEntry type="library" name="react.production" level="application" />
<orderEntry type="library" name="react-dom.production" level="application" />
</component>
<component name="TemplatesService">
<option name="TEMPLATE_CONFIGURATION" value="Django" />
......
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# production
/build
# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*
This diff is collapsed.
{
"name": "dynselect",
"version": "0.1.0",
"private": true,
"dependencies": {
"jquery": "^3.3.1",
"materialize-css": "^1.0.0-rc.2",
"react": "^16.7.0",
"react-dom": "^16.7.0",
"react-scripts": "2.1.3",
"prop-types": "latest"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": "react-app"
},
"browserslist": [
">0.2%",
"not dead",
"not ie <= 11",
"not op_mini all"
]
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico"/>
<meta
name="viewport"
content="width=device-width, initial-scale=1, shrink-to-fit=no"
/>
<meta name="theme-color" content="#000000"/>
<link rel="manifest" href="%PUBLIC_URL%/manifest.json"/>
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<title>React App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>
</html>
{
"short_name": "React App",
"name": "Create React App Sample",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}
import React, {Component} from 'react';
import './App.css';
import "materialize-css/dist/css/materialize.css";
import M from "materialize-css/dist/js/materialize";
import PropTypes from "prop-types";
const OPTIONS_ONLINE_COMMON = [
"Portal ist nicht erreichbar",
"Fehlermeldung(en) tauchen auf",
"Anmeldung funktiontiert nicht",
"Zugangsdaten vergessen"
];
const BASIC_OPTIONS = [
{
id: "deviceIssues",
name: "Probleme am Computer/Notebook",
options: [
{
id: "loginIssue",
name: "Anmeldeproblem/Passwort vergessen"
},
{
id: "internetIssue",
name: "Internetproblem"
},
{
id: "noReaction",
name: "Programm-/Computerabsturz (keine Reaktion)"
},
{
id: "powerOffNoBoot",
name: "Computer/Notebook ist ausgegangen/startet nicht"
},
{
id: "speedIssue",
name: "Computer/Notebook zu langsam"
},
{
id: "noUSB",
name: "USB-Stick wird nicht erkannt"
},
{
id: "noOpenTray",
name: "CD/DVD-Laufwerk öffnet sich nicht"
},
{
id: "noCDDVD",
name: "CD/DVD wird nicht erkannt/abgespielt"
},
{
id: "keyboardMouse",
name: "Tastatur/Maus funktioniert nicht"
},
{
id: "missingHardware",
name: "Tastatur/Maus/Lautsprecher/etc. fehlt"
},
{
id: "missingKeys",
name: "Fehlende Tasten auf der Tastatur"
}
]
},
{
id: "infrastructureIssues",
name: "Infrastrukturprobleme",
options: [
{
id: "presentationDeviceIssue",
name: "Problem mit Beamer/Fernseher",
helpText: "Bitte wähle aus, wo der Beamer bzw. Fernseher steht!"
},
{
id: "subMonitorIssue",
name: "Vertretungsplanmonitor funktioniert nicht",
helpText: "Nenne uns bitte in der Beschreibung ggf. weitere Informationen!"
},
{
id: "aulaIssue",
name: "Problem in der Aula (→Technik-AG)",
helpText: "Deine Anfrage wird direkt an die Technik-AG weitergeleitet."
},
{
id: "wlanIssue",
name: "Probleme mit dem Schul-WLAN (kath-schueler/lehrer)",
helpText: "Nenne uns bitte unbedingt auch den Ort in der Schule, an dem das Problem auftrat."
},
]
},
{
id: "onlineIssues",
name: "Webservices",
options: [
{
id: "forum",
name: "Forum (ILIAS)",
options: OPTIONS_ONLINE_COMMON.concat([
"Ich kann meinen Kurs bzw. Klasse nicht sehen/finden.",
"Ich kann keine Dateien hochladen.",
"Es taucht eine weiße Seite auf.",
"Ich habe falsche Informationen gefunden.",
])
},
{
id: "mail",
name: "Webmail/Mailserver",
options: OPTIONS_ONLINE_COMMON.concat([
"Mein E-Mail-Programm funktioniert mit meiner …@katharineum.de-Adresse nicht.",
"Ich bekomme keine E-Mails bzw. kann keine senden."
])
},
{
id: "schoolapps",
name: "SchoolApps",
options: OPTIONS_ONLINE_COMMON.concat([
"Der Stundenplan/Vertretungsplan ist falsch.",
"Ich bin der falschen Klasse zugeordnet.",
"Ich habe einen Fehler gefunden."
])
},
{
id: "subOrMenu",
name: "Vertretungsplan/Speiseplan",
options: OPTIONS_ONLINE_COMMON.concat([
"Kein Vertretungsplan zu sehen",
"Falscher Vertretungsplan zu sehen",
"Kein Speiseplan zu sehen",
"Falscher Speiseplan zu sehen"
])
},
{
id: "website",
name: "Website (katharineum-zu-luebeck.de)",
options: [
"Website nicht erreichbar",
"Falsche Inhalte vorhanden",
"Typografiefehler"
]
},
{
id: "otherOnlineIssue",
name: "Andere Anwendung"
},
]
},
{
id: "otherIssues",
name: "Andere Probleme",
options: [
{
id: "extra",
name: "Sonstiges"
}
]
},
];
const ROOMS_WITH_PRESENTATION_DEVICE = [
"R 0.04",
"R 0.05",
"R 0.07",
"R 0.08"
];
const OTHER_LOCATIONS = [
"Notebookwagen 1",
"NotebookqAFWN 1",
];
const LOCATIONS = ROOMS_WITH_PRESENTATION_DEVICE.concat(OTHER_LOCATIONS);
function getCategoryOfOption(option) {
for (const category of BASIC_OPTIONS) {
// console.log(category);
for (const opt of category.options) {
// console.log(opt);
if (opt.id === option) {
return category.id;
}
}
}
}
function getOption(option) {
for (const category of BASIC_OPTIONS) {
// console.log(category);
for (const opt of category.options) {
// console.log(opt);
if (opt.id === option) {
return opt;
}
}
}
}
class Select extends Component {
render() {
return <select onChange={this.props.onChange} defaultValue={"no"} required={true}>
<option value={"no"} disabled={true}>Nichts ausgewählt</option>
{this.props.values.map(function (val, i) {
return <option value={val} key={i}>{val}</option>;
})}
<option value={"extra"}>{this.props.defaultValue}</option>
</select>
}
}
Select.propTypes = {
onChange: PropTypes.func.isRequired,
values: PropTypes.array.isRequired,
defaultValue: PropTypes.string,
};
Select.defaultProps = {
defaultValue: "Sonstiges"
};
class Input extends Component {
render() {
return <div
className={(this.props.show ? "" : "hide ") + "input-field col s4"}>
<i className={"material-icons prefix"}>{this.props.icon}</i>
{this.props.children}
<label>{this.props.label}</label>
</div>;
}
}
Input.propTypes = {
icon: PropTypes.string,
show: PropTypes.bool,
label: PropTypes.string.isRequired,
children: PropTypes.object.isRequired
};
Input.defaultProps = {
icon: "list",
show: false,
};
class App extends Component {
constructor() {
super();
this.state = {
selectedCategory: "noCategory",
selectedOption: null,
helpText: "Wähle bitte eine Kategorie aus!",
valueB: "",
valueC: "",
step: 0
}
}
componentDidMount() {
// Init materialize selects
const elems = document.querySelectorAll('select');
M.FormSelect.init(elems, {});
}
_onCategoryChanges = (e) => {
const opt = e.target.value;
const category = getCategoryOfOption(opt);
const option = getOption(opt);
// Get matching helper text
let helpText = option.helpText || this.state.helpText;
if (category === "deviceIssues") {
helpText = "Wähle bitte das Gerät mit dem Problem aus! Bitte vergiss nicht, uns das Problem unten genauer zu beschreiben!"
} else if (category === "onlineIssues") {
helpText = "Bitte konkretisiere das Problem durch eine Auswahl und gib bitte unten genauere Informationen an."
} else if (category === "otherIssues") {
helpText = "Da es sich scheinbar um ein seltenes oder noch nicht erfasstes Problem handelt, gib uns bitte besonders viele Informationen."
}
// Update state
this.setState({
selectedCategory: category,
selectedOption: option,
step: 1,
helpText: helpText
})
};
_onSetB = (e) => {
const val = e.target.value;
this.setState({
valueB: val,
step: 2
})
};
_onSetC = (e) => {
const val = e.target.value;
this.setState({
valueC: val,
step: 2
})
};
render() {
console.log(this.state);
const that = this;
const sC = this.state.selectedCategory;
const sO = this.state.selectedOption ? this.state.selectedOption.id : null;
const step = this.state.step;
console.log(BASIC_OPTIONS[2].options);
return (
<div className="App">
<div className={"row"}>
<div className="input-field col s4">
<i className={"material-icons prefix"}>list</i>
<select onChange={this._onCategoryChanges} defaultValue={"noCategory"}>
<option value={"noCategory"} disabled={true}>Keine Kategorie ausgewählt</option>
{BASIC_OPTIONS.map(function (category) {
return <optgroup label={category.name} key={category.id}>
{category.options.map(function (option) {
return <option value={option.id} key={option.id}>{option.name}</option>;
})}
</optgroup>;
})}
{/*<option value={"extra"}>Sonstiges</option>*/}
</select>
<label>Kategorie</label>
</div>
{/* Section B – Device Issues*/}
<Input label={"Ort des Computer/Notebook"} icon={"location_on"} show={sC === "deviceIssues"}>
<Select onChange={this._onSetB} values={LOCATIONS} defaultValue={"Anderer Ort"}/>
</Input>
{/* Section B – Presentation Device Issues */}
<Input label={"Ort des Beamer/Fernseher"} icon={"location_on"}
show={sO === "presentationDeviceIssue"}>
<Select onChange={this._onSetB} values={ROOMS_WITH_PRESENTATION_DEVICE}
defaultValue={"Anderer Raum"}/>
</Input>
{/* Section B – Substitution Monitor Issue */}
<Input label={"Art des Problems"} icon={"bug_report"} show={sO === "subMonitorIssue"}>
<Select onChange={this._onSetB}
values={["Schwarzer Bildschirm", "Tage wechseln nicht (Eingefroren)"]}
defaultValue={"Anderer Raum"}/>
</Input>
{/* Section B – WLAN Issue */}
<Input label={"Art des Problems"} icon={"bug_report"} show={sO === "wlanIssue"}>
<Select onChange={this._onSetB}
values={["Kein Empfang", "Zugangsdaten funktionieren nicht", "Geschwindigkeit zu langsam"]}
defaultValue={"Anderes Problem"}/>
</Input>
{/* Section B – Online Issue*/}
{BASIC_OPTIONS[2].options.map(function (opt) {
if (opt.options) {
return <Input label={"Art des Problems"} icon={"bug_report"}
show={sC === "onlineIssues" && sO === opt.id} key={opt.id}>
<Select onChange={that._onSetB}
values={opt.options}
defaultValue={"Anderes Problem"}/>
</Input>;
} else {
return <p/>;
}
})}
{/* Section C – Presentation Device Issues */}
<Input label={"Handelt es sich um einen Beamer oder einen Fernseher?"} icon={"tv"}
show={sO === "presentationDeviceIssue" && step === 2}>
<Select onChange={this._onSetC} values={["Beamer", "Fernseher/Bildschirm"]}
defaultValue={"Sonstiges"}/>
</Input>
{/* Section C – WLAN Issue */}
<Input label={"Um welches WLAN-Netzwerk handelt es sich?"} icon={"wifi"}
show={sO === "wlanIssue" && step === 2}>
<Select onChange={this._onSetC}
values={["kath-schueler", "kath-lehrer", "kath-edu", "kath-gaeste"]}
defaultValue={"-"}/>
</Input>
{/* Section C – Device Issue */}
<div
className={(sC === "deviceIssues" && step === 2 ? "" : "hide ") + "input-field col s4"}>
<i className={"material-icons prefix"}>device_unknown</i>
<input type={"text"} id={"valc"} onChange={this._onSetC} required={true}/>
<label htmlFor="valc">Um welches Gerät handelt es sich?</label>
</div>
{/* Helper Text */}
<div className={"col s12"}>
<p>
<i className={"material-icons left"}>info</i>
{this.state.helpText}
</p>
</div>
</div>
{/* Prepare values for Django */}
<div>
<input type={"hidden"} name={"a"}
value={this.state.selectedOption ? this.state.selectedOption.name : ""}/>
<input type={"hidden"} name={"b"} value={this.state.valueB}/>
<input type={"hidden"} name={"c"} value={this.state.valueC}/>
</div>
</div>
);
}
}
export default App;
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
ReactDOM.render(<App />, document.getElementById('root'));
......@@ -54,6 +54,7 @@ INSTALLED_APPS = [
'django.contrib.messages',
'django.contrib.staticfiles',
'material',
'django_react_templatetags',
]
MIDDLEWARE = [
......@@ -82,6 +83,7 @@ TEMPLATES = [
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
'django_react_templatetags.context_processors.react_context_processor',
],
},
},
......
......@@ -8,15 +8,11 @@ class REBUSForm(forms.Form):
('PC funktioniert nicht', 'PC funktioniert nicht'),
('Laptop funktioniert nicht', 'Laptop funktioniert nicht'), ('Sonstiges', 'Sonstiges')]
room = forms.CharField(label='Ihr Raum', max_length=15, required=True)
# room = forms.CharField(label='Ihr Raum', max_length=15, required=True)
category = forms.ChoiceField(label='Kategorie', choices=categories, required=True)
short_description = forms.CharField(label='Bitte beschreiben Sie Ihren Fehler in einem Satz', required=True)
long_description = forms.CharField(label='Bitte beschreiben Sie Ihren Fehler genauer', required=False)
layout = Layout(Row('room', 'category'),
Row('short_description'),
Row('long_description'),
)
long_description = forms.CharField(widget=forms.Textarea, label='Bitte beschreiben Sie Ihren Fehler genauer',
required=False)
class FeedbackForm(forms.Form):
......@@ -43,7 +39,8 @@ class FeedbackForm(forms.Form):
choices=ratings, required=True)
short_description = forms.CharField(label='Bitte geben Sie ein kurzes Feedback in einem Satz ein', required=True)
long_description = forms.CharField(label='Bitte geben Sie ein ausführliches Feedback ein', required=False)
ideas = forms.CharField(label='Haben Sie Ideen, die wir in die SchoolApps einbauen können? Geben Sie sie hier ein!', required=False)
ideas = forms.CharField(label='Haben Sie Ideen, die wir in die SchoolApps einbauen können? Geben Sie sie hier ein!',
required=False)
layout = Layout(Row('design_rating'),
Row('functions_rating'),
......
......@@ -2,25 +2,65 @@
{% load material_form %}
<main>
<script crossorigin src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>
{% load react %}
<p class="flow-text">
<strong>Fehler melden – REBUS – REport-A-Bug-System</strong>
</p>
<form method="post">
{% csrf_token %}
{% form form=form %}
{% endform %}
<button type="submit" name="go" class="btn waves-effect waves-light green">
Problem-/Fehlermeldung einreichen
<i class="material-icons right">send</i>
</button>
</form>
<p>
<strong>Wichtig: </strong>
Bitte beachten Sie, dass ein Widerruf nach dem Absenden nicht mehr möglich ist.
</p>
<p class="flow-text">
<strong>Fehler melden – REBUS – REport-A-Bug-System</strong>
</p>
<form method="post">
{% csrf_token %}
<p class="red-text">{{ form.non_field_errors }}</p>
{% react_render component="DynSelect" props=my_data %}
<div class="row">
<div class="col s12">
<p class="red-text">{{ form.category.errors }}</p>
<div class="input-field col s12 m4">
<i class="material-icons prefix">priority_high</i>
<select id="category" name="category" class="validate" required>
<option value="" selected disabled>Bitte auswählen ...</option>
<option value="Sonstiges">Sonstiges</option>
</select>
<label for="category">Kategorie</label>
</div>
</div>
</div>
<div class="row">
<p class="red-text">{{ form.short_description.errors }}</p>
<div class="input-field col s12">
<i class="material-icons prefix">help</i>
{{ form.short_description }}
<label for="{{ form.short_description.id_for_label }}">Bitte beschreiben Sie Ihren Fehler <strong>in
einem Satz</strong></label>
</div>
</div>
<div class="row">
<p class="red-text">{{ form.long_description.errors }}</p>
<div class="input-field col s12">
<i class="material-icons prefix">mode_edit</i>
<textarea id="{{ form.long_description.id_for_label }}" name="{{ form.long_description.html_name }}"
class="materialize-textarea"></textarea>
<label for="{{ form.long_description.id_for_label }}">Bitte beschreiben Sie Ihren Fehler
<strong>genauer</strong></label>
</div>
</div>
<button type="submit" name="go" class="btn waves-effect waves-light green">
Problem-/Fehlermeldung einreichen
<i class="material-icons right">send</i>
</button>
</form>
<p>
<strong>Wichtig: </strong>
Bitte beachten Sie, dass ein Widerruf nach dem Absenden nicht mehr möglich ist.
</p>
{% react_print %}
</main>
{% include 'partials/footer.html' %}
\ No newline at end of file
......@@ -11,12 +11,12 @@ def rebus(request):
if request.method == 'POST':
form = REBUSForm(request.POST)
if form.is_valid():
room = form.cleaned_data['room']
# room = form.cleaned_data['room']
contraction = request.user.username
category = form.cleaned_data['category']
short_description = form.cleaned_data['short_description']
long_description = form.cleaned_data['long_description']
description = "**Kategorie: **" + category + "\n\n" + "**Raum: **" + room + "\n\n" + "**Übermittelt von: **" + contraction + "\n\n" + "**Nachricht: **" + long_description + "\n\n"
description = "**Kategorie: **" + category + "\n\n" + "**Raum: **\n\n**Übermittelt von: **" + contraction + "\n\n" + "**Nachricht: **" + long_description + "\n\n"
kb = Kanboard('https://kanboard.katharineum.de/jsonrpc.php', 'jsonrpc', 'f984754c9e87ab43e98ed2f94d2080b6f8e5c499aca95e1fb98c4fc3c7ea')
kb.create_task(project_id=4, title=short_description, description=description)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment