231 Dhs
XERIAL Peel est un soin exfoliant conçu pour les pieds secs, rugueux et présentant des callosités. Ce masque chaussette unique exfolie et hydrate en profondeur, ciblant les zones épaissies tout en préservant les zones sensibles. Sa formule enrichie en actifs kératolytiques et émollients transforme les pieds en une peau douce et soyeuse.
Prenez en photo ou scannez votre ordonnance, puis envoyez-la nous sur WhatsApp.
Vous avez jusqu'à 7 jours à compter de la date de livraison pour retourner gratuitement vos produits non ouverts et non endommagés, sans aucun frais supplémentaire — avec un échange ou un remboursement total ou partiel, selon votre choix.
Tous nos produits sont 100% authentiques et originaux, achetés directement auprès des laboratoires et distributeurs officiels.
Aucune contrefaçon, aucun produit reconditionné.
Non, nous sommes 100% digital — pas de point de vente physique ni de click & collect.
Tout se passe en ligne, depuis notre siège à Casablanca (Val Fleurie), avec livraison partout au Maroc.
Si vous rencontrez un souci avec votre commande ou un produit, merci de nous envoyer un email détaillant votre réclamation à l'adresse ci-dessous. Notre équipe vous répondra dans les meilleurs délais.
'); } return w; } catch (e) { return null; } } function openOverlay(){ document.getElementById('pcv-wa-overlay').classList.add('active'); document.getElementById('pcv-wa-backdrop').classList.add('active'); showView('main'); } function closeOverlay(){ document.getElementById('pcv-wa-overlay').classList.remove('active'); document.getElementById('pcv-wa-backdrop').classList.remove('active'); } function updateScrollHint(){ var body = document.querySelector('.pcv-wa-body'); var hint = document.querySelector('.pcv-wa-scroll-hint'); if (!body || !hint) return; var canScroll = body.scrollHeight > body.clientHeight + 4; var atBottom = body.scrollTop + body.clientHeight >= body.scrollHeight - 4; hint.classList.toggle('visible', canScroll && !atBottom); } var currentView = 'main'; function showView(name){ currentView = name; document.querySelectorAll('.pcv-wa-view').forEach(function(v){ v.classList.remove('active'); }); document.querySelector('.pcv-wa-view[data-view="'+name+'"]').classList.add('active');var header = document.getElementById('pcv-wa-header'); var backBtn = document.getElementById('pcv-wa-header-back'); if (name === 'main') { header.classList.remove('has-back'); } else { header.classList.add('has-back'); backBtn.onclick = function(){ showView(parentView[name] || 'main'); }; }var body = document.querySelector('.pcv-wa-body'); body.scrollTop = 0; setTimeout(updateScrollHint, 30); } document.querySelector('.pcv-wa-body').addEventListener('scroll', updateScrollHint); window.addEventListener('resize', updateScrollHint);document.getElementById('pcv-wa-btn').addEventListener('click', function(e){ e.preventDefault(); openOverlay(); }); document.querySelector('.pcv-wa-close').addEventListener('click', closeOverlay); document.getElementById('pcv-wa-backdrop').addEventListener('click', closeOverlay);// Affiche directement prix + stock dès l'ouverture du sous-menu produit (pas besoin de cliquer) function renderProduitInfo(){ var priceBox = document.getElementById('pcv-price-box'); if (isProduct && productPrice) { var priceHtml = (onSale && regularPrice) ? '' + regularPrice + '' + productPrice + '' : '' + productPrice + ''; priceBox.innerHTML = '
Le prix est de :
'; } else { priceBox.innerHTML = '
Merci de vous rendre sur la page du produit qui vous intéresse pour voir son prix ici.
'; }var stockBox = document.getElementById('pcv-stock-box'); var badge; if (isProduct && stockState === 'rupture') { badge = '
'; } else if (isProduct && (stockState === 'faible' || stockState === 'critique')) { badge = '
'; } else if (isProduct && stockState === 'ok') { badge = '
'; } if (isProduct && badge) { stockBox.innerHTML = '
État du stock :
' + badge; } else { stockBox.innerHTML = '
Merci de vous rendre sur la page du produit qui vous intéresse pour voir sa disponibilité ici.
'; } }document.getElementById('pcv-opt-produit-menu').addEventListener('click', function(){ renderProduitInfo(); showView('produit-menu'); });// Autre question produit (avec prix) document.getElementById('pcv-opt-produit').addEventListener('click', function(){ var link = isProduct ? window.location.href : prompt('Lien du produit concerné ?'); if (!link) return; // vide OU annulé var priceTxt = (isProduct && productPrice) ? (' (Prix : ' + productPrice + ')') : ''; sendWA('Bonjour, j\'ai une question concernant ce produit' + priceTxt + ' : ' + link); closeOverlay(); });// Livraison / paiement / authenticité / point de vente / réclamation (info, pas de message) document.getElementById('pcv-opt-livraison').addEventListener('click', function(){ showView('delivery'); }); document.getElementById('pcv-opt-paiement').addEventListener('click', function(){ showView('paiement'); }); document.getElementById('pcv-opt-authenticite').addEventListener('click', function(){ showView('authenticite'); }); document.getElementById('pcv-opt-pointvente').addEventListener('click', function(){ showView('pointvente'); }); document.getElementById('pcv-opt-reclamation-menu').addEventListener('click', function(){ showView('reclamation'); }); document.getElementById('pcv-opt-ordonnance').addEventListener('click', function(){ showView('ordonnance'); });// Remises / codes promo (info, pas de message) document.getElementById('pcv-opt-promo').addEventListener('click', function(){ var box = document.getElementById('pcv-promo-box'); box.innerHTML = '
' + '
Nous n\'avons pas de code promo à offrir en général — mais on a mieux :
' + '
';
showView('promo');
});// Question commande (format N + numéro) — annuler = on n'envoie rien
document.getElementById('pcv-opt-commande').addEventListener('click', function(){
var num = prompt('Numéro de commande (laissez vide si vous ne l\'avez pas) :');
if (num === null) return;
num = num.trim();
var text = num
? 'Bonjour, j\'ai une question concernant ma commande N' + num
: 'Bonjour, j\'ai une question concernant une de mes commandes (je n\'ai pas le numéro sous la main).';
sendWA(text);
closeOverlay();
});// Retour / Annulation - sous-menu
document.getElementById('pcv-opt-retour').addEventListener('click', function(){
showView('retour');
});
document.querySelectorAll('[data-retour]').forEach(function(el){
el.addEventListener('click', function(){
var action = el.getAttribute('data-retour');
var num = prompt('Numéro de la commande concernée (laissez vide si vous ne l\'avez pas) :');
if (num === null) return;
num = num.trim();
var text = 'Bonjour, je souhaite ' + action;
text += num ? (', commande N' + num) : ' (je n\'ai pas le numéro de commande sous la main)';
sendWA(text + '.');
closeOverlay();
});
});// ============================================================
// Ordonnance : disclaimer + upload + envoi (partage natif mobile / lien WhatsApp en fallback desktop)
// ============================================================
(function(){
var fileIn = document.getElementById('pcv-ordo-file');
var drop = document.getElementById('pcv-ordo-drop');
var fname = document.getElementById('pcv-ordo-filename');
var prenom = document.getElementById('pcv-ordo-prenom');
var telIn = document.getElementById('pcv-ordo-tel');
var subBtn = document.getElementById('pcv-ordo-submit');
var omsg = document.getElementById('pcv-ordo-msg');
var fnameDefault = 'Choisir un ou plusieurs fichiers';
// Les photos sont compressées côté navigateur avant l'envoi (voir ordoCompressImage), donc on
// tolère des photos brutes assez lourdes à la sélection (ex: photo 12 Mo prise au smartphone) :
// seul le poids APRÈS compression compte vraiment pour le serveur.
var ordoMaxRawSize = 25 * 1024 * 1024;function ordoCheckReady(){
subBtn.disabled = !(fileIn.files && fileIn.files.length);
}fileIn.addEventListener('change', function(){
omsg.className = 'pcv-wa-msg';
omsg.textContent = '';
if (!fileIn.files.length) { fname.textContent = fnameDefault; drop.classList.remove('has-file'); ordoCheckReady(); return; }var files = Array.prototype.slice.call(fileIn.files);if (files.length > ordoMaxFiles) {
omsg.className = 'pcv-wa-msg error';
omsg.textContent = ordoMaxFiles + ' fichiers max en une fois.';
fileIn.value = '';
fname.textContent = fnameDefault;
drop.classList.remove('has-file');
ordoCheckReady();
return;
}var tooBig = files.some(function(f){ return f.size > ordoMaxRawSize; });
if (tooBig) {
omsg.className = 'pcv-wa-msg error';
omsg.textContent = 'Un des fichiers est trop volumineux.';
fileIn.value = '';
fname.textContent = fnameDefault;
drop.classList.remove('has-file');
ordoCheckReady();
return;
}fname.textContent = (files.length === 1) ? files[0].name : (files.length + ' fichiers sélectionnés');
drop.classList.add('has-file');
ordoCheckReady();
});function ordoResetButton(){
subBtn.disabled = false;
subBtn.classList.remove('is-loading');
subBtn.innerHTML = 'Envoyer via WhatsApp';
}// Remet toute la vue à zéro (fichier, champs, message) pour un prochain envoi
function ordoResetForm(){
fileIn.value = '';
fname.textContent = fnameDefault;
drop.classList.remove('has-file');
prenom.value = '';
telIn.value = '';
omsg.className = 'pcv-wa-msg';
omsg.textContent = '';
ordoResetButton();
subBtn.disabled = true;
}function ordoMakeBatchId(){
if (window.crypto && crypto.randomUUID) return crypto.randomUUID();
return 'b' + Date.now() + Math.random().toString(16).slice(2);
}// Compresse une photo côté navigateur avant l'envoi (redimensionnement + ré-encodage JPEG) pour
// alléger fortement l'upload : plus rapide sur mobile, et moins de charge pour le serveur. Une
// photo de smartphone de 4000x3000px / 6-10 Mo devient généralement une image de ~200-500 Ko.
// Les PDF ne sont pas concernés (on les envoie tels quels).
function ordoCompressImage(file){
return new Promise(function(resolve){
if (!file.type || file.type.indexOf('image/') !== 0) { resolve(file); return; }
if (!window.createImageBitmap && !window.Image) { resolve(file); return; }var maxDim = 1600; // largeur/hauteur max - largement suffisant pour lire une ordonnance
var quality = 0.72;
var url = URL.createObjectURL(file);
var img = new Image();img.onload = function(){
URL.revokeObjectURL(url);
try {
var w = img.naturalWidth || img.width;
var h = img.naturalHeight || img.height;
if (!w || !h) { resolve(file); return; }if (w > maxDim || h > maxDim) {
if (w >= h) { h = Math.round(h * (maxDim / w)); w = maxDim; }
else { w = Math.round(w * (maxDim / h)); h = maxDim; }
}var canvas = document.createElement('canvas');
canvas.width = w;
canvas.height = h;
var ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0, w, h);canvas.toBlob(function(blob){
// Si la compression ne fait pas gagner de poids (photo déjà petite/légère), on garde l'original.
if (!blob || blob.size >= file.size) { resolve(file); return; }
var newName = file.name.replace(/\.[^.]+$/, '') + '.jpg';
resolve(new File([blob], newName, { type: 'image/jpeg' }));
}, 'image/jpeg', quality);
} catch (e) {
resolve(file); // en cas de souci (ex: image corrompue), on envoie l'original tel quel
}
};
img.onerror = function(){ URL.revokeObjectURL(url); resolve(file); };
img.src = url;
});
}function uploadOrdonnance(file, batchId){
var fd = new FormData();
fd.append('action', 'pcv_wa_ordo_upload');
fd.append('nonce', ordoNonce);
fd.append('ordonnance', file);
fd.append('prenom', prenom.value.trim());
fd.append('tel', telIn.value.trim());
fd.append('batch_id', batchId);
return fetch(ajaxUrl, { method: 'POST', body: fd })
.then(function(r){
return r.text().then(function(bodyText){
if (!r.ok) {
throw new Error('Serveur a répondu ' + r.status + (bodyText ? (' - ' + bodyText.slice(0, 150)) : ''));
}
try {
return JSON.parse(bodyText);
} catch (parseErr) {
// La réponse n'était pas du JSON propre (souvent un warning/erreur PHP affiché avant) :
// on montre le tout début de la réponse brute pour comprendre pourquoi.
throw new Error('Réponse invalide du serveur - ' + bodyText.slice(0, 150));
}
});
})
.then(function(res){
if (!res || !res.ok) throw new Error((res && res.msg) || 'Échec de l\'envoi (raison inconnue).');
return res.url;
});
}subBtn.addEventListener('click', function(){
if (subBtn.disabled) return;var files = Array.prototype.slice.call(fileIn.files);
if (!files.length) return;// Ouvert tout de suite, de façon synchrone dans le clic, pour ne pas se faire bloquer par le
// navigateur une fois la compression/l'upload (asynchrones) terminés - voir sendWA().
var waWin = pcvOpenWaTab();subBtn.disabled = true;
subBtn.classList.add('is-loading');
subBtn.textContent = files.length > 1 ? 'Envoi en cours (0/' + files.length + ')...' : 'Envoi en cours...';
omsg.className = 'pcv-wa-msg';
omsg.textContent = '';// On upload systématiquement puis on ouvre WhatsApp avec TON numéro pré-rempli (que le client
// ait ou non déjà ce numéro en contact). Le partage natif du téléphone a été retiré : il ne permet
// pas de cibler un numéro précis, il propose juste "choisir une conversation" au client - inutile
// si le client n'a pas déjà ton numéro enregistré.
// Plusieurs fichiers = plusieurs photos/pages d'une même ordonnance : on les envoie un par un
// au serveur (même batch_id pour les regrouper côté admin), puis on met tous les liens dans un
// seul message WhatsApp.
var batchId = ordoMakeBatchId();
var urls = [];files.reduce(function(chain, file, idx){
return chain.then(function(){
subBtn.textContent = files.length > 1
? 'Compression (' + (idx + 1) + '/' + files.length + ')...'
: 'Compression...';
return ordoCompressImage(file).then(function(compressed){
subBtn.textContent = files.length > 1
? 'Envoi en cours (' + (idx + 1) + '/' + files.length + ')...'
: 'Envoi en cours...';
return uploadOrdonnance(compressed, batchId);
}).then(function(url){
urls.push(url);
});
});
}, Promise.resolve())
.then(function(){
var caption = 'Bonjour, j\'ai mis une ordonnance sur votre site, merci de me confirmer la disponibilité et le prix des produits.';
var who = [];
var p = prenom.value.trim();
var t = telIn.value.trim();
if (p) who.push('au nom de ' + p);
if (t) who.push('sur le numéro ' + t);
if (who.length) caption += ' (' + who.join(', ') + ')';
var numberedUrls = urls.map(function(u, i){ return (i + 1) + ' - ' + u; }).join('\n\n');
sendWA(caption + '\n\n' + numberedUrls, waWin);
closeOverlay();
ordoResetForm();
})
.catch(function(err){
if (window.console && console.error) console.error('Envoi ordonnance échoué :', err);
try { if (waWin && !waWin.closed) waWin.close(); } catch (e) {}
omsg.className = 'pcv-wa-msg error';
// On affiche la vraie raison technique (au lieu d'un message générique) pour pouvoir
// diagnostiquer directement depuis l'écran, sans avoir besoin d'ouvrir la console.
var reason = (err && err.message) ? err.message : 'inconnue';
omsg.textContent = 'Erreur : ' + reason;
ordoResetButton();
});
});
})();// Je veux passer commande : résumé + infos client si panier non vide, sinon message direct
document.getElementById('pcv-opt-passer').addEventListener('click', function(){
var box = document.getElementById('pcv-order-box');
box.innerHTML = '
Chargement...
'; showView('order');fetch(ajaxUrl + '?action=pcv_wa_get_cart') .then(function(r){ return r.json(); }) .then(function(data){ if (data.empty) { sendWA('Bonjour, j\'ai besoin de vous pour passer une commande.'); closeOverlay(); return; }var html = '
';var f = function(id){ var el = document.getElementById(id); return el ? el.value.trim() : ''; }; var s = (data.client || {}); var client = { prenom: (isCheckout && f('billing_first_name')) || s.prenom || '', adresse: (isCheckout && f('billing_address_1')) || s.adresse || '', quartier: (isCheckout && f('billing_quartier')) || s.quartier || '', ville: (isCheckout && f('billing_city')) || s.ville || '', tel: (isCheckout && f('billing_phone')) || s.tel || '', email: (isCheckout && f('billing_email')) || s.email || '' }; var hasClient = client.prenom || client.adresse || client.ville || client.tel || client.email || client.quartier;if (hasClient) { html += '
'; } else { html += '
Vos coordonnées n\'ont pas encore été renseignées sur le site.
'; }html += ''; box.innerHTML = html; updateScrollHint();document.getElementById('pcv-order-confirm').addEventListener('click', function(){ var btn = document.getElementById('pcv-order-confirm'); // Ouvert tout de suite (voir pcvOpenWaTab) pour éviter le blocage popup une fois le fetch // ci-dessous terminé. var waWin = pcvOpenWaTab(); btn.disabled = true; btn.classList.add('is-loading'); btn.innerHTML = 'Préparation du lien...';var params = new URLSearchParams(); params.append('action', 'pcv_wa_save_snapshot'); params.append('prenom', client.prenom); params.append('adresse', client.adresse); params.append('quartier', client.quartier); params.append('ville', client.ville); params.append('tel', client.tel); params.append('email', client.email);fetch(ajaxUrl, { method: 'POST', headers: {'Content-Type': 'application/x-www-form-urlencoded'}, body: params.toString() }) .then(function(r){ return r.json(); }) .then(function(res){ var msg = 'Bonjour, je souhaite passer la commande suivante :\n\n'; data.items.forEach(function(it){ msg += '- ' + it.qty + 'x ' + it.name + ' (' + it.total + ')\n'; }); msg += '\nTotal : ' + data.total + '\n';if (hasClient) { msg += '\n'; if (client.prenom) msg += 'Nom : ' + client.prenom + '\n'; if (client.adresse) msg += 'Adresse : ' + client.adresse + '\n'; if (client.quartier) msg += 'Quartier : ' + client.quartier + '\n'; if (client.ville) msg += 'Ville : ' + client.ville + '\n'; if (client.tel) msg += 'Téléphone : ' + client.tel + '\n'; if (client.email) msg += 'Email : ' + client.email + '\n'; }var link = (res && res.ok) ? res.url : data.checkout_url; msg += '\nLien pour retrouver mon panier + mes coordonnées en un clic : ' + link; sendWA(msg, waWin); closeOverlay(); }) .catch(function(){ try { if (waWin && !waWin.closed) waWin.close(); } catch (e) {} }); }); }); }); })();

