Files
percovitrine/form.php
T

245 lines
11 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
require __DIR__ . '/includes/db.php';
require __DIR__ . '/includes/helpers.php';
require __DIR__ . '/includes/layout.php';
$id = (int)($_GET['id'] ?? 0);
$product = null;
$medias = [];
if ($id) {
$product = $pdo->prepare("SELECT * FROM products WHERE id=?")->execute([$id])
? $pdo->query("SELECT * FROM products WHERE id=$id")->fetch()
: null;
if (!$product) { header('Location: /'); exit; }
$medias = $pdo->query("SELECT * FROM product_media WHERE product_id=$id ORDER BY sort_order")->fetchAll();
}
/* ─── Sauvegarde ─────────────────────────────────────────── */
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$title = trim($_POST['title'] ?? '');
$desc = trim($_POST['desc'] ?? '');
$price = (float)str_replace(',','.',($_POST['price'] ?? 0));
$shipping = (float)str_replace(',','.',($_POST['shipping'] ?? 0));
$sku = trim($_POST['sku'] ?? '');
$cat_id = (int)($_POST['category_id'] ?? 0) ?: null;
$status = $_POST['status'] ?? 'brouillon';
$tags = trim($_POST['tags'] ?? '');
if (!$title) { $error = 'Le titre est obligatoire.'; goto show; }
if ($id) {
$pdo->prepare("UPDATE products SET title=?,description=?,price=?,shipping=?,sku=?,category_id=?,status=?,tags=?,updated_at=CURRENT_TIMESTAMP WHERE id=?")
->execute([$title,$desc,$price,$shipping,$sku,$cat_id,$status,$tags,$id]);
} else {
$pdo->prepare("INSERT INTO products (title,description,price,shipping,sku,category_id,status,tags) VALUES(?,?,?,?,?,?,?,?)")
->execute([$title,$desc,$price,$shipping,$sku,$cat_id,$status,$tags]);
$id = (int)$pdo->lastInsertId();
}
// Uploads médias
if (!empty($_FILES['medias']['name'][0])) {
$count = count($_FILES['medias']['name']);
for ($i = 0; $i < $count; $i++) {
if ($_FILES['medias']['error'][$i] !== UPLOAD_ERR_OK) continue;
$orig = $_FILES['medias']['name'][$i];
$ext = strtolower(pathinfo($orig, PATHINFO_EXTENSION));
if (!in_array($ext, array_merge(imgExts(), vidExts()))) continue;
$fname = uniqid('m', true) . '.' . $ext;
if (!move_uploaded_file($_FILES['medias']['tmp_name'][$i], $UPLOAD_DIR . $fname)) continue;
$type = isImage($fname) ? 'image' : 'video';
$order = (int)$pdo->query("SELECT COALESCE(MAX(sort_order),0)+1 FROM product_media WHERE product_id=$id")->fetchColumn();
$pdo->prepare("INSERT INTO product_media (product_id,type,filename,original_name,sort_order) VALUES(?,?,?,?,?)")
->execute([$id,$type,$fname,$orig,$order]);
}
}
// Suppression médias cochés
if (!empty($_POST['del_media'])) {
foreach ($_POST['del_media'] as $mid) {
$mid = (int)$mid;
$m = $pdo->query("SELECT filename FROM product_media WHERE id=$mid")->fetch();
if ($m && $m['filename']) @unlink($UPLOAD_DIR . $m['filename']);
$pdo->prepare("DELETE FROM product_media WHERE id=?")->execute([$mid]);
}
}
header('Location: /produit.php?id=' . $id);
exit;
}
show:
$cats = $pdo->query("SELECT * FROM categories ORDER BY name")->fetchAll();
$pageTitle = $id ? 'Modifier le produit' : 'Nouveau produit';
layout_head($pageTitle);
layout_sidebar($id ? '' : 'products');
layout_main_open();
?>
<div class="page-header">
<div>
<div class="page-title"><?= $id ? 'Modifier' : 'Nouveau produit' ?></div>
<?php if ($id): ?><div class="page-sub"><a href="/produit.php?id=<?= $id ?>" style="color:var(--muted);text-decoration:none">← Retour au produit</a></div><?php endif ?>
</div>
</div>
<?php if (!empty($error)): ?><div style="background:rgba(239,68,68,.1);border:1px solid rgba(239,68,68,.3);padding:.75rem 1rem;border-radius:8px;margin-bottom:1rem;color:var(--red)"><?= h($error) ?></div><?php endif ?>
<form method="post" enctype="multipart/form-data">
<div style="display:grid;grid-template-columns:1fr 360px;gap:1.5rem;align-items:start">
<!-- Colonne gauche -->
<div style="display:flex;flex-direction:column;gap:1rem">
<div class="card">
<div class="form-group">
<label>Titre *</label>
<input type="text" name="title" value="<?= h($product['title'] ?? '') ?>" placeholder="Nom du produit" required>
</div>
<div class="form-group" style="margin-bottom:0">
<label>Description</label>
<textarea name="desc" rows="8" placeholder="Décrivez votre produit (sera envoyé sur Etsy)…"><?= h($product['description'] ?? '') ?></textarea>
</div>
</div>
<div class="card">
<div style="font-size:.85rem;font-weight:700;color:var(--muted);text-transform:uppercase;letter-spacing:.05em;margin-bottom:.75rem"><i class="fas fa-images" style="margin-right:.4rem"></i>Photos & vidéos</div>
<?php if ($medias): ?>
<div class="media-grid" id="mediaGrid" style="margin-bottom:1rem">
<?php foreach ($medias as $m): ?>
<div class="media-item<?= $m['type']==='video'?' video-item':'' ?>" data-id="<?= $m['id'] ?>">
<?php if ($m['filename']): ?>
<?php if ($m['type']==='image'): ?>
<img src="/file.php?f=<?= urlencode($m['filename']) ?>" alt="">
<?php else: ?>
<video src="/file.php?f=<?= urlencode($m['filename']) ?>" muted playsinline></video>
<?php endif ?>
<?php elseif ($m['video_url']): ?>
<div style="width:100%;height:100%;display:flex;align-items:center;justify-content:center;padding:.5rem;font-size:.7rem;word-break:break-all;color:var(--muted)"><?= h($m['video_url']) ?></div>
<?php endif ?>
<span class="sort-handle" title="Drag pour réordonner"><i class="fas fa-grip-vertical"></i></span>
<label style="all:unset"><input type="checkbox" name="del_media[]" value="<?= $m['id'] ?>" style="position:absolute;top:4px;right:4px;cursor:pointer;width:16px;height:16px" title="Supprimer ce média"></label>
</div>
<?php endforeach ?>
</div>
<p class="form-hint" style="margin-bottom:.75rem"><i class="fas fa-square-check" style="margin-right:.3rem"></i>Cocher un média pour le supprimer à la sauvegarde</p>
<?php endif ?>
<div class="drop-zone" id="dropZone">
<input type="file" name="medias[]" multiple accept="image/*,video/mp4,video/webm,video/quicktime" id="fileInput">
<i class="fas fa-cloud-arrow-up" style="font-size:1.5rem;margin-bottom:.5rem;display:block"></i>
<strong>Cliquer ou glisser</strong> des images / vidéos<br>
<span style="font-size:.75rem">JPG, PNG, WEBP, AVIF, GIF, MP4, WEBM, MOV</span>
</div>
<div class="preview-strip" id="previewStrip"></div>
</div>
</div>
<!-- Colonne droite -->
<div style="display:flex;flex-direction:column;gap:1rem">
<div class="card">
<div style="font-size:.85rem;font-weight:700;color:var(--muted);text-transform:uppercase;letter-spacing:.05em;margin-bottom:.75rem"><i class="fas fa-euro-sign" style="margin-right:.4rem"></i>Prix</div>
<div class="form-row">
<div class="form-group" style="margin-bottom:0">
<label>Prix de vente</label>
<div class="input-group">
<span class="input-prefix">€</span>
<input type="number" name="price" value="<?= h((string)($product['price'] ?? '0')) ?>" step="0.01" min="0" placeholder="0.00">
</div>
</div>
<div class="form-group" style="margin-bottom:0">
<label>Frais de port</label>
<div class="input-group">
<span class="input-prefix">€</span>
<input type="number" name="shipping" value="<?= h((string)($product['shipping'] ?? '0')) ?>" step="0.01" min="0" placeholder="0.00">
</div>
</div>
</div>
</div>
<div class="card">
<div style="font-size:.85rem;font-weight:700;color:var(--muted);text-transform:uppercase;letter-spacing:.05em;margin-bottom:.75rem"><i class="fas fa-layer-group" style="margin-right:.4rem"></i>Organisation</div>
<div class="form-group">
<label>Statut</label>
<select name="status">
<?php foreach (['brouillon'=>'Brouillon','prêt'=>'Prêt à publier','publié'=>'Publié'] as $v=>$l): ?>
<option value="<?= $v ?>"<?= ($product['status']??'brouillon')===$v?' selected':'' ?>><?= $l ?></option>
<?php endforeach ?>
</select>
</div>
<div class="form-group">
<label>Catégorie</label>
<select name="category_id">
<option value="">— Aucune —</option>
<?php foreach ($cats as $c): ?>
<option value="<?= $c['id'] ?>"<?= ($product['category_id']??'')==$c['id']?' selected':'' ?>><?= h($c['name']) ?></option>
<?php endforeach ?>
</select>
<div class="form-hint">Gérer les catégories dans <a href="/categories.php" style="color:var(--primary)">Catégories</a></div>
</div>
<div class="form-group">
<label>Référence / SKU</label>
<input type="text" name="sku" value="<?= h($product['sku'] ?? '') ?>" placeholder="REF-001">
</div>
<div class="form-group" style="margin-bottom:0">
<label>Tags <span style="font-weight:400;text-transform:none">(séparés par des virgules)</span></label>
<input type="text" name="tags" value="<?= h($product['tags'] ?? '') ?>" placeholder="artisanat, fait main, cadeau…">
<div class="form-hint">Les tags seront utilisés lors de la publication Etsy</div>
</div>
</div>
<?php if ($id && ($product['etsy_listing_id'] ?? '')): ?>
<div class="etsy-panel">
<div class="etsy-logo"><i class="fab fa-etsy"></i> Etsy</div>
<div class="mt-2 etsy-status-ok"><i class="fas fa-check-circle"></i> Publié — ID <?= h($product['etsy_listing_id']) ?></div>
</div>
<?php endif ?>
<div style="display:flex;gap:.75rem">
<button type="submit" class="btn btn-primary" style="flex:1"><i class="fas fa-save"></i> Sauvegarder</button>
<a href="<?= $id ? '/produit.php?id='.$id : '/' ?>" class="btn btn-secondary"><i class="fas fa-xmark"></i></a>
</div>
</div>
</div><!-- /grid -->
</form>
<script>
// Preview médias avant upload
const input = document.getElementById('fileInput');
const strip = document.getElementById('previewStrip');
const drop = document.getElementById('dropZone');
let files = [];
function addFiles(newFiles) {
[...newFiles].forEach(f => {
files.push(f);
const div = document.createElement('div');
div.className = 'preview-item';
const rm = document.createElement('button');
rm.type = 'button'; rm.className = 'rm'; rm.innerHTML = '×';
rm.onclick = () => { files = files.filter(x=>x!==f); div.remove(); syncInput(); };
const tag = f.type.startsWith('image') ? document.createElement('img') : document.createElement('video');
tag.src = URL.createObjectURL(f);
if (!f.type.startsWith('image')) { tag.muted = true; tag.loop = true; tag.autoplay = true; }
div.appendChild(tag); div.appendChild(rm); strip.appendChild(div);
});
syncInput();
}
function syncInput() {
const dt = new DataTransfer();
files.forEach(f => dt.items.add(f));
input.files = dt.files;
}
input.addEventListener('change', () => { addFiles(input.files); });
drop.addEventListener('dragover', e => { e.preventDefault(); drop.classList.add('drag-over'); });
drop.addEventListener('dragleave', () => drop.classList.remove('drag-over'));
drop.addEventListener('drop', e => { e.preventDefault(); drop.classList.remove('drag-over'); addFiles(e.dataTransfer.files); });
</script>
<?php layout_foot(); ?>