1
1
Fork 0

Challenges CRUD + several changes

This commit is contained in:
Jordy van Zeeland 2023-11-14 08:31:57 +01:00
parent 9a33be5460
commit 76cc5fb0f4
11 changed files with 234 additions and 21 deletions

View File

@ -4,6 +4,7 @@ import { ColorRing } from 'react-loader-spinner'
import Login from "./views/login";
import Books from "./views/bookslist";
import BooksList from "./views/bookslist";
import Challenges from "./views/challenges";
const Dashboard = lazy(() => import("./views/dashboard"));
@ -28,6 +29,7 @@ function App() {
<Routes>
<Route exact path="/" element={localStorage.getItem('token') ? <Dashboard /> : <Login />} />
<Route exact path="/books" element={<BooksList />} />
<Route exact path="/challenges" element={<Challenges />} />
{/* <Route exact path="/login" element={<Login />} /> */}
</Routes>
</Suspense>

View File

@ -1,7 +1,26 @@
const getFlagEmoji = (countryCode) => {
const codePoints = countryCode
.toUpperCase()
.split('')
.map(char => 127397 + char.charCodeAt());
return String.fromCodePoint(...codePoints);
export const readCookie = (name) => {
var nameEQ = name + "=";
var ca = document.cookie.split(';');
for(var i=0;i < ca.length;i++) {
var c = ca[i];
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)
}

View File

@ -26,15 +26,15 @@ export const getAllBooks = () => {
// })
// }
// export const getAllChallenges = () => {
// return fetch('/api/books/challenges', {
// "method": "GET",
// })
// .then(response => response.json())
// .then(data => {
// return data;
// })
// }
export const getAllChallenges = () => {
return fetch('/api/books/challenges', {
"method": "GET",
})
.then(response => response.json())
.then(data => {
return data;
})
}
export const insertChallenge = (data) => {
return fetch('/api/books/challenges/insert', {

View File

@ -18,9 +18,9 @@ const Sidebar = () => {
</ul>
<ul className="bottom-menu">
<NavLink to={'/settings'} exact="true">
{/* <NavLink to={'/settings'} exact="true">
<li><i className="fas fa-cog"></i> Instellingen</li>
</NavLink>
</NavLink> */}
<li><i className="fas fa-power-off"></i> Uitloggen</li>
</ul>
</div>

View File

@ -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;

View File

@ -66,6 +66,57 @@ html, body{
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{
width:100%;
background:#1f2940;

File diff suppressed because one or more lines are too long

View File

@ -14,6 +14,10 @@
!*** ./src/views/bookslist.js ***!
\********************************/
/*!*********************************!*\
!*** ./src/views/challenges.js ***!
\*********************************/
/*!***********************************!*\
!*** ./src/components/Sidebar.js ***!
\***********************************/

View File

@ -1,2 +1,2 @@
/*! 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

View File

@ -21,6 +21,7 @@ urlpatterns = [
path('api/', include('api.urls')),
path('', include('frontend.urls')),
path('books/', include('frontend.urls')),
path('challenges/', include('frontend.urls')),
path('login/', include('frontend.urls')),
path('manage/', include('frontend.urls')),
path('manage/challenges', include('frontend.urls'))