add video backend server, fix styling and more #54
@@ -1,9 +1,9 @@
|
|||||||
## Oscars Pool 2025
|
## Oscars Pool 2026
|
||||||
Little nodejs + mongodb app that I hack together with ChatGPT to keep track of watched movies for an incoming Oscars Pool with some friends. App is not secure, using old html standard and is not the most responsive but does the job.
|
Little nodejs + mongodb app that I hack together with ChatGPT to keep track of watched movies for an incoming Oscars Pool with some friends. App is not secure, using old html standard and is not the most responsive but does the job.
|
||||||
|
|
||||||
Would probably need to revamp everything, but didn't want to spend more time on it.
|
Would probably need to revamp everything, but didn't want to spend more time on it.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
## Setup
|
## Setup
|
||||||
Config those in your .env file:
|
Config those in your .env file:
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>Pool Oscars 2025 - Checklist</title>
|
<title>Pool Oscars 2026 - Checklist</title>
|
||||||
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
|
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
<link href="./css/app.css" rel="stylesheet">
|
<link href="./css/app.css" rel="stylesheet">
|
||||||
<style>
|
<style>
|
||||||
@@ -65,6 +65,7 @@
|
|||||||
<a href="movies.html" class="nav-link btn btn-outline-light me-2">Films</a>
|
<a href="movies.html" class="nav-link btn btn-outline-light me-2">Films</a>
|
||||||
<a href="checklist.html" class="nav-link btn btn-outline-light me-2">Checklist</a>
|
<a href="checklist.html" class="nav-link btn btn-outline-light me-2">Checklist</a>
|
||||||
<a href="user-stat.html" class="nav-link btn btn-outline-light me-2">Statistiques</a>
|
<a href="user-stat.html" class="nav-link btn btn-outline-light me-2">Statistiques</a>
|
||||||
|
<a id="admin-control-link" href="control.html" class="nav-link btn btn-warning me-2 d-none">Admin</a>
|
||||||
</div>
|
</div>
|
||||||
<!-- Move user info inside collapsible navbar and align it properly -->
|
<!-- Move user info inside collapsible navbar and align it properly -->
|
||||||
<div class="d-flex ms-auto mt-2 mt-lg-0 align-items-center">
|
<div class="d-flex ms-auto mt-2 mt-lg-0 align-items-center">
|
||||||
@@ -78,7 +79,7 @@
|
|||||||
<div class="container mt-5">
|
<div class="container mt-5">
|
||||||
<h2>Checklist</h2>
|
<h2>Checklist</h2>
|
||||||
<div id="watched-ratio" class="ratio"></div>
|
<div id="watched-ratio" class="ratio"></div>
|
||||||
<h3 class="fs-6" style="margin-bottom: -1px;">Temps avant les Oscars (2 mars 2025) - <span id="time-left"></span></h3>
|
<h3 class="fs-6" style="margin-bottom: -1px;">Temps avant les Oscars (15 mars 2026) - <span id="time-left"></span></h3>
|
||||||
<h3 class="fs-6"><span id="movies-per-day"></span></h3>
|
<h3 class="fs-6"><span id="movies-per-day"></span></h3>
|
||||||
<div class="progress my-3">
|
<div class="progress my-3">
|
||||||
<div id="progress-bar" class="progress-bar" role="progressbar" style="width: 0%; background-color: red;" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div>
|
<div id="progress-bar" class="progress-bar" role="progressbar" style="width: 0%; background-color: red;" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div>
|
||||||
|
|||||||
@@ -0,0 +1,87 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Pool Oscars 2026 - Admin</title>
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
|
<link href="./css/app.css" rel="stylesheet">
|
||||||
|
<style>
|
||||||
|
.navbar-custom {
|
||||||
|
background-color: black;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
.navbar-custom .navbar-brand,
|
||||||
|
.navbar-custom .nav-link {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
.navbar-custom .nav-link:hover {
|
||||||
|
color: #ddd;
|
||||||
|
}
|
||||||
|
.navbar-toggler {
|
||||||
|
border-color: white;
|
||||||
|
}
|
||||||
|
.navbar-toggler-icon {
|
||||||
|
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3E%3Cpath stroke='white' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3E%3C/svg%3E");
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body class="bg-light">
|
||||||
|
|
||||||
|
<nav class="navbar navbar-expand-lg navbar-custom">
|
||||||
|
<div class="container">
|
||||||
|
<a class="navbar-brand" style="margin-left: -7px;">
|
||||||
|
<img src="img/logo_w.png" style="max-width: 220px; height: 70px; object-fit: contain;">
|
||||||
|
</a>
|
||||||
|
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||||
|
<span class="navbar-toggler-icon"></span>
|
||||||
|
</button>
|
||||||
|
<div class="collapse navbar-collapse" id="navbarNav">
|
||||||
|
<div class="navbar-nav">
|
||||||
|
<a href="movies.html" class="nav-link btn btn-outline-light me-2">Films</a>
|
||||||
|
<a href="checklist.html" class="nav-link btn btn-outline-light me-2">Checklist</a>
|
||||||
|
<a href="user-stat.html" class="nav-link btn btn-outline-light me-2">Statistiques</a>
|
||||||
|
<a href="control.html" class="nav-link btn btn-warning me-2">Admin</a>
|
||||||
|
</div>
|
||||||
|
<div class="d-flex ms-auto mt-2 mt-lg-0 align-items-center">
|
||||||
|
<span id="user-name" class="navbar-text me-3"></span>
|
||||||
|
<button id="log-off" class="btn btn-danger">Déconnexion</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<div class="container mt-5" style="max-width: 720px;">
|
||||||
|
<h2>Admin - Ajouter un film</h2>
|
||||||
|
<p class="text-muted mb-4">
|
||||||
|
Ajoute un film via l’API (<code>/api/movies/add</code>). Le serveur récupère automatiquement le titre/plot/affiche depuis OMDb avec l’<code>imdb_id</code>.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div id="response" class="alert d-none" role="alert"></div>
|
||||||
|
|
||||||
|
<form id="add-movie-form" class="card p-3">
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="imdb_id" class="form-label">IMDB ID (ex: tt1234567)</label>
|
||||||
|
<input type="text" class="form-control" id="imdb_id" placeholder="tt..." required>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="category" class="form-label">Catégorie</label>
|
||||||
|
<input type="text" class="form-control" id="category" placeholder="Best Picture, etc." required>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="vod_link" class="form-label">Lien VOD</label>
|
||||||
|
<input type="url" class="form-control" id="vod_link" placeholder="https://..." required>
|
||||||
|
</div>
|
||||||
|
<div class="d-flex gap-2">
|
||||||
|
<button type="submit" class="btn btn-primary">Ajouter</button>
|
||||||
|
<button type="button" id="reset-form" class="btn btn-outline-secondary">Reset</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
|
||||||
|
<script src="./js/app_control.js"></script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
+2
-2
@@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>Pool Oscars 2025</title>
|
<title>Pool Oscars 2026</title>
|
||||||
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
|
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
<link href="./css/app.css" rel="stylesheet">
|
<link href="./css/app.css" rel="stylesheet">
|
||||||
<style>
|
<style>
|
||||||
@@ -46,7 +46,7 @@
|
|||||||
<!-- Footer Section -->
|
<!-- Footer Section -->
|
||||||
<footer>
|
<footer>
|
||||||
|
|
||||||
<p id="footer-copy"><a id="copy" href="https://github.com/quoije/oscars-pool">quoije</a> - deux mille vingt-cinq</p>
|
<p id="footer-copy"><a id="copy" href="https://github.com/quoije/oscars-pool">quoije</a> - deux mille vingt-six</p>
|
||||||
<p id="footer-text"></p>
|
<p id="footer-text"></p>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
window.onload = async function () {
|
window.onload = async function () {
|
||||||
const token = localStorage.getItem('auth_token');
|
const token = localStorage.getItem('auth_token');
|
||||||
|
|
||||||
const targetDate = new Date('March 2, 2025');
|
const targetDate = new Date('March 15, 2026');
|
||||||
const currentDate = new Date();
|
const currentDate = new Date();
|
||||||
const timeDifference = targetDate - currentDate;
|
const timeDifference = targetDate - currentDate;
|
||||||
const daysLeft = Math.floor(timeDifference / (1000 * 60 * 60 * 24));
|
const daysLeft = Math.floor(timeDifference / (1000 * 60 * 60 * 24));
|
||||||
@@ -12,6 +12,10 @@ window.onload = async function () {
|
|||||||
const decoded = JSON.parse(atob(token.split('.')[1]));
|
const decoded = JSON.parse(atob(token.split('.')[1]));
|
||||||
const userName = decoded.name;
|
const userName = decoded.name;
|
||||||
document.getElementById('user-name').textContent = userName;
|
document.getElementById('user-name').textContent = userName;
|
||||||
|
if (decoded.admin) {
|
||||||
|
const adminLink = document.getElementById('admin-control-link');
|
||||||
|
if (adminLink) adminLink.classList.remove('d-none');
|
||||||
|
}
|
||||||
const currentTime = Math.floor(Date.now() / 1000);
|
const currentTime = Math.floor(Date.now() / 1000);
|
||||||
if (decoded.exp && decoded.exp < currentTime) {
|
if (decoded.exp && decoded.exp < currentTime) {
|
||||||
localStorage.removeItem('auth_token');
|
localStorage.removeItem('auth_token');
|
||||||
|
|||||||
@@ -0,0 +1,92 @@
|
|||||||
|
window.onload = async function () {
|
||||||
|
const token = localStorage.getItem('auth_token');
|
||||||
|
if (!token) {
|
||||||
|
window.location.href = '/';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let decoded;
|
||||||
|
try {
|
||||||
|
decoded = JSON.parse(atob(token.split('.')[1]));
|
||||||
|
} catch (e) {
|
||||||
|
localStorage.removeItem('auth_token');
|
||||||
|
window.location.href = '/';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentTime = Math.floor(Date.now() / 1000);
|
||||||
|
if (decoded.exp && decoded.exp < currentTime) {
|
||||||
|
localStorage.removeItem('auth_token');
|
||||||
|
window.location.href = '/';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById('user-name').textContent = decoded.name || '';
|
||||||
|
|
||||||
|
// Admin-only page: if token doesn't contain admin flag, bounce.
|
||||||
|
if (!decoded.admin) {
|
||||||
|
window.location.href = '/movies.html';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const responseEl = document.getElementById('response');
|
||||||
|
const form = document.getElementById('add-movie-form');
|
||||||
|
|
||||||
|
function showResponse(kind, message) {
|
||||||
|
responseEl.classList.remove('d-none', 'alert-success', 'alert-danger', 'alert-warning');
|
||||||
|
responseEl.classList.add(kind === 'success' ? 'alert-success' : kind === 'warning' ? 'alert-warning' : 'alert-danger');
|
||||||
|
responseEl.textContent = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById('reset-form').addEventListener('click', function () {
|
||||||
|
form.reset();
|
||||||
|
responseEl.classList.add('d-none');
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById('log-off').addEventListener('click', function () {
|
||||||
|
localStorage.removeItem('auth_token');
|
||||||
|
window.location.href = '/';
|
||||||
|
});
|
||||||
|
|
||||||
|
form.addEventListener('submit', async function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
const imdb_id = document.getElementById('imdb_id').value.trim();
|
||||||
|
const category = document.getElementById('category').value.trim();
|
||||||
|
const vod_link = document.getElementById('vod_link').value.trim();
|
||||||
|
|
||||||
|
if (!/^tt\d{5,}$/.test(imdb_id)) {
|
||||||
|
showResponse('warning', 'IMDB ID invalide. Exemple attendu: tt1234567');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await fetch('/api/movies/add', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Authorization': `Bearer ${token}`
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ imdb_id, category, vod_link })
|
||||||
|
});
|
||||||
|
|
||||||
|
if (res.ok) {
|
||||||
|
showResponse('success', 'Film ajouté avec succès.');
|
||||||
|
form.reset();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let errMessage = `Erreur (${res.status})`;
|
||||||
|
try {
|
||||||
|
const data = await res.json();
|
||||||
|
errMessage = data.message || data.error || errMessage;
|
||||||
|
} catch (_) {
|
||||||
|
// ignore JSON parse errors
|
||||||
|
}
|
||||||
|
showResponse('danger', errMessage);
|
||||||
|
} catch (err) {
|
||||||
|
showResponse('danger', err.message || 'Erreur réseau');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
window.onload = async function () {
|
window.onload = async function () {
|
||||||
const targetDate = new Date('March 2, 2025');
|
const targetDate = new Date('March 15, 2026');
|
||||||
const currentDate = new Date();
|
const currentDate = new Date();
|
||||||
const timeDifference = targetDate - currentDate;
|
const timeDifference = targetDate - currentDate;
|
||||||
const daysLeft = Math.floor(timeDifference / (1000 * 60 * 60 * 24));
|
const daysLeft = Math.floor(timeDifference / (1000 * 60 * 60 * 24));
|
||||||
@@ -11,6 +11,10 @@ window.onload = async function () {
|
|||||||
const decoded = JSON.parse(atob(token.split('.')[1]));
|
const decoded = JSON.parse(atob(token.split('.')[1]));
|
||||||
const userName = decoded.name;
|
const userName = decoded.name;
|
||||||
document.getElementById('user-name').textContent = userName;
|
document.getElementById('user-name').textContent = userName;
|
||||||
|
if (decoded.admin) {
|
||||||
|
const adminLink = document.getElementById('admin-control-link');
|
||||||
|
if (adminLink) adminLink.classList.remove('d-none');
|
||||||
|
}
|
||||||
|
|
||||||
const currentTime = Math.floor(Date.now() / 1000);
|
const currentTime = Math.floor(Date.now() / 1000);
|
||||||
if (decoded.exp && decoded.exp < currentTime) {
|
if (decoded.exp && decoded.exp < currentTime) {
|
||||||
|
|||||||
@@ -6,6 +6,10 @@ window.onload = async function () {
|
|||||||
const decoded = JSON.parse(atob(token.split('.')[1])); // Manually decoding JWT
|
const decoded = JSON.parse(atob(token.split('.')[1])); // Manually decoding JWT
|
||||||
const userName = decoded.name;
|
const userName = decoded.name;
|
||||||
document.getElementById('user-name').textContent = userName;
|
document.getElementById('user-name').textContent = userName;
|
||||||
|
if (decoded.admin) {
|
||||||
|
const adminLink = document.getElementById('admin-control-link');
|
||||||
|
if (adminLink) adminLink.classList.remove('d-none');
|
||||||
|
}
|
||||||
|
|
||||||
// Verify JWT expiration
|
// Verify JWT expiration
|
||||||
const currentTime = Math.floor(Date.now() / 1000);
|
const currentTime = Math.floor(Date.now() / 1000);
|
||||||
|
|||||||
+4
-3
@@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>Pool Oscars 2025 - Films</title>
|
<title>Pool Oscars 2026 - Films</title>
|
||||||
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
|
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
<link href="./css/app.css" rel="stylesheet">
|
<link href="./css/app.css" rel="stylesheet">
|
||||||
<style>
|
<style>
|
||||||
@@ -80,6 +80,7 @@
|
|||||||
<a href="movies.html" class="nav-link btn btn-outline-light me-2">Films</a>
|
<a href="movies.html" class="nav-link btn btn-outline-light me-2">Films</a>
|
||||||
<a href="checklist.html" class="nav-link btn btn-outline-light me-2">Checklist</a>
|
<a href="checklist.html" class="nav-link btn btn-outline-light me-2">Checklist</a>
|
||||||
<a href="user-stat.html" class="nav-link btn btn-outline-light me-2">Statistiques</a>
|
<a href="user-stat.html" class="nav-link btn btn-outline-light me-2">Statistiques</a>
|
||||||
|
<a id="admin-control-link" href="control.html" class="nav-link btn btn-warning me-2 d-none">Admin</a>
|
||||||
</div>
|
</div>
|
||||||
<!-- Move user info inside collapsible navbar and align it properly -->
|
<!-- Move user info inside collapsible navbar and align it properly -->
|
||||||
<div class="d-flex ms-auto mt-2 mt-lg-0 align-items-center">
|
<div class="d-flex ms-auto mt-2 mt-lg-0 align-items-center">
|
||||||
@@ -97,7 +98,7 @@
|
|||||||
|
|
||||||
<!-- Displaying last updated vod_links -->
|
<!-- Displaying last updated vod_links -->
|
||||||
<div class="alert alert-warning fade show" role="alert">
|
<div class="alert alert-warning fade show" role="alert">
|
||||||
Dernière mise à jour des films: <strong>09-02-2025</strong>
|
Dernière mise à jour des films: <strong>—</strong>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Displaying the ratio of watched movies -->
|
<!-- Displaying the ratio of watched movies -->
|
||||||
@@ -105,7 +106,7 @@
|
|||||||
<!-- This will display the ratio -->
|
<!-- This will display the ratio -->
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h3 class="fs-6">Temps avant les Oscars (2 mars 2025) - <span id="time-left"></span></h3>
|
<h3 class="fs-6">Temps avant les Oscars (15 mars 2026) - <span id="time-left"></span></h3>
|
||||||
<h3 class="fs-6 mb-0">
|
<h3 class="fs-6 mb-0">
|
||||||
|
|
||||||
</h3>
|
</h3>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>Pool Oscars 2025 - Enregistrement</title>
|
<title>Pool Oscars 2026 - Enregistrement</title>
|
||||||
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
|
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
<link href="./css/app.css" rel="stylesheet">
|
<link href="./css/app.css" rel="stylesheet">
|
||||||
</head>
|
</head>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>Pool Oscars 2025 - Statistiques des utilisateurs</title>
|
<title>Pool Oscars 2026 - Statistiques des utilisateurs</title>
|
||||||
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
|
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
<style>
|
<style>
|
||||||
.navbar-custom {
|
.navbar-custom {
|
||||||
@@ -48,6 +48,7 @@
|
|||||||
<a href="movies.html" class="nav-link btn btn-outline-light me-2">Films</a>
|
<a href="movies.html" class="nav-link btn btn-outline-light me-2">Films</a>
|
||||||
<a href="checklist.html" class="nav-link btn btn-outline-light me-2">Checklist</a>
|
<a href="checklist.html" class="nav-link btn btn-outline-light me-2">Checklist</a>
|
||||||
<a href="user-stat.html" class="nav-link btn btn-outline-light me-2">Statistiques</a>
|
<a href="user-stat.html" class="nav-link btn btn-outline-light me-2">Statistiques</a>
|
||||||
|
<a id="admin-control-link" href="control.html" class="nav-link btn btn-warning me-2 d-none">Admin</a>
|
||||||
</div>
|
</div>
|
||||||
<!-- Move user info inside collapsible navbar and align it properly -->
|
<!-- Move user info inside collapsible navbar and align it properly -->
|
||||||
<div class="d-flex ms-auto mt-2 mt-lg-0 align-items-center">
|
<div class="d-flex ms-auto mt-2 mt-lg-0 align-items-center">
|
||||||
|
|||||||
Reference in New Issue
Block a user