718 lines
24 KiB
PHP
718 lines
24 KiB
PHP
<?php
|
||
ini_set('display_errors', 1);
|
||
error_reporting(E_ALL);
|
||
session_start();
|
||
|
||
$db = new PDO('sqlite:db.sqlite');
|
||
|
||
$CATEGORIES = [
|
||
"Bricolage",
|
||
"Jardinage",
|
||
"Cuisine",
|
||
"Outils lourds",
|
||
"Matériel événementiel",
|
||
"Transport",
|
||
"Sport",
|
||
"Voyage",
|
||
"Autre"
|
||
];
|
||
|
||
$action = $_GET['action'] ?? 'home';
|
||
|
||
function redirect($a) {
|
||
header("Location: index.php?action=$a");
|
||
exit;
|
||
}
|
||
|
||
function is_logged() {
|
||
return isset($_SESSION['owner_id']);
|
||
}
|
||
|
||
/* ============================================================
|
||
TRAITEMENT DES FORMULAIRES
|
||
============================================================ */
|
||
|
||
/* ---------- INSCRIPTION ---------- */
|
||
if ($action === 'do_register' && $_SERVER['REQUEST_METHOD'] === 'POST') {
|
||
try {
|
||
$stmt = $db->prepare("
|
||
INSERT INTO owners (name, address, phone, email, username, password_hash)
|
||
VALUES (?, ?, ?, ?, ?, ?)
|
||
");
|
||
$stmt->execute([
|
||
$_POST['name'],
|
||
$_POST['address'],
|
||
$_POST['phone'],
|
||
$_POST['email'],
|
||
$_POST['username'],
|
||
password_hash($_POST['password'], PASSWORD_DEFAULT)
|
||
]);
|
||
|
||
$_SESSION['owner_id'] = $db->lastInsertId();
|
||
redirect('edit');
|
||
|
||
} catch (PDOException $e) {
|
||
$error = "Nom d'utilisateur déjà pris.";
|
||
$action = 'register';
|
||
}
|
||
}
|
||
|
||
/* ---------- CONNEXION ---------- */
|
||
if ($action === 'do_login' && $_SERVER['REQUEST_METHOD'] === 'POST') {
|
||
$stmt = $db->prepare("SELECT * FROM owners WHERE username=?");
|
||
$stmt->execute([$_POST['username']]);
|
||
$owner = $stmt->fetch(PDO::FETCH_ASSOC);
|
||
|
||
if ($owner && password_verify($_POST['password'], $owner['password_hash'])) {
|
||
$_SESSION['owner_id'] = $owner['id'];
|
||
redirect('edit');
|
||
} else {
|
||
$error = "Identifiants incorrects.";
|
||
$action = 'login';
|
||
}
|
||
}
|
||
|
||
/* ---------- DÉCONNEXION ---------- */
|
||
if ($action === 'logout') {
|
||
session_destroy();
|
||
redirect('home');
|
||
}
|
||
|
||
/* ---------- SAUVEGARDE MATERIEL (prix numérique + prix libre) ---------- */
|
||
if ($action === 'save_item' && $_SERVER['REQUEST_METHOD'] === 'POST' && is_logged()) {
|
||
|
||
// Prix numérique obligatoire
|
||
$price = floatval($_POST['price']);
|
||
if ($price <= 0) {
|
||
$error = "Le prix doit être un nombre positif.";
|
||
$action = 'edit';
|
||
}
|
||
|
||
// Prix libre ?
|
||
$price_free = isset($_POST['price_free']) ? "free" : "";
|
||
$price_value = $price_free ? "$price|free" : "$price";
|
||
|
||
// Upload photo
|
||
$photo = null;
|
||
if (!empty($_FILES['photo']['name'])) {
|
||
$photo = time() . "_" . basename($_FILES['photo']['name']);
|
||
move_uploaded_file($_FILES['photo']['tmp_name'], "uploads/" . $photo);
|
||
}
|
||
|
||
// UPDATE
|
||
if (!empty($_POST['id'])) {
|
||
if ($photo) {
|
||
$stmt = $db->prepare("UPDATE items SET name=?, price=?, description=?, photo=?, category=? WHERE id=? AND owner_id=?");
|
||
$stmt->execute([
|
||
$_POST['name'],
|
||
$price_value,
|
||
$_POST['description'],
|
||
$photo,
|
||
$_POST['category'],
|
||
$_POST['id'],
|
||
$_SESSION['owner_id']
|
||
]);
|
||
} else {
|
||
$stmt = $db->prepare("UPDATE items SET name=?, price=?, description=?, category=? WHERE id=? AND owner_id=?");
|
||
$stmt->execute([
|
||
$_POST['name'],
|
||
$price_value,
|
||
$_POST['description'],
|
||
$_POST['category'],
|
||
$_POST['id'],
|
||
$_SESSION['owner_id']
|
||
]);
|
||
}
|
||
|
||
// INSERT
|
||
} else {
|
||
$stmt = $db->prepare("INSERT INTO items (name, price, description, photo, owner_id, category)
|
||
VALUES (?, ?, ?, ?, ?, ?)");
|
||
$stmt->execute([
|
||
$_POST['name'],
|
||
$price_value,
|
||
$_POST['description'],
|
||
$photo,
|
||
$_SESSION['owner_id'],
|
||
$_POST['category']
|
||
]);
|
||
}
|
||
|
||
redirect('edit');
|
||
}
|
||
|
||
/* ---------- SUPPRESSION MATERIEL ---------- */
|
||
if ($action === 'delete_item' && is_logged()) {
|
||
$stmt = $db->prepare("DELETE FROM items WHERE id=? AND owner_id=?");
|
||
$stmt->execute([$_GET['id'], $_SESSION['owner_id']]);
|
||
redirect('edit');
|
||
}
|
||
|
||
/* ---------- SUPPRESSION PHOTO MATERIEL ---------- */
|
||
if ($action === 'delete_photo' && is_logged()) {
|
||
|
||
// Récupérer le matériel
|
||
$stmt = $db->prepare("SELECT photo FROM items WHERE id=? AND owner_id=?");
|
||
$stmt->execute([$_GET['id'], $_SESSION['owner_id']]);
|
||
$item = $stmt->fetch(PDO::FETCH_ASSOC);
|
||
|
||
if ($item && !empty($item['photo'])) {
|
||
$file = "uploads/" . $item['photo'];
|
||
if (file_exists($file)) {
|
||
unlink($file);
|
||
}
|
||
|
||
// Mettre la colonne photo à NULL
|
||
$stmt = $db->prepare("UPDATE items SET photo=NULL WHERE id=? AND owner_id=?");
|
||
$stmt->execute([$_GET['id'], $_SESSION['owner_id']]);
|
||
}
|
||
|
||
redirect('edit_item&id=' . $_GET['id']);
|
||
}
|
||
|
||
/* ---------- MODIFICATION PROFIL ---------- */
|
||
if ($action === 'save_profile' && $_SERVER['REQUEST_METHOD'] === 'POST' && is_logged()) {
|
||
|
||
$params = [
|
||
$_POST['name'],
|
||
$_POST['address'],
|
||
$_POST['phone'],
|
||
$_POST['email'],
|
||
$_POST['username']
|
||
];
|
||
|
||
$sql = "UPDATE owners SET name=?, address=?, phone=?, email=?, username=?";
|
||
|
||
if (!empty($_POST['password'])) {
|
||
$sql .= ", password_hash=?";
|
||
$params[] = password_hash($_POST['password'], PASSWORD_DEFAULT);
|
||
}
|
||
|
||
$sql .= " WHERE id=?";
|
||
$params[] = $_SESSION['owner_id'];
|
||
|
||
$stmt = $db->prepare($sql);
|
||
$stmt->execute($params);
|
||
|
||
$success = "Profil mis à jour.";
|
||
$action = 'profile';
|
||
}
|
||
?>
|
||
<!DOCTYPE html>
|
||
<html>
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<title>Location de matériel</title>
|
||
<link rel="stylesheet" href="pico.css">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||
<style>
|
||
body { max-width: 900px; margin: 40px auto; }
|
||
.item { padding: 1rem; border: 1px solid #ddd; border-radius: 8px; margin-bottom: 1.5rem; }
|
||
.tool-row { display: flex; gap: 1.5rem; align-items: flex-start; }
|
||
.tool-row img { width: 25%; max-width: 180px; border-radius: 8px; object-fit: cover; }
|
||
.tool-info { flex: 1; }
|
||
.owner-block { margin-top: .5rem; font-size: .9rem; color: #555; }
|
||
</style>
|
||
</head>
|
||
<body style="padding: 0 10px">
|
||
|
||
<h1 style="display:flex; align-items:center; justify-content:space-between;">
|
||
<span>Matériel partagé à Durban-sur-Arize</span>
|
||
<img src="uploads/blason-durban.png" alt="Blason de Durban-sur-Arize"
|
||
style="height:48px; width:auto; margin-left:1rem;">
|
||
</h1>
|
||
|
||
<nav>
|
||
<a href="index.php">Accueil</a>
|
||
<?php if (is_logged()): ?>
|
||
<a href="index.php?action=edit">Mon matériel</a>
|
||
<a href="index.php?action=profile">Mon profil</a>
|
||
<a href="index.php?action=logout">Déconnexion</a>
|
||
<?php else: ?>
|
||
<a href="index.php?action=login">Connexion</a>
|
||
<a href="index.php?action=register">Inscription</a>
|
||
<?php endif; ?>
|
||
</nav>
|
||
|
||
<hr>
|
||
|
||
<?php
|
||
/* ============================================================
|
||
VUE : ACCUEIL (liste publique)
|
||
============================================================ */
|
||
if ($action === 'home') {
|
||
?>
|
||
|
||
<div id="price-customizer" style="
|
||
margin-bottom: 1.2rem;
|
||
padding: .6rem .8rem;
|
||
border: 1px solid var(--pico-muted-border-color);
|
||
border-radius: .5rem;
|
||
font-size: .8rem;
|
||
">
|
||
<form id="income-form" style="
|
||
display: flex;
|
||
align-items: center;
|
||
gap: .4rem;
|
||
flex-wrap: wrap;
|
||
margin: 0;
|
||
">
|
||
<strong>Personnaliser les indications de prix libre</strong>
|
||
<span>selon mon revenu mensuel :</span>
|
||
<input
|
||
type="number"
|
||
id="income"
|
||
value="1900"
|
||
min="0"
|
||
step="1"
|
||
style="width: 110px; margin: 0; height: 0.8rem; font-size: 0.8rem;">
|
||
<span>€/mois</span>
|
||
</form>
|
||
</div>
|
||
|
||
<div style="text-align: justify;"><small>L'objectif du site est de mettre en relation des emprunteur·ses et loueur·ses avec des propriétaires de matériel. Des tarifs peuvent être indiqués, ils restent avant tout indicatifs afin d’éviter les malaises et de poser une base aux discussions. L’essentiel est de privilégier la discussion, la confiance, les arrangements et l'entraide. L'idée n'est pas de faire une grande publicité pour cet outil de partage, mais de le garder à petite échelle, localement, autour de valeurs de solidarité et de proximité. N'hésitez pas à être le plus clair possible dès le début sur les issues d'une casse.</small></div>
|
||
|
||
|
||
<div id="search-tools" style="
|
||
margin: 1.2rem 0;
|
||
padding: .6rem .8rem;
|
||
border: 1px solid var(--pico-muted-border-color);
|
||
border-radius: .5rem;
|
||
font-size: .9rem;
|
||
">
|
||
<form style="display:flex; align-items:center; gap:.6rem; flex-wrap:wrap; margin:0;">
|
||
<strong style="font-size:.95rem;">Rechercher un matériel :</strong>
|
||
<input
|
||
type="text"
|
||
id="search"
|
||
placeholder="Nom ou description…"
|
||
style="flex:1; min-width:200px; margin:0;"
|
||
>
|
||
</form>
|
||
</div>
|
||
|
||
|
||
<?php
|
||
$items = $db->query("
|
||
SELECT items.*, owners.name AS owner_name, owners.phone, owners.address, owners.email
|
||
FROM items
|
||
JOIN owners ON owners.id = items.owner_id
|
||
ORDER BY items.category COLLATE NOCASE ASC,
|
||
items.name COLLATE NOCASE ASC
|
||
")->fetchAll(PDO::FETCH_ASSOC);
|
||
|
||
foreach ($items as $item) {
|
||
|
||
// Décodage du prix
|
||
$price_raw = $item['price'] ?? '';
|
||
$price_parts = explode('|', $price_raw);
|
||
$price_value = floatval($price_parts[0]);
|
||
$price_free = isset($price_parts[1]) && $price_parts[1] === 'free';
|
||
|
||
$search_text = strtolower(
|
||
($item['name'] ?? '') . ' ' . ($item['description'] ?? '')
|
||
);
|
||
|
||
echo "<article class='item' data-search='" . htmlspecialchars($search_text, ENT_QUOTES) . "'>";
|
||
echo "<div class='tool-row'>";
|
||
|
||
// Photo
|
||
if (!empty($item['photo'])) {
|
||
echo "<img src='uploads/{$item['photo']}' alt='Photo'>";
|
||
} else {
|
||
echo "<div style='
|
||
width:25%; max-width: 180px;
|
||
height:120px;
|
||
display:flex;
|
||
align-items:center;
|
||
justify-content:center;
|
||
font-size:60px;
|
||
'>🛠️</div>";
|
||
}
|
||
|
||
echo "<div class='tool-info'>";
|
||
|
||
echo "<h2 style='margin: 0;'>" . htmlspecialchars($item['name'] ?? '') . "</h2>";
|
||
|
||
echo "<p style='opacity:.7; font-size:.85rem;'>Catégorie : " . htmlspecialchars($item['category']) . "</p>";
|
||
|
||
// Prix
|
||
echo "<p class='price-block' data-base-price='{$price_value}' data-free='{$price_free}'>";
|
||
echo "<strong>Prix :</strong> {$price_value} € / jour";
|
||
if ($price_free) echo " <em>(prix libre)</em>";
|
||
echo "</p>";
|
||
|
||
// Description
|
||
echo "<p>" . nl2br(htmlspecialchars($item['description'] ?? '')) . "</p>";
|
||
|
||
// Propriétaire
|
||
echo "<div class='owner-block'>";
|
||
echo "<strong>Propriétaire :</strong> " . htmlspecialchars($item['owner_name'] ?? '') . "<br>";
|
||
|
||
// Adresse
|
||
$addr = urlencode($item['address'] ?? '');
|
||
echo htmlspecialchars($item['address'] ?? '')."<br>";
|
||
|
||
// Téléphone → tel:
|
||
echo "<a href='tel:" . htmlspecialchars($item['phone'] ?? '') . "'>"
|
||
. htmlspecialchars($item['phone'] ?? '')
|
||
. "</a><br>";
|
||
|
||
// Email → mailto:
|
||
echo "<a href='mailto:" . htmlspecialchars($item['email'] ?? '') . "'>"
|
||
. htmlspecialchars($item['email'] ?? '')
|
||
. "</a>";
|
||
|
||
echo "</div>"; // owner-block
|
||
|
||
echo "</div>"; // tool-info
|
||
echo "</div>"; // tool-row
|
||
echo "</article>";
|
||
}
|
||
}
|
||
|
||
/* ============================================================
|
||
VUE : CONNEXION
|
||
============================================================ */
|
||
if ($action === 'login') {
|
||
echo "<h2>Connexion</h2>";
|
||
if (!empty($error)) echo "<p style='color:red'>$error</p>";
|
||
?>
|
||
<form method="post" action="index.php?action=do_login">
|
||
<input name="username" placeholder="Nom d'utilisateur" required>
|
||
<input name="password" type="password" placeholder="Mot de passe" required>
|
||
<button>Connexion</button>
|
||
</form>
|
||
<?php
|
||
}
|
||
|
||
/* ============================================================
|
||
VUE : INSCRIPTION
|
||
============================================================ */
|
||
if ($action === 'register') {
|
||
echo "<h2>Inscription</h2>";
|
||
if (!empty($error)) echo "<p style='color:red'>$error</p>";
|
||
?>
|
||
<form method="post" action="index.php?action=do_register">
|
||
<small>Toutes les coordonnées indiquées ici seront affichées publiquement.<br><br></small>
|
||
<input name="name" placeholder="Nom complet" required>
|
||
<input name="address" placeholder="Commune (éviter une adresse précise)">
|
||
<input name="phone" placeholder="Téléphone">
|
||
<input name="email" placeholder="Email">
|
||
<input name="username" placeholder="Nom d'utilisateur" required>
|
||
<input name="password" type="password" placeholder="Mot de passe" required>
|
||
<button>Créer mon compte</button>
|
||
</form>
|
||
<?php
|
||
}
|
||
|
||
/* ============================================================
|
||
VUE : PROFIL
|
||
============================================================ */
|
||
if ($action === 'profile' && is_logged()) {
|
||
|
||
$stmt = $db->prepare("SELECT * FROM owners WHERE id=?");
|
||
$stmt->execute([$_SESSION['owner_id']]);
|
||
$owner = $stmt->fetch(PDO::FETCH_ASSOC);
|
||
|
||
echo "<h2>Mon profil</h2>";
|
||
|
||
if (!empty($success)) echo "<p style='color:green'>$success</p>";
|
||
|
||
?>
|
||
<form method="post" action="index.php?action=save_profile">
|
||
<small>Toutes les coordonnées indiquées ici seront affichées publiquement.<br><br></small>
|
||
<input name="name" value="<?= htmlspecialchars($owner['name'] ?? '') ?>" placeholder="Nom complet" required>
|
||
<input name="address" value="<?= htmlspecialchars($owner['address'] ?? '') ?>" placeholder="Commune (éviter une adresse précise)">
|
||
<input name="phone" value="<?= htmlspecialchars($owner['phone'] ?? '') ?>" placeholder="Téléphone">
|
||
<input name="email" value="<?= htmlspecialchars($owner['email'] ?? '') ?>" placeholder="Email">
|
||
<input name="username" value="<?= htmlspecialchars($owner['username'] ?? '') ?>" placeholder="Nom d'utilisateur" required>
|
||
<input name="password" type="password" placeholder="Nouveau mot de passe (laisser vide)">
|
||
<button>Mettre à jour</button>
|
||
</form>
|
||
<?php
|
||
}
|
||
|
||
/* ============================================================
|
||
VUE : ÉDITION D’UN MATERIEL
|
||
============================================================ */
|
||
if ($action === 'edit_item' && is_logged()) {
|
||
|
||
$stmt = $db->prepare("SELECT * FROM items WHERE id=? AND owner_id=?");
|
||
$stmt->execute([$_GET['id'], $_SESSION['owner_id']]);
|
||
$item = $stmt->fetch(PDO::FETCH_ASSOC);
|
||
|
||
if (!$item) {
|
||
echo "<p>Matériel introuvable.</p>";
|
||
} else {
|
||
|
||
// Décodage du prix
|
||
$price_raw = $item['price'] ?? '';
|
||
$price_parts = explode('|', $price_raw);
|
||
$price_value = floatval($price_parts[0]);
|
||
$price_free = isset($price_parts[1]) && $price_parts[1] === 'free';
|
||
|
||
echo "<h2>Modifier le matériel</h2>";
|
||
?>
|
||
|
||
<form method="post" enctype="multipart/form-data" action="index.php?action=save_item">
|
||
<input type="hidden" name="id" value="<?= $item['id'] ?>">
|
||
|
||
<label>Nom du matériel</label>
|
||
<input name="name" value="<?= htmlspecialchars($item['name']) ?>" required>
|
||
|
||
<label>Prix par jour (€)</label>
|
||
<input name="price" type="number" step="0.01" min="0"
|
||
value="<?= $price_value ?>" required>
|
||
|
||
<p style="font-size:.85rem; opacity:.8;">
|
||
Le prix libre conseillé sera automatiquement ajusté selon le revenu de l’utilisateur.
|
||
</p>
|
||
|
||
<label>
|
||
<input type="checkbox" name="price_free" <?= $price_free ? 'checked' : '' ?>>
|
||
Prix libre (le prix devient indicatif)
|
||
</label>
|
||
|
||
<label>Catégorie</label>
|
||
<select name="category" required>
|
||
<option value="">Choisir…</option>
|
||
<?php foreach ($CATEGORIES as $cat): ?>
|
||
<option value="<?= htmlspecialchars($cat) ?>"
|
||
<?= ($item['category'] === $cat ? 'selected' : '') ?>>
|
||
<?= htmlspecialchars($cat) ?>
|
||
</option>
|
||
<?php endforeach; ?>
|
||
</select>
|
||
|
||
<label>Description</label>
|
||
<textarea name="description"><?= htmlspecialchars($item['description']) ?></textarea>
|
||
|
||
<label>Photo actuelle</label><br>
|
||
<?php if ($item['photo']): ?>
|
||
<img src="uploads/<?= $item['photo'] ?>" style="max-width:150px;border-radius:6px;">
|
||
|
||
<br>
|
||
|
||
<a href="index.php?action=delete_photo&id=<?= $item['id'] ?>"
|
||
onclick="return confirm('Supprimer cette photo ?')"
|
||
style="font-size:.85rem; color:var(--pico-del-color);">
|
||
Supprimer la photo
|
||
</a>
|
||
<?php else: ?>
|
||
<div style='
|
||
width:150px;
|
||
height:100px;
|
||
display:flex;
|
||
align-items:center;
|
||
justify-content:center;
|
||
font-size:50px;
|
||
'>🛠️</div>
|
||
<?php endif; ?>
|
||
<br><br>
|
||
|
||
<label>Nouvelle photo (optionnel)</label>
|
||
<input type="file" name="photo">
|
||
|
||
<button>Mettre à jour</button>
|
||
</form>
|
||
|
||
<?php
|
||
}
|
||
}
|
||
|
||
/* ============================================================
|
||
VUE : GESTION DES MATERIELS
|
||
============================================================ */
|
||
if ($action === 'edit' && is_logged()) {
|
||
|
||
echo "<h2>Mes matériels</h2>";
|
||
|
||
?>
|
||
<h3 style="cursor:pointer;" id="toggle-form">➕ Ajouter un matériel</h3>
|
||
<div id="tool-form" style="display:none; margin-bottom:2rem;">
|
||
<form method="post" enctype="multipart/form-data" action="index.php?action=save_item">
|
||
<input type="hidden" name="id">
|
||
|
||
<label>Nom du matériel</label>
|
||
<input name="name" placeholder="Nom" required>
|
||
|
||
<label>Prix par jour (€)</label>
|
||
<input name="price" type="number" step="0.01" min="0" placeholder="Prix" required>
|
||
|
||
<p style="font-size:.85rem; opacity:.8;">
|
||
Le prix libre conseillé sera automatiquement ajusté selon le revenu de l’utilisateur.
|
||
</p>
|
||
|
||
<label>
|
||
<input type="checkbox" name="price_free">
|
||
Prix libre (le prix devient indicatif)
|
||
</label>
|
||
|
||
<label>Catégorie</label>
|
||
<select name="category" required>
|
||
<option value="">Choisir…</option>
|
||
<?php foreach ($CATEGORIES as $cat): ?>
|
||
<option value="<?= htmlspecialchars($cat) ?>"><?= htmlspecialchars($cat) ?></option>
|
||
<?php endforeach; ?>
|
||
</select>
|
||
|
||
<label>Description</label>
|
||
<textarea name="description" placeholder="Description"></textarea>
|
||
|
||
<label>Photo</label>
|
||
<input type="file" name="photo">
|
||
|
||
<button>Enregistrer</button>
|
||
</form>
|
||
</div>
|
||
<?php
|
||
|
||
/* Liste des matériels existants */
|
||
$stmt = $db->prepare("SELECT * FROM items WHERE owner_id=? ORDER BY category COLLATE NOCASE ASC,
|
||
name COLLATE NOCASE ASC
|
||
");
|
||
$stmt->execute([$_SESSION['owner_id']]);
|
||
$items = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||
|
||
echo "<h3>Mes matériels existants</h3>";
|
||
|
||
foreach ($items as $item) {
|
||
|
||
// Décodage du prix
|
||
$price_raw = $item['price'] ?? '';
|
||
$price_parts = explode('|', $price_raw);
|
||
$price_value = floatval($price_parts[0]);
|
||
$price_free = isset($price_parts[1]) && $price_parts[1] === 'free';
|
||
|
||
echo "<article class='item'>";
|
||
echo "<div class='tool-row'>";
|
||
|
||
// Photo
|
||
if (!empty($item['photo'])) {
|
||
echo "<img src='uploads/{$item['photo']}' alt='Photo'>";
|
||
} else {
|
||
echo "<div style='
|
||
width:25%; max-width: 180px;
|
||
height:120px;
|
||
display:flex;
|
||
align-items:center;
|
||
justify-content:center;
|
||
font-size:60px;
|
||
'>🛠️</div>";
|
||
}
|
||
|
||
echo "<div class='tool-info'>";
|
||
echo "<h3 style='margin: 0;'>" . htmlspecialchars($item['name'] ?? '') . "</h3>";
|
||
|
||
echo "<p style='opacity:.7; font-size:.85rem;'>Catégorie : " . htmlspecialchars($item['category']) . "</p>";
|
||
|
||
echo "<p><strong>Prix :</strong> {$price_value} € / jour";
|
||
if ($price_free) echo " <em>(prix libre)</em>";
|
||
echo "</p>";
|
||
|
||
echo "<p>" . nl2br(htmlspecialchars($item['description'] ?? '')) . "</p>";
|
||
|
||
echo "<footer>";
|
||
echo "<a href='index.php?action=edit_item&id={$item['id']}'>Modifier</a> | ";
|
||
echo "<a href='index.php?action=delete_item&id={$item['id']}' onclick='return confirm(\"Supprimer ce matériel ?\")'>Supprimer</a>";
|
||
echo "</footer>";
|
||
|
||
|
||
echo "</div>"; // tool-info
|
||
echo "</div>"; // tool-row
|
||
echo "</article>";
|
||
}
|
||
}
|
||
?>
|
||
|
||
<script>
|
||
// -----------------------------
|
||
// Recalcul des prix libres
|
||
// -----------------------------
|
||
function updateFreePrices() {
|
||
const incomeInput = document.getElementById('income');
|
||
if (!incomeInput) return; // Pas de champ -> rien à faire
|
||
|
||
const income = parseFloat(incomeInput.value) || 1900;
|
||
const ratio = income / 1900;
|
||
|
||
document.querySelectorAll('.price-block').forEach(block => {
|
||
const base = parseFloat(block.dataset.basePrice);
|
||
const isFree = block.dataset.free === "1" || block.dataset.free === "true";
|
||
|
||
if (!isFree) return;
|
||
|
||
const newPrice = (base * ratio).toFixed(2);
|
||
block.innerHTML = `<strong>Prix :</strong> ${newPrice} € / jour <em>(prix libre)</em>`;
|
||
});
|
||
}
|
||
|
||
// Mise à jour en direct si le champ existe
|
||
const incomeInput = document.getElementById('income');
|
||
if (incomeInput) {
|
||
incomeInput.addEventListener('input', updateFreePrices);
|
||
updateFreePrices(); // Mise à jour initiale
|
||
}
|
||
|
||
// Empêcher Enter dans le formulaire income
|
||
const incomeForm = document.getElementById('income-form');
|
||
if (incomeForm) {
|
||
incomeForm.addEventListener('keydown', function (e) {
|
||
if (e.key === "Enter") e.preventDefault();
|
||
});
|
||
}
|
||
|
||
|
||
// -----------------------------
|
||
// Recherche dynamique
|
||
// -----------------------------
|
||
function updateSearch() {
|
||
const searchInput = document.getElementById('search');
|
||
if (!searchInput) return;
|
||
|
||
const query = searchInput.value.toLowerCase().trim();
|
||
const words = query.split(/\s+/).filter(w => w.length > 0);
|
||
|
||
document.querySelectorAll('article.item').forEach(item => {
|
||
const text = item.dataset.search || "";
|
||
const match = words.every(w => text.includes(w));
|
||
item.style.display = match ? "" : "none";
|
||
});
|
||
}
|
||
|
||
const searchInput = document.getElementById('search');
|
||
if (searchInput) {
|
||
searchInput.addEventListener('input', updateSearch);
|
||
|
||
searchInput.addEventListener('keydown', function (e) {
|
||
if (e.key === "Enter") e.preventDefault();
|
||
});
|
||
}
|
||
|
||
|
||
// -----------------------------
|
||
// Dépliage du formulaire matériel
|
||
// -----------------------------
|
||
const toggleForm = document.getElementById('toggle-form');
|
||
const toolForm = document.getElementById('tool-form');
|
||
|
||
if (toggleForm && toolForm) {
|
||
toggleForm.addEventListener('click', function () {
|
||
toolForm.style.display =
|
||
(toolForm.style.display === "none" || toolForm.style.display === "")
|
||
? "block"
|
||
: "none";
|
||
});
|
||
}
|
||
|
||
</script>
|
||
|
||
<footer style="margin-top:2rem; text-align:center; opacity:.7; font-size:.85rem;">
|
||
Problème ou question :
|
||
<a href="mailto:leo@kabano.org">Léo / leo@kabano.org</a>
|
||
</footer>
|
||
|
||
</body>
|
||
</html>
|