SPB Git forge

spb/fabri-ka

Public

Agrégateur de produits québécois — www.fabri-ka.com

217commits 1branches 0releases
66.1 MBsize
maindefault branch
6 h agolast push
Python 38.4% HTML 30.3% TypeScript 17.2% CSS 11% JavaScript 3.2%
7.7 KB · 250 lines tsx
Raw Blame History
1// Auteur : Simon-Pierre Boucher — contact@spboucher.ai2// pages/Inscrire.tsx — « Inscrire mon atelier » : auto-inscription des3// artisans/fabricants québécois. Le dépôt part en quarantaine de validation4// (statut pending) — rien n'est publié sans validation manuelle.5import { useEffect, useState } from 'react'6import {7  fetchFacets,8  setPageMeta,9  submitInscription,10  type InscriptionPayload,11} from '../api'1213const FIELD: React.CSSProperties = { display: 'grid', gap: 4 }1415export default function Inscrire() {16  const [cats, setCats] = useState<{ key: string; label: string }[]>([])17  const [form, setForm] = useState<InscriptionPayload>({18    name: '',19    metier: '',20    description: '',21    address: '',22    website: '',23    email: '',24    phone: '',25    entreprise_url: '',26  })27  const [socials, setSocials] = useState('')28  const [photos, setPhotos] = useState('')29  const [sending, setSending] = useState(false)30  const [done, setDone] = useState<string | null>(null)31  const [error, setError] = useState<string | null>(null)3233  useEffect(() => {34    setPageMeta(35      'Inscrire mon atelier — Fabri-Ka',36      'Artisans et fabricants québécois : inscrivez votre atelier sur ' +37        'Fabri-Ka. Chaque fiche est validée manuellement avant publication.'38    )39    fetchFacets()40      .then((f) => setCats(f.all_categories ?? []))41      .catch(() => {})42  }, [])4344  function set<K extends keyof InscriptionPayload>(45    key: K,46    value: InscriptionPayload[K]47  ) {48    setForm((f) => ({ ...f, [key]: value }))49  }5051  async function onSubmit(e: React.FormEvent) {52    e.preventDefault()53    setError(null)54    setSending(true)55    try {56      const clean = (s: string) =>57        s58          .split(/[\n,]/)59          .map((x) => x.trim())60          .filter(Boolean)61      const res = await submitInscription({62        ...form,63        socials: clean(socials),64        photos: clean(photos),65      })66      setDone(67        res.message ??68          'Merci ! Votre atelier est en attente de validation avant publication.'69      )70    } catch (err) {71      setError(err instanceof Error ? err.message : 'Erreur inattendue')72    } finally {73      setSending(false)74    }75  }7677  if (done) {78    return (79      <div className="page inscrire-page">80        <span className="kicker">Inscrire mon atelier</span>81        <h1>Demande reçue !</h1>82        <p className="contact-lede">{done}</p>83        <p className="contact-note">84          Notre équipe vérifie chaque atelier (fabrication québécoise,85          coordonnées, site) avant de publier la fiche. Vous serez joint aux86          coordonnées fournies si un détail manque.87        </p>88      </div>89    )90  }9192  return (93    <div className="page inscrire-page">94      <span className="kicker">Artisans &amp; fabricants québécois</span>95      <h1>Inscrire mon atelier</h1>96      <p className="contact-lede">97        Vous fabriquez au Québec ? Inscrivez votre atelier : après une{' '}98        <b>validation manuelle</b> (fabrication québécoise et coordonnées99        vérifiables), votre fiche apparaîtra dans le répertoire — et si votre100        boutique en ligne expose un catalogue public, vos produits seront101        ajoutés automatiquement.102      </p>103104      <form105        className="inscrire-form"106        onSubmit={onSubmit}107        style={{ display: 'grid', gap: 16, maxWidth: 640 }}108      >109        <label style={FIELD}>110          <b>Nom de l&rsquo;atelier / entreprise *</b>111          <input112            required113            minLength={2}114            maxLength={120}115            value={form.name}116            onChange={(e) => set('name', e.target.value)}117            placeholder="Ex. : Atelier Boréal"118          />119        </label>120        <label style={FIELD}>121          <b>Métier / spécialité *</b>122          <select123            required124            value={form.metier}125            onChange={(e) => set('metier', e.target.value)}126          >127            <option value="">Choisir…</option>128            {cats.map((c) => (129              <option key={c.key} value={c.key}>130                {c.label}131              </option>132            ))}133          </select>134        </label>135        <label style={FIELD}>136          <b>Description *</b>137          <textarea138            required139            minLength={20}140            maxLength={4000}141            rows={5}142            value={form.description}143            onChange={(e) => set('description', e.target.value)}144            placeholder="Ce que vous fabriquez, où, comment… (min. 20 caractères)"145          />146        </label>147        <label style={FIELD}>148          <b>Adresse de l&rsquo;atelier</b>149          <input150            maxLength={300}151            value={form.address}152            onChange={(e) => set('address', e.target.value)}153            placeholder="123 rue Principale, Ville (Québec) G0X 0X0"154          />155        </label>156        <label style={FIELD}>157          <b>Site web / boutique en ligne</b>158          <input159            type="url"160            maxLength={200}161            value={form.website}162            onChange={(e) => set('website', e.target.value)}163            placeholder="https://…"164          />165        </label>166        <div167          style={{168            display: 'grid',169            gap: 16,170            gridTemplateColumns: 'repeat(auto-fit, minmax(220px, 1fr))',171          }}172        >173          <label style={FIELD}>174            <b>Courriel *</b>175            <input176              type="email"177              maxLength={200}178              value={form.email}179              onChange={(e) => set('email', e.target.value)}180              placeholder="vous@atelier.ca"181            />182          </label>183          <label style={FIELD}>184            <b>Téléphone</b>185            <input186              type="tel"187              maxLength={40}188              value={form.phone}189              onChange={(e) => set('phone', e.target.value)}190              placeholder="418 555-0199"191            />192          </label>193        </div>194        <label style={FIELD}>195          <b>Réseaux sociaux</b>196          <textarea197            rows={2}198            value={socials}199            onChange={(e) => setSocials(e.target.value)}200            placeholder={'https://instagram.com/…\nhttps://facebook.com/…'}201          />202          <small>Une URL par ligne (Instagram, Facebook, TikTok…)</small>203        </label>204        <label style={FIELD}>205          <b>Photos (liens)</b>206          <textarea207            rows={2}208            value={photos}209            onChange={(e) => setPhotos(e.target.value)}210            placeholder="https://…/photo-atelier.jpg"211          />212          <small>213            Liens vers des photos de l&rsquo;atelier ou des produits (une URL214            par ligne)215          </small>216        </label>217        {/* honeypot anti-robot : invisible, doit rester vide */}218        <label219          aria-hidden="true"220          style={{ position: 'absolute', left: '-9999px', height: 0, overflow: 'hidden' }}221          tabIndex={-1}222        >223          Ne pas remplir224          <input225            type="text"226            autoComplete="off"227            tabIndex={-1}228            value={form.entreprise_url}229            onChange={(e) => set('entreprise_url', e.target.value)}230          />231        </label>232        {error && (233          <p role="alert" style={{ color: 'var(--danger, #b3261e)' }}>234            {error}235          </p>236        )}237        <button type="submit" className="btn-primary" disabled={sending}>238          {sending ? 'Envoi…' : 'Soumettre mon atelier'}239        </button>240        <p className="contact-note">241          En soumettant, vous confirmez que les produits sont fabriqués (ou242          conçus) au Québec. Un courriel ou un téléphone est requis pour la243          vérification. Aucune fiche n&rsquo;est publiée sans validation244          manuelle.245        </p>246      </form>247    </div>248  )249}250