Files
xamxam/public/admin/add.php
Pontoporeia e9e012376d Replace .admin-alert BEM classes with semantic role/data-type attributes
- admin.css: replace .admin-alert / .admin-alert--error / .admin-alert--success
  selectors with [role="alert"][data-type="error"] and [role="status"][data-type="success"]
- All 10 admin templates updated: <div class="admin-alert admin-alert--{type}">
  becomes <p role="alert|status" data-type="error|success"> (or <div> for the
  import.php multi-item list that contains a <ul>)
- flash-messages.php partial updated to match
- WCAG benefit: role="alert" is an ARIA live region — errors are announced
  immediately by screen readers without focus movement (fixes WCAG 3.3.1, 4.1.2)
- role="status" (polite live region) used for success messages — announced
  without interrupting the user
- Removes two BEM modifier classes; CSS now targets element semantics directly
2026-04-02 12:35:23 +02:00

252 lines
10 KiB
PHP

<?php
require_once __DIR__ . "/../../config/bootstrap.php";
require_once __DIR__ . '/../../src/AdminAuth.php';
AdminAuth::requireLogin();
if (empty($_SESSION["csrf_token"])) {
$_SESSION["csrf_token"] = bin2hex(random_bytes(32));
}
$pageTitle = "Ajouter un TFE";
require_once __DIR__ . '/../../src/Database.php';
try {
$db = new Database();
$orientations = $db->getAllOrientations();
$apPrograms = $db->getAllAPPrograms();
$finalityTypes = $db->getAllFinalityTypes();
$languages = $db->getAllLanguages();
$formatTypes = $db->getAllFormatTypes();
$licenseTypes = $db->getAllLicenseTypes();
} catch (Exception $e) {
error_log("Failed to load form data: " . $e->getMessage());
die("Erreur lors du chargement du formulaire.");
}
$error = $_SESSION["form_error"] ?? null;
$formData = $_SESSION["form_data"] ?? [];
unset($_SESSION["form_error"], $_SESSION["form_data"]);
function old($key, $default = "") {
global $formData;
return isset($formData[$key]) ? htmlspecialchars($formData[$key]) : $default;
}
function wasSelected($key, $value) {
global $formData;
if (!isset($formData[$key])) return false;
if (is_array($formData[$key])) return in_array($value, $formData[$key]);
return $formData[$key] == $value;
}
?>
<?php $isAdmin = true; $bodyClass = 'admin-body'; require_once APP_ROOT . '/templates/head.php'; ?>
<?php include APP_ROOT . '/templates/header.php'; ?>
<main id="main-content">
<h1>Ajouter un TFE</h1>
<?php if ($error): ?>
<p role="alert" data-type="error">⚠ <?= htmlspecialchars($error) ?></p>
<?php endif; ?>
<form action="actions/formulaire.php" method="post" enctype="multipart/form-data" class="admin-form">
<input type="hidden" name="csrf_token" value="<?= htmlspecialchars($_SESSION["csrf_token"]) ?>">
<!-- Titre -->
<div class="admin-form-row">
<label class="admin-label" for="titre">Titre :</label>
<input class="admin-input" type="text" id="titre" name="titre"
value="<?= old('titre') ?>" required>
</div>
<!-- Sous-titre -->
<div class="admin-form-row">
<label class="admin-label" for="subtitle">Sous-titre (si applicable) :</label>
<input class="admin-input" type="text" id="subtitle" name="subtitle"
value="<?= old('subtitle') ?>">
</div>
<!-- Auteur·ice -->
<div class="admin-form-row">
<label class="admin-label" for="auteurice">Auteur·ice(s) :</label>
<input class="admin-input" type="text" id="auteurice" name="auteurice"
value="<?= old('auteurice') ?>" required>
</div>
<!-- Contact -->
<div class="admin-form-row">
<label class="admin-label" for="mail">Contact(s) (optionnel) [mail/site/insta/etc.] :</label>
<input class="admin-input" type="text" id="mail" name="mail"
value="<?= old('mail') ?>">
</div>
<?php require APP_ROOT . '/templates/partials/form/jury-fieldset.php'; ?>
<!-- Année -->
<div class="admin-form-row">
<label class="admin-label" for="année">Année :</label>
<input class="admin-input" type="number" id="année" name="année"
min="2000" max="<?= date('Y') + 1 ?>"
placeholder="<?= date('Y') ?>"
value="<?= old('année') ?>" required>
</div>
<!-- Orientation -->
<div class="admin-form-row">
<label class="admin-label" for="orientation">Orientation :</label>
<select class="admin-select" id="orientation" name="orientation" required>
<option value=""></option>
<?php foreach ($orientations as $o): ?>
<option value="<?= htmlspecialchars($o['id']) ?>"
<?= wasSelected('orientation', $o['id']) ? 'selected' : '' ?>>
<?= htmlspecialchars($o['name']) ?>
</option>
<?php endforeach; ?>
</select>
</div>
<!-- AP -->
<div class="admin-form-row">
<label class="admin-label" for="ap">Atelier pluridisciplinaire :</label>
<select class="admin-select" id="ap" name="ap" required>
<option value=""></option>
<?php foreach ($apPrograms as $ap): ?>
<option value="<?= htmlspecialchars($ap['id']) ?>"
<?= wasSelected('ap', $ap['id']) ? 'selected' : '' ?>>
<?= htmlspecialchars($ap['name']) ?><?php if ($ap['code']): ?> (<?= htmlspecialchars($ap['code']) ?>)<?php endif; ?>
</option>
<?php endforeach; ?>
</select>
</div>
<!-- Finalité -->
<div class="admin-form-row">
<label class="admin-label" for="finality">Finalité du master :</label>
<select class="admin-select" id="finality" name="finality" required>
<option value=""></option>
<?php foreach ($finalityTypes as $f): ?>
<option value="<?= htmlspecialchars($f['id']) ?>"
<?= wasSelected('finality', $f['id']) ? 'selected' : '' ?>>
<?= htmlspecialchars($f['name']) ?>
</option>
<?php endforeach; ?>
</select>
</div>
<!-- Langue(s) -->
<div class="admin-form-row">
<label class="admin-label">Langue(s) :</label>
<div class="admin-checkbox-list">
<?php foreach ($languages as $lang): ?>
<label class="admin-checkbox-label">
<input type="checkbox" name="languages[]"
value="<?= htmlspecialchars($lang['id']) ?>"
<?= wasSelected('languages', $lang['id']) ? 'checked' : '' ?>>
<?= htmlspecialchars($lang['name']) ?>
</label>
<?php endforeach; ?>
</div>
</div>
<!-- Format(s) -->
<div class="admin-form-row">
<label class="admin-label">Format(s) :</label>
<div class="admin-checkbox-list">
<?php foreach ($formatTypes as $fmt): ?>
<label class="admin-checkbox-label">
<input type="checkbox" name="formats[]"
value="<?= htmlspecialchars($fmt['id']) ?>"
<?= wasSelected('formats', $fmt['id']) ? 'checked' : '' ?>>
<?= htmlspecialchars($fmt['name']) ?>
</label>
<?php endforeach; ?>
</div>
</div>
<!-- Mots-clés -->
<div class="admin-form-row">
<label class="admin-label" for="tag">Mots-clés :</label>
<div>
<input class="admin-input" type="text" id="tag" name="tag"
placeholder="sociologie, anthropologie, ..."
value="<?= old('tag') ?>">
<small>Séparez par des virgules. Max 10 mots-clés.</small>
</div>
</div>
<!-- Synopsis -->
<div class="admin-form-row">
<label class="admin-label" for="synopsis">Synopsis :</label>
<textarea class="admin-textarea" id="synopsis" name="synopsis"
rows="7" required><?= old('synopsis') ?></textarea>
</div>
<!-- Licence -->
<div class="admin-form-row">
<label class="admin-label" for="license_id">Licence :</label>
<select class="admin-select" id="license_id" name="license_id">
<option value="">— Inconnue —</option>
<?php foreach ($licenseTypes as $lt): ?>
<option value="<?= htmlspecialchars($lt['id']) ?>"
<?= wasSelected('license_id', $lt['id']) ? 'selected' : '' ?>>
<?= htmlspecialchars($lt['name']) ?>
</option>
<?php endforeach; ?>
</select>
</div>
<!-- Durée/Taille -->
<div class="admin-form-row">
<label class="admin-label" for="duration_info">Durée / Taille :</label>
<div>
<input class="admin-input" type="text" id="duration_info" name="duration_info"
placeholder="Ex : 84 pages"
value="<?= old('duration_info') ?>">
<small>Durée (minutes) ou nombre de pages.</small>
</div>
</div>
<!-- Lien -->
<div class="admin-form-row">
<label class="admin-label" for="lien">Lien (site / ressource) :</label>
<input class="admin-input" type="url" id="lien" name="lien"
placeholder="https://..."
value="<?= old('lien') ?>">
</div>
<!-- Image couverture -->
<div class="admin-form-row">
<label class="admin-label">Image de couverture :</label>
<div class="admin-file-input">
<input type="file" id="couverture" name="couverture" accept="image/jpeg,image/png">
<small>JPG, PNG. Taille max : 10 MB.</small>
</div>
</div>
<!-- Image bannière -->
<div class="admin-form-row">
<label class="admin-label">Image bannière (accueil) :</label>
<div class="admin-file-input">
<input type="file" id="banner" name="banner" accept="image/jpeg,image/png,image/webp">
<small>JPG, PNG ou WEBP. Format paysage recommandé (4:1). Max 5 MB.</small>
</div>
</div>
<!-- Fichiers -->
<div class="admin-form-row">
<label class="admin-label">Fichiers du TFE :</label>
<div class="admin-file-input">
<input type="file" id="files" name="files[]" multiple
accept=".pdf,.jpg,.jpeg,.png,.mp4,.zip">
<small>PDF, JPG, PNG, MP4, ZIP. Max 50 MB par fichier.</small>
</div>
</div>
<div class="admin-submit-wrap">
<button type="submit" name="go" class="admin-btn">Soumettre</button>
</div>
</form>
</main>
<?php require_once APP_ROOT . '/templates/admin/footer.php'; ?>