Challenges CRUD + several changes
This commit is contained in:
parent
9a33be5460
commit
76cc5fb0f4
|
@ -4,6 +4,7 @@ import { ColorRing } from 'react-loader-spinner'
|
||||||
import Login from "./views/login";
|
import Login from "./views/login";
|
||||||
import Books from "./views/bookslist";
|
import Books from "./views/bookslist";
|
||||||
import BooksList from "./views/bookslist";
|
import BooksList from "./views/bookslist";
|
||||||
|
import Challenges from "./views/challenges";
|
||||||
|
|
||||||
const Dashboard = lazy(() => import("./views/dashboard"));
|
const Dashboard = lazy(() => import("./views/dashboard"));
|
||||||
|
|
||||||
|
@ -28,6 +29,7 @@ function App() {
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route exact path="/" element={localStorage.getItem('token') ? <Dashboard /> : <Login />} />
|
<Route exact path="/" element={localStorage.getItem('token') ? <Dashboard /> : <Login />} />
|
||||||
<Route exact path="/books" element={<BooksList />} />
|
<Route exact path="/books" element={<BooksList />} />
|
||||||
|
<Route exact path="/challenges" element={<Challenges />} />
|
||||||
{/* <Route exact path="/login" element={<Login />} /> */}
|
{/* <Route exact path="/login" element={<Login />} /> */}
|
||||||
</Routes>
|
</Routes>
|
||||||
</Suspense>
|
</Suspense>
|
||||||
|
|
|
@ -1,7 +1,26 @@
|
||||||
const getFlagEmoji = (countryCode) => {
|
export const readCookie = (name) => {
|
||||||
const codePoints = countryCode
|
var nameEQ = name + "=";
|
||||||
.toUpperCase()
|
var ca = document.cookie.split(';');
|
||||||
.split('')
|
for(var i=0;i < ca.length;i++) {
|
||||||
.map(char => 127397 + char.charCodeAt());
|
var c = ca[i];
|
||||||
return String.fromCodePoint(...codePoints);
|
while (c.charAt(0)==' ') c = c.substring(1,c.length);
|
||||||
|
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const initDataTable = () => {
|
||||||
|
let table = new DataTable('#DataTable');
|
||||||
|
table.destroy();
|
||||||
|
setTimeout(() => {
|
||||||
|
table = new DataTable('#DataTable', {
|
||||||
|
language: {
|
||||||
|
url: 'https://cdn.datatables.net/plug-ins/9dcbecd42ad/i18n/Dutch.json',
|
||||||
|
search: "",
|
||||||
|
searchPlaceholder: "Zoeken"
|
||||||
|
},
|
||||||
|
dom: 'rt<"bottom"pl><"clear">',
|
||||||
|
order: []
|
||||||
|
});
|
||||||
|
}, 300)
|
||||||
|
}
|
|
@ -26,15 +26,15 @@ export const getAllBooks = () => {
|
||||||
// })
|
// })
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// export const getAllChallenges = () => {
|
export const getAllChallenges = () => {
|
||||||
// return fetch('/api/books/challenges', {
|
return fetch('/api/books/challenges', {
|
||||||
// "method": "GET",
|
"method": "GET",
|
||||||
// })
|
})
|
||||||
// .then(response => response.json())
|
.then(response => response.json())
|
||||||
// .then(data => {
|
.then(data => {
|
||||||
// return data;
|
return data;
|
||||||
// })
|
})
|
||||||
// }
|
}
|
||||||
|
|
||||||
export const insertChallenge = (data) => {
|
export const insertChallenge = (data) => {
|
||||||
return fetch('/api/books/challenges/insert', {
|
return fetch('/api/books/challenges/insert', {
|
||||||
|
|
|
@ -18,9 +18,9 @@ const Sidebar = () => {
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<ul className="bottom-menu">
|
<ul className="bottom-menu">
|
||||||
<NavLink to={'/settings'} exact="true">
|
{/* <NavLink to={'/settings'} exact="true">
|
||||||
<li><i className="fas fa-cog"></i> Instellingen</li>
|
<li><i className="fas fa-cog"></i> Instellingen</li>
|
||||||
</NavLink>
|
</NavLink> */}
|
||||||
<li><i className="fas fa-power-off"></i> Uitloggen</li>
|
<li><i className="fas fa-power-off"></i> Uitloggen</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -0,0 +1,136 @@
|
||||||
|
import React, { useEffect, useState } from "react";
|
||||||
|
import '../components/DataTables.css';
|
||||||
|
import * as moment from 'moment';
|
||||||
|
import Sidebar from "../components/Sidebar.js";
|
||||||
|
moment.locale('nl');
|
||||||
|
|
||||||
|
const Challenges = (props) => {
|
||||||
|
const [challenges, setChallenges] = useState([]);
|
||||||
|
const [showModal, setShowModal] = useState(false);
|
||||||
|
|
||||||
|
const getData = async (init) => {
|
||||||
|
const [data, functions] = await Promise.all([
|
||||||
|
import("../components/Data.js"),
|
||||||
|
import("../Functions.js")
|
||||||
|
])
|
||||||
|
|
||||||
|
const getchallenges = await data.getAllChallenges();
|
||||||
|
setChallenges(getchallenges);
|
||||||
|
functions.initDataTable();
|
||||||
|
}
|
||||||
|
|
||||||
|
const addChallenge = async (event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
var details = {
|
||||||
|
'year': event.target.year.value,
|
||||||
|
'challenge': event.target.challenge.value
|
||||||
|
};
|
||||||
|
|
||||||
|
var formBody = [];
|
||||||
|
for (var property in details) {
|
||||||
|
var encodedKey = encodeURIComponent(property);
|
||||||
|
var encodedValue = encodeURIComponent(details[property]);
|
||||||
|
formBody.push(encodedKey + "=" + encodedValue);
|
||||||
|
}
|
||||||
|
formBody = formBody.join("&");
|
||||||
|
|
||||||
|
const data = await import("../components/Data.js");
|
||||||
|
await data.insertChallenge(formBody);
|
||||||
|
setShowModal(false);
|
||||||
|
await getData();
|
||||||
|
}
|
||||||
|
|
||||||
|
const deleteChallenge = async (challengeid) => {
|
||||||
|
var result = confirm("Weet je zeker dat je dit wilt verwijderen?");
|
||||||
|
|
||||||
|
if (result) {
|
||||||
|
const data = await import("../components/Data.js");
|
||||||
|
await data.deleteChallenge(challengeid);
|
||||||
|
await getData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
getData();
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<React.Fragment>
|
||||||
|
<Sidebar />
|
||||||
|
<div className="content-manage">
|
||||||
|
<h1>Challenges beheren <button type="button" onClick={() => setShowModal(true)} className="btn btn-success btn-add">Toevoegen</button></h1>
|
||||||
|
|
||||||
|
<div className="DataTable_Container">
|
||||||
|
<table id="DataTable" className="showHead table responsive nowrap" width="100%">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Jaar</th>
|
||||||
|
<th>Challenge</th>
|
||||||
|
<th>Gelezen</th>
|
||||||
|
<th>Voortgang</th>
|
||||||
|
<th>Acties</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{challenges.map((challenge, i) => {
|
||||||
|
|
||||||
|
var challengePercentage = Math.round((challenge.booksread / challenge.nrofbooks) * 100, 0);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<tr key={challenge.id}>
|
||||||
|
<td>{challenge.year}</td>
|
||||||
|
<td>{challenge.nrofbooks}</td>
|
||||||
|
<td>{challenge.booksread}</td>
|
||||||
|
<td>
|
||||||
|
<div className="progress">
|
||||||
|
<div className="progress-bar progress-bar" role="progressbar" style={{ width: challengePercentage + '%' }} aria-valuenow={challengePercentage} aria-valuemin="0" aria-valuemax="100">
|
||||||
|
<div className="progress-bar-number">{challengePercentage}%</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{/* <button type="button" className="btn btn-warning"><i className="fa fa-pen"></i></button> */}
|
||||||
|
<button type="button" onClick={() => deleteChallenge(challenge.id)} className="btn btn-danger"><i className="fa fa-trash"></i></button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{showModal && (<div style={{ display: 'block' }} className="modal" tabIndex="-1" role="dialog">
|
||||||
|
<div className="modal-dialog" role="document">
|
||||||
|
<div className="modal-content">
|
||||||
|
<div className="modal-header">
|
||||||
|
<h5 className="modal-title">Challenge toevoegen</h5>
|
||||||
|
<button type="button" onClick={() => setShowModal(false)} className="close" data-dismiss="modal" aria-label="Close">
|
||||||
|
<i class="fas fa-times-circle"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<form method="POST" onSubmit={(event) => addChallenge(event)}>
|
||||||
|
<div className="modal-body">
|
||||||
|
<div className="form-group">
|
||||||
|
<label htmlFor="year">Jaar</label>
|
||||||
|
<input type="text" className="form-control" id="year"/>
|
||||||
|
</div>
|
||||||
|
<div className="form-group">
|
||||||
|
<label htmlFor="challenge">Aantal boeken</label>
|
||||||
|
<input type="text" className="form-control" id="challenge" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="modal-footer">
|
||||||
|
<button type="submit" className="btn btn-success">Toevoegen</button>
|
||||||
|
<button type="button" onClick={() => setShowModal(false)} className="btn btn-danger cancel" data-dismiss="modal">Annuleren</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>)}
|
||||||
|
</div>
|
||||||
|
</React.Fragment>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Challenges;
|
|
@ -66,6 +66,57 @@ html, body{
|
||||||
background:rgba(0,0,0,0.3);
|
background:rgba(0,0,0,0.3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.content-manage .progress{
|
||||||
|
height: 20px;
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal .modal-header{
|
||||||
|
border-bottom:none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal .modal-header .modal-title{
|
||||||
|
font-size:13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal .modal-footer{
|
||||||
|
border-top: none;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal .modal-footer button{
|
||||||
|
font-size: 13px;
|
||||||
|
padding: 5px 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal .modal-dialog{
|
||||||
|
background: #ffffff;
|
||||||
|
-webkit-box-shadow: 0px 1px 1px 1px #eee;
|
||||||
|
box-shadow: 0px 1px 1px 1px #eee;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal .modal-content{
|
||||||
|
border:none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal .modal-body .form-group{
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal .modal-body .form-group:last-child{
|
||||||
|
margin-bottom: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal .close{
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal .close i{
|
||||||
|
font-size: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
.filter{
|
.filter{
|
||||||
width:100%;
|
width:100%;
|
||||||
background:#1f2940;
|
background:#1f2940;
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -14,6 +14,10 @@
|
||||||
!*** ./src/views/bookslist.js ***!
|
!*** ./src/views/bookslist.js ***!
|
||||||
\********************************/
|
\********************************/
|
||||||
|
|
||||||
|
/*!*********************************!*\
|
||||||
|
!*** ./src/views/challenges.js ***!
|
||||||
|
\*********************************/
|
||||||
|
|
||||||
/*!***********************************!*\
|
/*!***********************************!*\
|
||||||
!*** ./src/components/Sidebar.js ***!
|
!*** ./src/components/Sidebar.js ***!
|
||||||
\***********************************/
|
\***********************************/
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
/*! For license information please see src_Functions_js.js.LICENSE.txt */
|
/*! For license information please see src_Functions_js.js.LICENSE.txt */
|
||||||
(self.webpackChunkfrontend=self.webpackChunkfrontend||[]).push([["src_Functions_js"],{"./src/Functions.js":()=>{eval("const filterDataTable = (column, value, exact) => {\n if (value !== 0 && exact === true) {\n $('#DataTable').DataTable().column(column).search(\"(^\" + value + \"$)\", true, false).draw();\n } else {\n $('#DataTable').DataTable().column(column).search(value).draw();\n }\n};\n\nconst fillDataTableFilters = (filter, value, text) => {\n console.log(value, text);\n\n if (value && !filter.find(\"option:contains('\" + text + \"')\").length) {\n var option = new Option(value, value);\n option.innerHTML = text;\n filter[0].appendChild(option);\n }\n};\n\nconst getFlagEmoji = countryCode => {\n const codePoints = countryCode.toUpperCase().split('').map(char => 127397 + char.charCodeAt());\n return String.fromCodePoint(...codePoints);\n};\n\n//# sourceURL=webpack://frontend/./src/Functions.js?")}}]);
|
"use strict";(self.webpackChunkfrontend=self.webpackChunkfrontend||[]).push([["src_Functions_js"],{"./src/Functions.js":(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{eval('__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ "initDataTable": () => (/* binding */ initDataTable),\n/* harmony export */ "readCookie": () => (/* binding */ readCookie)\n/* harmony export */ });\nconst readCookie = name => {\n var nameEQ = name + "=";\n var ca = document.cookie.split(\';\');\n for (var i = 0; i < ca.length; i++) {\n var c = ca[i];\n while (c.charAt(0) == \' \') c = c.substring(1, c.length);\n if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length);\n }\n return null;\n};\nconst initDataTable = () => {\n let table = new DataTable(\'#DataTable\');\n table.destroy();\n setTimeout(() => {\n table = new DataTable(\'#DataTable\', {\n language: {\n url: \'https://cdn.datatables.net/plug-ins/9dcbecd42ad/i18n/Dutch.json\',\n search: "",\n searchPlaceholder: "Zoeken"\n },\n dom: \'rt<"bottom"pl><"clear">\',\n order: []\n });\n }, 300);\n};\n\n//# sourceURL=webpack://frontend/./src/Functions.js?')}}]);
|
File diff suppressed because one or more lines are too long
|
@ -21,6 +21,7 @@ urlpatterns = [
|
||||||
path('api/', include('api.urls')),
|
path('api/', include('api.urls')),
|
||||||
path('', include('frontend.urls')),
|
path('', include('frontend.urls')),
|
||||||
path('books/', include('frontend.urls')),
|
path('books/', include('frontend.urls')),
|
||||||
|
path('challenges/', include('frontend.urls')),
|
||||||
path('login/', include('frontend.urls')),
|
path('login/', include('frontend.urls')),
|
||||||
path('manage/', include('frontend.urls')),
|
path('manage/', include('frontend.urls')),
|
||||||
path('manage/challenges', include('frontend.urls'))
|
path('manage/challenges', include('frontend.urls'))
|
||||||
|
|
Loading…
Reference in New Issue