SEO/GEO : prérendu statique, 8 nouvelles pages, schémas et vraies captures
Chantier de l'audit audit-seo-geo.md — 20 des 21 actions.
Technique
- Prérendu statique rétabli : le layout racine passe dans [lang], plus de
headers() ni de x-pathname. 0 page prérendue avant, 89 après.
- Schémas : offres 39/99/179 €, Organization ancrée en Belgique (adresse,
TVA, areaServed, LinkedIn), FAQPage sur la home, BreadcrumbList partout.
- Hiérarchie h1/h2/h3 remise dans l'ordre ; liens morts corrigés ; liens
légaux en <Link> — le lint passe de 15 erreurs à 0.
- Les 9 modules de la home sont enfin dans le HTML (8 manquaient).
- sharp en dépendance : mesuré, sans lui /_next/image renvoyait le JPEG
source (64 Ko), avec lui du WebP (26 Ko).
Contenu
- Nouvelles pages en 4 langues : /tarifs, /assistant-ia, /borne-kiosk,
/visite-hors-ligne, /marches-publics.
- Blog /fr/ressources (2 articles) et comparatifs sourcés et datés
myinfomate-vs-smartify et -vs-stqry, en français.
- Pages légales sous /{lang}/ : mentions et confidentialité traduites, CGU
publiées (le lien de consentement de /signup ne menait nulle part) avec
un avis traduit, la version française faisant foi.
- Vocabulaire acheteur dans les 6 segments : RGPD, marchés publics,
accessibilité — en disant l'absence de certification Access-i.
- Captures réelles de la V3 et carte de parcours ; alt textes localisés.
1,1 Mo d'images économisé.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@ -35,7 +35,9 @@
|
|||||||
- [x] **Google Search Console** — soumettre `https://myinfomate.be/sitemap.xml`, vérifier qu'il n'y a pas d'erreurs d'indexation
|
- [x] **Google Search Console** — soumettre `https://myinfomate.be/sitemap.xml`, vérifier qu'il n'y a pas d'erreurs d'indexation
|
||||||
- [x] **Bing Webmaster Tools** — même chose (souvent oublié, représente ~10% du trafic desktop)
|
- [x] **Bing Webmaster Tools** — même chose (souvent oublié, représente ~10% du trafic desktop)
|
||||||
- [ ] **Lighthouse audit** — ouvrir Chrome DevTools sur myinfomate.be, onglet Lighthouse, mode Mobile → viser > 90. Les points rouges qui sortent sont à corriger en priorité.
|
- [ ] **Lighthouse audit** — ouvrir Chrome DevTools sur myinfomate.be, onglet Lighthouse, mode Mobile → viser > 90. Les points rouges qui sortent sont à corriger en priorité.
|
||||||
- [ ] **LinkedIn entreprise Unov** — si pas encore actif, créer la page et pointer vers myinfomate.be. Google valorise les signaux sociaux B2B.
|
- [x] **LinkedIn** — page Unov existante + vitrine MyInfoMate créée le 2026-09-10 (`linkedin.com/showcase/myinfomate/`), les deux dans le schema du site. Posts : `DOCS/linkedin-posts-lancement.md`
|
||||||
|
|
||||||
|
> Plan complet et suivi depuis le 2026-09-09 : **[audit-seo-geo.md](audit-seo-geo.md)** (§0 pour l'avancement).
|
||||||
|
|
||||||
### Contenu long-tail (impact élevé, effort éditorial)
|
### Contenu long-tail (impact élevé, effort éditorial)
|
||||||
|
|
||||||
|
|||||||
335
audit-seo-geo.md
Normal file
@ -0,0 +1,335 @@
|
|||||||
|
# Audit SEO / GEO — myinfomate-landing
|
||||||
|
|
||||||
|
> Audit en lecture seule du repo `myinfomate-landing`, réalisé le 2026-09-09.
|
||||||
|
> Périmètre : code source uniquement. Aucun test réseau sur `https://myinfomate.be` n'a été fait —
|
||||||
|
> tout ce qui n'est pas dérivable du code est marqué **non vérifiable depuis le code**.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 0. Suivi d'avancement
|
||||||
|
|
||||||
|
> Mis à jour le 2026-09-10. Les numéros renvoient au plan d'action du §6.
|
||||||
|
|
||||||
|
| # | Action | État |
|
||||||
|
|---|---|---|
|
||||||
|
| 1 | Hiérarchie `h2`/`h3` | ✅ 2026-09-10 — libellé décoratif en `<p>`, titre de section en `h2`, cartes en `h3` (home + segments) |
|
||||||
|
| 2 | Schema `Organization` | ✅ 2026-09-10 — adresse, `vatID`, `taxID`, `areaServed`, `sameAs` LinkedIn Unov ; `url` passé à `https://unov.be` |
|
||||||
|
| 3 | 9 panneaux `ModulesSection` dans le DOM | ✅ 2026-09-10 — vérifié dans le HTML servi |
|
||||||
|
| 4 | Offres Essentiel/Pro/Premium + `AggregateOffer` | ✅ 2026-09-10 — `src/data/structured-data.ts`, HTVA (`valueAddedTaxIncluded: false`) |
|
||||||
|
| 5 | Liens morts `href="#"` | ✅ 2026-09-10 — logo et ACCUEIL → `/{lang}`, globe du footer → unov.be (home **et** segments, le 2ᵉ n'était pas relevé par l'audit) |
|
||||||
|
| M4 | TVA écrite dans les mentions légales | ✅ 2026-09-10 |
|
||||||
|
| M7 | Profils sociaux | ✅ 2026-09-10 — vitrine LinkedIn MyInfoMate créée, dans `sameAs` du `SoftwareApplication` ; fiche produit LinkedIn soumise pour évaluation |
|
||||||
|
| 6 | `llms.txt` FR + prix + `robots.txt` | ✅ 2026-09-10 — `llms.txt` en français (vocabulaire acheteur, grille complète, TVA), anglais déplacé dans `llms-en.txt`, les deux cités dans `robots.txt` |
|
||||||
|
| 7 | Prérendu statique | ✅ 2026-09-10 — `<html lang>` dans `[lang]/layout.tsx` (layout racine par langue), pages légales dans le groupe `(legal)` avec leur propre layout, plus de `headers()` ni de `x-pathname`. **58 pages prérendues**, servies en `x-nextjs-cache: HIT` |
|
||||||
|
| 8 | `/{lang}/tarifs` | ✅ 2026-09-10 — grille + 7 FAQ tarifaires ×4 langues, `FAQPage` + offres ; lien « Tarifs » du menu (home et segments) pointe dessus ; grille extraite dans `components/PricingPlans.tsx` (était copiée deux fois) |
|
||||||
|
| 9 | `/{lang}/assistant-ia` | ✅ 2026-09-10 — **4 langues** (736 à 846 mots), 6 FAQ + `FAQPage` par langue, `hreflang` complet, liée depuis la section IA de la home et dans le sitemap. Section « Ce qu'il ne fait pas » assumée : dire les limites plutôt que survendre l'IA |
|
||||||
|
| — | Liens légaux du footer | ✅ 2026-09-10 — passés en `<Link>` (home, segments, signup) : **le lint du repo est à 0 erreur**, il en comptait 15 |
|
||||||
|
| — | Page CGU | ✅ 2026-09-10 — `/conditions-generales` publiée (~4 000 mots) : la case de consentement de `/signup` faisait accepter des CGU **introuvables**. Liée depuis les pieds de page et le sitemap. ⚠️ validation juridique toujours due |
|
||||||
|
| M4 | Frais de mise en place | ✅ 2026-09-10 — **décision de Thomas : pas de montant affiché.** À la place, dans les 4 langues : « frais de mise en place **uniques, chiffrés dans le devis** », et la FAQ de `/tarifs` dit ce qu'ils couvrent et qu'ils précèdent la signature (voir carte kanban 180) |
|
||||||
|
| 12 | Vocabulaire acheteur dans les 6 segments | 🟠 2026-09-10 — **français fait**. Nouvelles FAQ par segment : RGPD (les 6), marchés publics (5 — pas hôtels, secteur privé), accessibilité/Access-i (3). « Médiation numérique », « parcours de visite » et « cartel numérique » injectés dans les intros. **NL/EN/DE pas encore traduits** : les FAQ françaises sont plus fournies que les autres langues |
|
||||||
|
| 14 | Page marchés publics | 🟠 partiellement couvert par la FAQ des segments ; page dédiée toujours à faire |
|
||||||
|
| 10 | FAQ sur la homepage | ✅ 2026-09-10 — 8 questions ×4 langues + `FAQPage` (produit, prix, canaux, hors ligne, marque blanche, délai, hébergement des données). C'était la page qu'un LLM atteint en premier, et elle n'avait aucune FAQ |
|
||||||
|
| 13 | `BreadcrumbList` | ✅ 2026-09-10 — sur segments, cas clients (liste et détail), tarifs et assistant IA ; helper `breadcrumbSchema()` dans `structured-data.ts` |
|
||||||
|
| 21 | Dates du sitemap | ✅ 2026-09-10 — `lastModified: new Date()` (date du build sur les 55 URLs) remplacé par des dates réelles par famille de pages, constante `LAST_MODIFIED` en tête de `sitemap.ts` **à mettre à jour avec le contenu** |
|
||||||
|
| 12 bis | Traduction des FAQ segments | ✅ 2026-09-10 — **42 items** ajoutés en EN/NL/DE. Parité atteinte : 10 / 10 / 8 / 7 / 8 / 9 FAQ par segment dans les 4 langues |
|
||||||
|
| 16 | Images | ✅ 2026-09-10 — recompressées (palette PNG, `effort: 10`) : `app-screenshot-1` 731 → **232 Ko**, `app-screenshot-2` 547 → **185 Ko**, `myinfomate-logo` 240 → **57 Ko**. Qualité vérifiée à l'œil. `map_generated` déjà optimale. **1,1 Mo économisé.** `sharp` a servi en installation temporaire, il n'est **pas** ajouté aux dépendances |
|
||||||
|
| — | `google-maps-route.png` (699 Ko) | ⚠️ **référencé nulle part dans `src/`** — supprimable, mais je n'y touche pas sans ton accord |
|
||||||
|
| — | Captures d'écran de l'app | ✅ 2026-09-10 — remplacées par les **vraies captures de la V3** fournies par Thomas (app du Fort de Saint-Héribert) : accueil sombre en grille bento et fiche article dans les deux téléphones du hero, liste des sections dans le mockup « white label », où un cadre vide affichait une icône de palette. Anciennes captures `.png` supprimées, nouvelles en JPEG (129 / 121 / 107 Ko). **Textes alternatifs réécrits et localisés** dans les 4 langues — ils étaient en anglais et décrivaient l'ancienne interface |
|
||||||
|
| 14 | `/{lang}/marches-publics` | ✅ 2026-09-10 — 4 langues, 5 FAQ. Argument central : **Visit Namur, attribué sur cahier des charges publié**. Dit franchement l'absence de certification Access-i et d'audit, et renvoie au service marchés pour les seuils plutôt que de citer un chiffre non vérifié |
|
||||||
|
| 17 | `/{lang}/borne-kiosk` et `/{lang}/visite-hors-ligne` | ✅ 2026-09-10 — 4 langues, 4 FAQ chacune, adossées à Visit Namur et au Fort de Saint-Héribert. Gabarit partagé `components/ContentPage.tsx` |
|
||||||
|
| — | Optimisation d'images en prod | ✅ 2026-09-10 — **`sharp` ajouté aux dépendances, après mesure** : sans lui, `/_next/image` renvoyait le JPEG source (64 Ko) ; avec lui, du **WebP de 26 Ko**. ⚠️ à confirmer au premier build Docker (binaires `linuxmusl`) |
|
||||||
|
| — | Maillage interne vers les 5 pages produit | ✅ 2026-09-10 — colonne « Solutions » dans le pied de page de la **home et des pages segment** (3 colonnes vides récupérées), plus des liens **dans le contenu**, qui valent davantage : carte « Mode Kiosk » → `/borne-kiosk`, point « Contenu hors ligne » → `/visite-hors-ligne`, bandeau acheteur public sous la grille de `/tarifs` → `/marches-publics`. Compté sur les pages servies : chaque page produit reçoit 1 à 3 liens par page. **Sitemap : 67 URLs** |
|
||||||
|
| 15 | Pages légales en 4 langues | ✅ 2026-09-10 — mentions légales et confidentialité **traduites**, CGU laissées en français avec un **avis traduit** (« la version française fait foi ») et le corps marqué `lang="fr"` : traduire un contrat qu'un juriste va corriger, c'est du travail à refaire. Les 3 pages vivent sous `/{lang}/…`, les anciennes URLs redirigent vers la langue du visiteur |
|
||||||
|
| 18 | Pages comparatives | ✅ 2026-09-10 — `/fr/comparatif/myinfomate-vs-smartify` et `…-vs-stqry`, **prix relevés à la source le 10/09** (Smartify : 1 800 / 3 500 / 9 500 £ par an ; STQRY : 199 $/mois, +100 $ Pro, 2 000 $ de frais uniques d'app native), sources liées et datées. Chaque page dit **ce que le concurrent fait mieux**. ⚠️ Guideius et izi.TRAVEL écartés : le premier ne publie aucun prix, le second a un modèle gratuit non comparable |
|
||||||
|
| 20 | Blog `/fr/ressources` | ✅ 2026-09-10 — index + 2 articles (audioguide vs application, borne vs BYOD), schema `BlogPosting`. **Français seulement** ; les autres langues répondent 404, c'est volontaire |
|
||||||
|
| 11 | Témoignages clients | ⏸️ **écarté le 2026-09-10 par Thomas** — il ne souhaite pas solliciter les clients pour l'instant, même satisfaits. Le type `CasClient` reste sans champ témoignage : à rouvrir le jour où un client en propose un spontanément |
|
||||||
|
| 19 | Pages XR | ⬜ **deux pages à prévoir, pas une** : `/lunettes-connectees` et `/casque-vr`. À écrire quand chaque module sera démontrable — cf. `DOCS/v2/vr-quest-unity-plan.md` et `DOCS/rayban-meta-integration.md` |
|
||||||
|
|
||||||
|
Tout est **stagé, pas encore committé** au 2026-09-10 (en attente de validation).
|
||||||
|
|
||||||
|
Point connu : une URL inexistante (`/fr/xyz`) répond bien **404 + `noindex`**, mais son HTML initial est le shell d'erreur de Next ; la page 404 (`[lang]/not-found.tsx`) s'affiche après hydratation. Effet de l'absence de layout racine commun ; le corriger demanderait `experimental.globalNotFound`. Sans impact SEO.
|
||||||
|
Posts LinkedIn de lancement : `DOCS/linkedin-posts-lancement.md`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Verdict en 5 lignes
|
||||||
|
|
||||||
|
1. **Oui, partiellement citable.** Le contenu textuel principal est rendu côté serveur (composants serveur + client components pré-rendus par Next), les prix sont en texte brut, `llms.txt` existe et est bon, et aucun crawler IA n'est bloqué. Un LLM interrogé sur « audioguide pour musée en Belgique » a de la matière.
|
||||||
|
2. **Mais le site n'est trouvable que sur des requêtes produit, pas sur les requêtes d'acheteur.** Les 6 pages segment sont bien construites (~1 130 mots FR + 6 FAQ chacune), mais il n'existe **aucune** page `/tarifs`, `/assistant-ia`, `/borne-kiosk`, `/visite-offline`, ni page lunettes connectées : le différenciateur IA n'a pas d'URL propre.
|
||||||
|
3. **Le vocabulaire de l'acheteur public belge est absent** : zéro occurrence de « médiation numérique », « scénographie », « cartel numérique », « accessibilité », « Access-i », « marché public », « RGPD » dans les ~5 700 lignes de contenu de `src/data/`.
|
||||||
|
4. **Deux fuites de contenu réelles** : 8 des 9 descriptions de modules de la homepage ne sont pas dans le HTML (`ModulesSection.tsx:135`), et aucune page n'est pré-rendue statiquement (`layout.tsx:36` force le SSR sur tout l'arbre).
|
||||||
|
5. **Les preuves clients sont là mais désincarnées** : 3 cas clients datés et nommés, mais aucun logo, aucun témoignage attribué, aucun lien sortant vers un site client ou une fiche store — c'est ce qui manque le plus à un dossier de marché public.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Inventaire factuel
|
||||||
|
|
||||||
|
### Framework et mode de rendu
|
||||||
|
|
||||||
|
| Élément | Valeur | Source |
|
||||||
|
|---|---|---|
|
||||||
|
| Framework | Next.js **16.1.6**, React 19.2.3, App Router | `package.json:12-13` |
|
||||||
|
| CSS | Tailwind v4 (`@tailwindcss/postcss`) | `package.json:22` |
|
||||||
|
| Build | `output: "standalone"`, React Compiler activé | `next.config.ts:5-6` |
|
||||||
|
| Déploiement | Docker `node:22-alpine`, `node server.js` derrière Traefik | `Dockerfile:8-18`, `README.md` |
|
||||||
|
| Routing i18n | Middleware Next 16 (`src/proxy.ts`) → redirect vers `/{locale}` selon `Accept-Language` | `src/proxy.ts:28-32` |
|
||||||
|
| Locales | `fr`, `en`, `nl`, `de` — `fr` par défaut, html lang `fr-BE` / `nl-BE` | `src/i18n.ts:1-17` |
|
||||||
|
| **Mode de rendu effectif** | **SSR dynamique sur 100 % des pages de contenu — 0 page prérendue** | voir ci-dessous |
|
||||||
|
|
||||||
|
**Le contenu texte est bien dans le HTML servi** — ce n'est pas une SPA client-only, donc le point critique redouté n'est pas présent. Deux composants seulement sont des client components porteurs de contenu (`SegmentPageClient.tsx:1`, `ModulesSection.tsx:1`) ; Next les rend quand même dans le HTML initial, donc leur texte est extractible **à l'exception de ce qui est conditionné par un `useState`** (voir bloquant B2).
|
||||||
|
|
||||||
|
**En revanche, la génération statique ne fonctionne pas.** Le `prerender-manifest.json` du dernier build présent dans `.next/` (daté du 13/08) ne contient que trois routes prérendues :
|
||||||
|
|
||||||
|
```
|
||||||
|
PRERENDERED: ['/_global-error', '/icon.png', '/sitemap.xml']
|
||||||
|
DYNAMIC: []
|
||||||
|
```
|
||||||
|
|
||||||
|
Cause : `src/app/layout.tsx:36-37` appelle `await headers()` pour lire `x-pathname`. Cet accès aux headers de requête opte **tout l'arbre de routes** hors du rendu statique. Résultat : les `generateStaticParams()` déclarés dans `[lang]/page.tsx:27`, `[lang]/[segment]/page.tsx:9` et `[lang]/signup/page.tsx:25` ne produisent aucun HTML statique — chaque visite, y compris chaque crawl, déclenche un rendu React complet.
|
||||||
|
|
||||||
|
### Routes trouvées
|
||||||
|
|
||||||
|
| Route | Fichier | Titre (FR) | H1 | Contenu |
|
||||||
|
|---|---|---|---|---|
|
||||||
|
| `/{lang}` | `src/app/[lang]/page.tsx` | *MyInfoMate — Application guide visiteur pour musées & lieux* | `MyInfoMate - La solution facile pour créer, gérer et diffuser du contenu interactif` (`HomeClient.tsx:29-31`) | ~1 990 mots FR |
|
||||||
|
| `/{lang}/musees` | `[segment]/page.tsx` | *Application Guide de Visite pour Musées \| MyInfoMate* | `Votre musée mérite une application à la hauteur de vos collections` | ~1 134 mots FR, 6 FAQ |
|
||||||
|
| `/{lang}/offices-tourisme` | idem | même structure, meta propre | H1 hero segment | ~1 100 mots, 6 FAQ |
|
||||||
|
| `/{lang}/parcs-naturels` | idem | | | ~1 100 mots, 6 FAQ |
|
||||||
|
| `/{lang}/hotels-loisirs` | idem | | | ~1 100 mots, 6 FAQ |
|
||||||
|
| `/{lang}/evenements` | idem | | | ~1 100 mots, 6 FAQ |
|
||||||
|
| `/{lang}/education-culture` | idem | | | ~1 100 mots, 6 FAQ |
|
||||||
|
| `/{lang}/cas-clients` | `cas-clients/page.tsx` | listing | oui | court |
|
||||||
|
| `/{lang}/cas-clients/musee-de-la-fraise` | `cas-clients/[slug]/page.tsx` | *Musée de la Fraise — Premier client MyInfoMate \| Kiosk & App Mobile* | `De la vitrine au numérique : la naissance de MyInfoMate` (`:101`) | ~400 mots |
|
||||||
|
| `/{lang}/cas-clients/fort-de-saint-heribert` | idem | | | ~400 mots |
|
||||||
|
| `/{lang}/cas-clients/visit-namur` | idem | | | ~400 mots |
|
||||||
|
| `/{lang}/signup` | `signup/page.tsx` | *Créer mon compte — Plan Essentiel* | — | **`robots: {index:false}`** (`:41`) — correct |
|
||||||
|
| `/mentions-legales` | `app/mentions-legales/page.tsx` | *Mentions légales* | `Mentions légales` (`:18`) | FR uniquement, hors `[lang]` |
|
||||||
|
| `/confidentialite` | `app/confidentialite/page.tsx` | *Politique de confidentialité* | `Politique de confidentialité` (`:18`) | FR uniquement, hors `[lang]` |
|
||||||
|
|
||||||
|
**Total indexable : 11 URLs × 4 langues + 2 pages légales = 46 URLs.** Cohérent avec `src/app/sitemap.ts`, qui génère exactement ces entrées avec `alternates.languages` par entrée (`sitemap.ts:8-15`).
|
||||||
|
|
||||||
|
### Fondations techniques — état
|
||||||
|
|
||||||
|
| Point | État | Détail |
|
||||||
|
|---|---|---|
|
||||||
|
| `robots.txt` | ✅ présent | `public/robots.txt` — `User-agent: *` / `Allow: /` / `Disallow: /api/` |
|
||||||
|
| Blocage crawlers IA | ✅ **aucun bloqué** | GPTBot, ClaudeBot, anthropic-ai, PerplexityBot, Google-Extended, CCBot, Bingbot sont **tous autorisés** par le `User-agent: *`. Aucune règle nominative, ni Allow ni Disallow (`robots.txt:1-3`) |
|
||||||
|
| `sitemap.xml` | ✅ généré + référencé | `src/app/sitemap.ts`, référencé `robots.txt:5` |
|
||||||
|
| `llms.txt` | ✅ présent et de bonne qualité | `public/llms.txt`, 85 lignes — produit, features, modes de déploiement, assistant IA, clients, pricing, société |
|
||||||
|
| Canonical | ✅ sur toutes les pages | `[lang]/page.tsx:60`, `[segment]/page.tsx:48`, `cas-clients/[slug]`, légales `:7` |
|
||||||
|
| hreflang | ✅ complet + `x-default` | `layout.tsx:68-71`, `[lang]/page.tsx:59-62`, et aussi dans `sitemap.ts:13` |
|
||||||
|
| Open Graph | ✅ | `layout.tsx:53-62` + per-page ; **OG image dynamique** `[lang]/opengraph-image.tsx` (edge runtime, 1200×630, locale-aware) et variante par segment |
|
||||||
|
| Twitter Card | ✅ `summary_large_image` | `layout.tsx:63-67` |
|
||||||
|
| Données structurées | ✅ **JSON-LD** (pas microdata) | Organization + WebSite + SoftwareApplication (home) ; FAQPage + SoftwareApplication (segments) ; Article (cas clients) |
|
||||||
|
| BreadcrumbList | ❌ absent | aucune occurrence dans le repo |
|
||||||
|
| Images | ⚠️ | `next/image` partout (donc WebP/AVIF à la volée), `priority` sur le hero (`HomeClient.tsx:53`), `alt` renseignés. Mais les sources sont des PNG lourds : `app-screenshot-1.png` 748 Ko, `google-maps-route.png` 715 Ko, `app-screenshot-2.png` 560 Ko, `myinfomate-logo.png` 246 Ko |
|
||||||
|
| Temps de chargement réel | **non vérifiable depuis le code** — le Lighthouse est d'ailleurs encore coché « à faire » dans `TODO-SEO.md:39` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Bloquants critiques
|
||||||
|
|
||||||
|
### B1 — Aucune page n'est prérendue : tout est SSR à chaque requête
|
||||||
|
|
||||||
|
**Fichier : `src/app/layout.tsx:36-37`**
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const h = await headers();
|
||||||
|
const pathname = h.get("x-pathname") ?? "/";
|
||||||
|
```
|
||||||
|
|
||||||
|
Cet appel dans le layout racine force le rendu dynamique de l'intégralité de l'application. `prerender-manifest.json` le confirme : trois routes prérendues, aucune page de contenu. Les `generateStaticParams()` déclarés dans trois fichiers sont inertes.
|
||||||
|
|
||||||
|
*Conséquence* : pas de blocage d'indexation (le HTML est bien complet dans la réponse), mais un TTFB dépendant du serveur à chaque crawl, et la perte de toute mise en cache statique/CDN. Sur un VPS unique derrière Traefik (`README.md`), c'est le premier facteur de lenteur.
|
||||||
|
|
||||||
|
*Correctif* : le layout racine n'a besoin de la locale que pour `<html lang>` et des métadonnées de repli — or elle est déjà disponible via le segment `[lang]`. Déplacer `resolveLocale()` + `generateMetadata` vers un `src/app/[lang]/layout.tsx` (à créer) recevant `params.lang`, et laisser le layout racine muet. `[lang]/page.tsx:31` et `[segment]/page.tsx:16` définissent déjà leurs métadonnées complètes, donc le layout racine est en grande partie redondant.
|
||||||
|
|
||||||
|
### B2 — 8 des 9 descriptions de modules de la homepage sont absentes du HTML
|
||||||
|
|
||||||
|
**Fichier : `src/components/ModulesSection.tsx:20, 73, 125, 135`**
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
const [activeModule, setActiveModule] = useState(0);
|
||||||
|
...
|
||||||
|
<h3 ...>{modules[activeModule].title}</h3>
|
||||||
|
<p ...>{modules[activeModule].description}</p>
|
||||||
|
```
|
||||||
|
|
||||||
|
Seul le module d'index 0 (Carte interactive) voit sa `description` et sa `value` rendues. Les huit autres — Quiz/jeux, Vidéo, Article, Agenda, **Offline**, Web, Statistiques, **Escape game** — n'existent dans le HTML que sous forme de libellé de bouton (`ModulesSection.tsx:59`). Or « mode offline » et « escape game » sont deux des arguments les plus différenciants : ils figurent dans `llms.txt:26,29` mais pas dans le HTML de la homepage.
|
||||||
|
|
||||||
|
*Correctif* : rendre les neuf panneaux et masquer les inactifs en CSS (`hidden` / `aria-hidden`), exactement comme le fait déjà correctement la FAQ des pages segment (`SegmentPageClient.tsx:652` — collapse par `max-h-0`, contenu toujours présent dans le DOM).
|
||||||
|
|
||||||
|
### B3 — Aucun schema `Offer` pour les plans Pro / Premium / Enterprise
|
||||||
|
|
||||||
|
**Fichiers : `src/app/[lang]/page.tsx:100-110` et `[segment]/page.tsx:84-94`**
|
||||||
|
|
||||||
|
Le `SoftwareApplication` ne déclare qu'une seule offre, à 39 €. Les prix 99 € et 179 € sont bien en texte brut dans le HTML (`SegmentPageClient.tsx:460` et suivantes) — donc lisibles par un LLM — mais invisibles pour Google Rich Results et pour tout agent qui s'appuie sur les données structurées. À la question « combien coûte MyInfoMate pour avoir l'assistant IA ? », un LLM devra deviner.
|
||||||
|
|
||||||
|
*Correctif* : remplacer `offers` par un tableau de trois à quatre `Offer` (`name: "Essentiel" / "Pro" / "Premium"`, `price`, `priceCurrency: "EUR"`, périodicité), plus un `AggregateOffer` avec `lowPrice: 39` / `highPrice: 179`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Manques importants (existe mais mal fait)
|
||||||
|
|
||||||
|
### M1 — Hiérarchie de titres inversée sur toutes les pages
|
||||||
|
|
||||||
|
Le label décoratif en petites capitales est un `<h2>`, et le vrai titre de section un `<h3>`. Vérifiable partout :
|
||||||
|
|
||||||
|
- `HomeClient.tsx:78-79` — `<h2>{t.strategic.sectionLabel}</h2>` puis `<h3>{t.strategic.sectionTitle}</h3>`
|
||||||
|
- `HomeClient.tsx:126-127`, `:181-182`, `:301-302`, `:421-422`, `:474-475`
|
||||||
|
- `SegmentPageClient.tsx:310-311`, `:333-334`, `:363-364`, `:398-399`, `:636-637`
|
||||||
|
- `ModulesSection.tsx:34-35`
|
||||||
|
|
||||||
|
Un extracteur de plan de page lit donc « LE DÉFI DES MUSÉES » comme titre de niveau 2 et « Ce que vivent la plupart des musées » comme sous-titre : l'inverse exact. Correctif purement cosmétique — inverser les balises, garder les classes.
|
||||||
|
|
||||||
|
### M2 — Le schema `Organization` n'ancre pas l'entreprise en Belgique
|
||||||
|
|
||||||
|
**`src/app/[lang]/page.tsx:70-81`** ne contient que `name`, `url`, `logo`, `contactPoint`. Manquent `address` (PostalAddress : Rue René Copette 3, 5020 Namur, BE), `areaServed` (BE / FR / LU), `vatID` ou `taxID` (BCE 0776.895.467), et `sameAs` (aucun profil externe déclaré). Toutes ces données existent pourtant en clair dans `mentions-legales/page.tsx:24-28`. C'est le signal le plus direct qu'un LLM utilise pour répondre à « une solution **belge** ».
|
||||||
|
|
||||||
|
### M3 — Les mentions légales sont hors du système i18n
|
||||||
|
|
||||||
|
`src/app/mentions-legales/page.tsx` et `src/app/confidentialite/page.tsx` vivent hors de `[lang]`, sont explicitement exclues du middleware (`proxy.ts:5`), n'existent qu'en français et n'ont pas de `hreflang`. Un acheteur néerlandophone ou luxembourgeois qui vérifie la conformité de l'éditeur tombe sur du français. Le sitemap ne les référence qu'en une seule version (`sitemap.ts:66-77`).
|
||||||
|
|
||||||
|
### M4 — TVA jamais écrite, RGPD jamais mis en avant côté commercial
|
||||||
|
|
||||||
|
`mentions-legales/page.tsx:25` donne « Numéro d'entreprise BCE : 0776.895.467 » mais jamais le format TVA `BE 0776.895.467` — c'est pourtant la chaîne que cherche le service comptable d'une commune. Par ailleurs « RGPD » n'apparaît **que** dans `confidentialite/page.tsx` : `grep -ric "RGPD" src/data/*.ts` retourne 0. Le seul argument d'hébergement européen est une ligne de la page signup (`translations.ts:207`, « Hébergé en Europe ») — sur une page en `noindex`.
|
||||||
|
|
||||||
|
### M5 — Cas clients : aucune preuve vérifiable de l'extérieur
|
||||||
|
|
||||||
|
`src/data/cas-clients.ts` donne pour chaque client `client`, `year`, `location` (`:49-52`, `:223-225`, `:397-399`), mais l'interface `CasClient` (`:36-42`) ne prévoit **ni URL du site client, ni lien vers une fiche store, ni témoignage, ni logo**.
|
||||||
|
|
||||||
|
- Aucun témoignage nommé : zéro occurrence de `quote` / `testimonial` / `author` dans le fichier.
|
||||||
|
- Aucun logo client : `public/` ne contient que le logo MyInfoMate et quatre screenshots génériques.
|
||||||
|
- Aucun lien sortant : pas un seul `href="http"` dans `cas-clients/[slug]/page.tsx`.
|
||||||
|
- Les « résultats » sont qualitatifs — `{value:'2021', label:'Premier déploiement'}`, `{value:'100%', label:'Autonomie éditoriale'}` (`cas-clients.ts:97-100`) : aucun chiffre de fréquentation, de nombre de POI, de langues ou de sessions.
|
||||||
|
- Le schema `Article` (`cas-clients/[slug]/page.tsx:56-65`) n'a ni `image`, ni `dateModified`, ni `about`/`mentions` pointant vers le lieu.
|
||||||
|
|
||||||
|
Les chiffres concrets présents ailleurs restent maigres : `llms.txt:64-68` mentionne iBeacon, offline 100 %, iOS + Android — c'est le contenu le plus factuel du site, et il n'est pas dans le HTML.
|
||||||
|
|
||||||
|
### M6 — Aucune date de mise à jour visible
|
||||||
|
|
||||||
|
`sitemap.ts:18` fixe `lastModified: new Date()`, c'est-à-dire la date du build, appliquée uniformément à toutes les URLs : ce n'est pas un signal de fraîcheur, c'est du bruit. Aucune page n'affiche de date dans son HTML ; les cas clients affichent l'année du projet (`cas-clients/[slug]/page.tsx:99`), pas la date de rédaction.
|
||||||
|
|
||||||
|
### M7 — Deux liens morts et aucun profil social
|
||||||
|
|
||||||
|
- `HomeClient.tsx:766` : `<a href="#">` avec une icône « public » dans le footer — bouton social qui ne pointe nulle part.
|
||||||
|
- `NavBar.tsx:59` et `:149` : logo et « ACCUEIL » en `href="#"` (scroll JS) au lieu de `href={/${lang}}`. Un crawler n'a pas de lien de retour vers la home depuis le header.
|
||||||
|
- Aucun `sameAs` LinkedIn — la création de la page LinkedIn Unov est d'ailleurs encore ouverte dans `TODO-SEO.md:40`.
|
||||||
|
|
||||||
|
### M8 — Images sources non optimisées
|
||||||
|
|
||||||
|
748 Ko, 715 Ko et 560 Ko en PNG pour des screenshots d'app. `next/image` réencode, mais l'optimiseur travaille sur ces sources à chaque cache miss. `myinfomate-logo.png` (246 Ko) sert à la fois de favicon (`layout.tsx:52`), d'image OG de repli (`layout.tsx:61`) et d'image 32 px dans le footer (`HomeClient.tsx:755-760`). Le paquet `sharp` n'est pas dans `package.json` ; le comportement réel de l'optimiseur dans le conteneur `node:22-alpine` est **non vérifiable depuis le code**.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Opportunités (n'existe pas et devrait exister)
|
||||||
|
|
||||||
|
### O1 — Pages par intention manquantes
|
||||||
|
|
||||||
|
Aucune de ces routes n'existe dans `src/app/` :
|
||||||
|
|
||||||
|
| URL attendue | État | Commentaire |
|
||||||
|
|---|---|---|
|
||||||
|
| `/tarifs` | ❌ | Les prix ne vivent que dans des sections `#pricing` de la home et des six pages segment. Une requête « prix audioguide musée » n'a aucune page à faire remonter. Le contenu existe déjà (`SegmentPageClient.tsx:395-628`) — il suffit de l'extraire dans une route. |
|
||||||
|
| `/assistant-ia` | ❌ | **Le différenciateur n'a pas de page.** Il est une section de la home (`HomeClient.tsx:170-260`) et un paragraphe de `llms.txt:42-49`. Face à Guideius ou izi.TRAVEL, c'est l'argument qui n'existe nulle part ailleurs — et il n'est pas adressable. |
|
||||||
|
| `/borne-kiosk` | ❌ | Le kiosk n'est qu'un mode de déploiement dans `#deployment-modes` (`translations.ts:53`) ; le cas Visit Namur porte entièrement dessus. Mérite une page. |
|
||||||
|
| `/visite-offline-sans-reseau` | ❌ | Le mode offline est un module (`ModulesSection.tsx:12`) dont la description **n'est même pas dans le HTML** (bloquant B2). Le cas Fort de Saint-Héribert est un argument offline parfait (iBeacon, aucune couverture réseau). |
|
||||||
|
| `/musee-plein-air` | ❌ | Partiellement couvert par `/parcs-naturels`. |
|
||||||
|
| `/lunettes-connectees` | ❌ | Une seule occurrence dans tout le contenu : `translations.ts:60`, « Meta Quest et lunettes connectées », dans un bloc « à venir ». Pas de page, pas de schema. |
|
||||||
|
| `/application-office-de-tourisme` | ✅ équivalent | `/{lang}/offices-tourisme` existe et est complet. |
|
||||||
|
|
||||||
|
### O2 — Vocabulaire de l'acheteur culturel : absent
|
||||||
|
|
||||||
|
`grep -ric` sur `src/data/translations.ts`, `segments.ts`, `cas-clients.ts` :
|
||||||
|
|
||||||
|
| Terme | Occurrences |
|
||||||
|
|---|---|
|
||||||
|
| « médiation numérique » | **0** |
|
||||||
|
| « scénographie » | **0** |
|
||||||
|
| « cartel numérique » | **0** |
|
||||||
|
| « accessibilité » | **0** |
|
||||||
|
| « Access-i » | **0** |
|
||||||
|
| « marché public » | **0** |
|
||||||
|
| « RGPD » | **0** (hors page confidentialité) |
|
||||||
|
| « réalité augmentée » | **0** |
|
||||||
|
| « BYOD » | 8 (bon) |
|
||||||
|
| « audioguide » / « audio guide » | 24 / 30 (bon) |
|
||||||
|
| « Namur » | 34 (bon, surtout via les cas clients) |
|
||||||
|
| « Wallonie » | 2 |
|
||||||
|
| « Belgique » | 3 (uniquement dans `cas-clients.ts`) |
|
||||||
|
|
||||||
|
Le site parle la langue du produit, pas celle du conservateur ni celle du service marchés publics. « Médiation numérique » est le terme employé par les appels à projets de la Fédération Wallonie-Bruxelles : ne pas l'avoir écrit une seule fois est une occasion manquée gratuite.
|
||||||
|
|
||||||
|
### O3 — Aucune page marchés publics
|
||||||
|
|
||||||
|
Rien dans le repo sur les seuils, la procédure de marché de faible montant, la capacité à répondre à un cahier des charges, ni de document type. C'est pourtant l'objection numéro un d'une commune ou d'une province.
|
||||||
|
|
||||||
|
### O4 — Aucune page comparative
|
||||||
|
|
||||||
|
`src/app/` ne contient aucune route `comparatif`. Le comparatif existe **à l'intérieur** des pages segment (`Segment.comparison`, `segments.ts:23-26`) mais compare des catégories abstraites (« App visiteur générique », « Fiches pédagogiques papier »). Les seuls concurrents nommés le sont dans les meta descriptions (« Alternative à Smartify », `segments.ts:81`) et dans un pain point (`segments.ts:~120` : « Smartify, SmartGuide ou STQRY coûtent entre €100 et €925/mois »). **Aucune mention de Guideius, izi.TRAVEL, MySmartJourney, Musa Guide, Cirkwi ou Apptree** dans tout le repo — alors que ce sont les noms réellement tapés par un acheteur belge ou français.
|
||||||
|
|
||||||
|
Ce n'est pas une erreur, c'est le levier GEO le plus rentable qui reste : les pages « alternative à X » sont exactement ce qu'un LLM ingère pour répondre à une question de comparaison. `TODO-SEO.md:56-59` les liste déjà comme à faire.
|
||||||
|
|
||||||
|
### O5 — Aucun blog
|
||||||
|
|
||||||
|
`src/app/` ne contient aucune route `blog`, `ressources` ou `articles`. `TODO-SEO.md:49-54` a déjà les cinq sujets d'articles identifiés ; aucun n'est écrit. Le seul contenu éditorial du site est du contenu produit — pas un texte ne répond à une question que se pose un responsable de musée avant d'avoir entendu parler de MyInfoMate.
|
||||||
|
|
||||||
|
### O6 — `llms.txt` : bon fichier, trois angles morts
|
||||||
|
|
||||||
|
`public/llms.txt` est de bonne facture (85 lignes, structuré, avec liens vers les trois cas clients). Ses faiblesses :
|
||||||
|
|
||||||
|
- **Il est uniquement en anglais** (`llms.txt:3`) alors que le marché cible est francophone. Un LLM interrogé en français citera plus volontiers une source française.
|
||||||
|
- **Il n'est pas référencé dans `robots.txt`**, ni lié depuis le HTML.
|
||||||
|
- Les prix y sont incomplets (`llms.txt:74`, « Starting from €39/month ») alors que la grille 39 / 99 / 179 est publique sur le site.
|
||||||
|
|
||||||
|
### O7 — Pas de FAQ sur la homepage
|
||||||
|
|
||||||
|
Les six pages segment ont chacune six questions et un `FAQPage` JSON-LD (`[segment]/page.tsx:65-76`) — c'est très bien fait. La homepage n'a **aucune** FAQ ni `FAQPage`. C'est pourtant la page qu'un LLM atteint en premier.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Plan d'action priorisé
|
||||||
|
|
||||||
|
Trié par ratio impact / effort. **T** = correctif technique, **C** = écriture de contenu.
|
||||||
|
|
||||||
|
| # | Action | Type | Impact | Effort |
|
||||||
|
|---|---|---|---|---|
|
||||||
|
| 1 | Inverser `h2`/`h3` sur les 12 sections concernées (`HomeClient.tsx:78,126,181,301,421,474` ; `SegmentPageClient.tsx:310,333,363,398,636` ; `ModulesSection.tsx:34`) | T | Moyen | **0,5 h** |
|
||||||
|
| 2 | Enrichir le schema `Organization` : `address`, `areaServed: ["BE","FR","LU"]`, `vatID: "BE0776895467"`, `sameAs` (`[lang]/page.tsx:70-81`) | T | **Fort** | **0,5 h** |
|
||||||
|
| 3 | Rendre les 9 panneaux de `ModulesSection` dans le DOM, masquer en CSS au lieu de `modules[activeModule]` (`ModulesSection.tsx:73,125`) — récupère « offline » et « escape game » dans le HTML | T | **Fort** | **1 h** |
|
||||||
|
| 4 | Passer `SoftwareApplication.offers` à un tableau de 3 `Offer` + `AggregateOffer` 39–179 € (`[lang]/page.tsx:100`, `[segment]/page.tsx:84`) | T | **Fort** | **1 h** |
|
||||||
|
| 5 | Corriger les liens morts : footer `href="#"` (`HomeClient.tsx:766`), logo et ACCUEIL de la NavBar (`NavBar.tsx:59,149`) → `/{lang}` | T | Moyen | **0,5 h** |
|
||||||
|
| 6 | Traduire `llms.txt` en français (ou publier FR + `llms-en.txt`), y ajouter la grille 39/99/179 et le référencer depuis `robots.txt` | C | **Fort** | **1,5 h** |
|
||||||
|
| 7 | Déplacer `resolveLocale()`/`generateMetadata` de `layout.tsx:36` vers un `[lang]/layout.tsx` → réactive le prérendu statique des 46 URLs | T | **Fort** | **2–3 h** |
|
||||||
|
| 8 | Créer `/{lang}/tarifs` en réutilisant la section pricing existante + une FAQ tarifaire | T+C | **Fort** | **3 h** |
|
||||||
|
| 9 | Créer `/{lang}/assistant-ia` — le différenciateur mérite son URL, avec FAQ et schema | C | **Fort** | **4 h** |
|
||||||
|
| 10 | Ajouter un `FAQPage` de 6–8 questions en bas de homepage (réutiliser le format de `segments.ts`) | C | Moyen | **3 h** |
|
||||||
|
| 11 | Ajouter au type `CasClient` : `clientUrl`, `storeUrls`, `testimonial {quote, name, role}` — et les remplir après accord des 3 clients | T+C | **Fort** | **4 h** + relance clients |
|
||||||
|
| 12 | Injecter le vocabulaire acheteur (« médiation numérique », « accessibilité », « scénographie », « parcours de visite », « RGPD », « hébergement européen ») dans `translations.ts` et les 6 segments FR | C | **Fort** | **4–6 h** |
|
||||||
|
| 13 | Ajouter `BreadcrumbList` sur les pages segment et cas clients | T | Faible | **1 h** |
|
||||||
|
| 14 | Créer `/{lang}/marches-publics` : seuils, marché de faible montant, capacité à répondre, coordonnées BCE/TVA | C | **Fort** (public belge) | **4 h** |
|
||||||
|
| 15 | Traduire `/mentions-legales` et `/confidentialite` en 4 langues et les faire passer sous `[lang]` (ajuster `proxy.ts:5`) | T+C | Moyen | **3 h** |
|
||||||
|
| 16 | Recompresser les 4 PNG de `public/` (748 / 715 / 560 / 246 Ko → cible < 150 Ko) et produire un logo 32 px distinct du logo OG | T | Moyen | **1 h** |
|
||||||
|
| 17 | Créer `/{lang}/borne-kiosk` et `/{lang}/visite-offline-sans-reseau`, adossées aux cas Visit Namur et Fort de Saint-Héribert | C | Moyen | **6 h** |
|
||||||
|
| 18 | Trois pages comparatives : `myinfomate-vs-izi-travel`, `myinfomate-vs-guideius`, `myinfomate-vs-smartify` — factuelles, sourcées, sans dénigrement | C | **Fort** (GEO) | **8 h** |
|
||||||
|
| 19 | Créer `/{lang}/lunettes-connectees` (à faire quand le module sera démontrable — cf. `DOCS/rayban-meta-integration.md`) | C | Faible aujourd'hui | **4 h** |
|
||||||
|
| 20 | Ouvrir un blog `/{lang}/ressources` avec les 5 articles déjà listés dans `TODO-SEO.md:49-54` | C | **Fort** à 6 mois | **20 h+** |
|
||||||
|
| 21 | Remplacer `lastModified: new Date()` par une date réelle par contenu (`sitemap.ts:18`) et afficher une date de mise à jour sur les cas clients | T | Faible | **2 h** |
|
||||||
|
|
||||||
|
**Séquence recommandée.** Les items 1 à 6 tiennent en une demi-journée et corrigent l'essentiel des pertes gratuites. L'item 7 est le seul chantier technique de fond. Les items 8, 9, 12 et 14 sont ceux qui changent réellement la réponse d'un LLM à « quelle solution d'audioguide pour mon musée en Belgique ? ».
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Annexe — ce qui est déjà bien fait
|
||||||
|
|
||||||
|
À ne pas casser :
|
||||||
|
|
||||||
|
- Le contenu textuel est intégralement dans le HTML servi — ce n'est pas une SPA client-only.
|
||||||
|
- Aucun crawler IA n'est bloqué (`robots.txt:1-2`).
|
||||||
|
- `llms.txt` existe et est structuré — la majorité des concurrents n'en ont pas.
|
||||||
|
- Les six pages segment sont de vraies pages d'intention : ~1 130 mots FR, pain points, features, comparatif, six FAQ, le tout en quatre langues, avec `FAQPage` JSON-LD.
|
||||||
|
- Les FAQ des pages segment sont collapsées en CSS (`max-h-0`, `SegmentPageClient.tsx:652`) et non conditionnées par un `useState` : le texte est bien dans le DOM. C'est le bon pattern — exactement ce que `ModulesSection` ne fait pas.
|
||||||
|
- `hreflang` complet avec `x-default`, sur chaque page **et** dans le sitemap.
|
||||||
|
- `/signup` est correctement en `noindex, follow` (`signup/page.tsx:41`).
|
||||||
|
- OG image générée dynamiquement et localisée, avec une variante par segment.
|
||||||
|
- Les prix (39 / 99 / 179 €) sont en texte brut dans le HTML, pas en image.
|
||||||
835
package-lock.json
generated
@ -11,7 +11,8 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"next": "16.1.6",
|
"next": "16.1.6",
|
||||||
"react": "19.2.3",
|
"react": "19.2.3",
|
||||||
"react-dom": "19.2.3"
|
"react-dom": "19.2.3",
|
||||||
|
"sharp": "^0.35.4"
|
||||||
},
|
},
|
||||||
"browserslist": [
|
"browserslist": [
|
||||||
"last 2 Chrome versions",
|
"last 2 Chrome versions",
|
||||||
|
|||||||
BIN
public/app-map.jpg
Normal file
|
After Width: | Height: | Size: 64 KiB |
BIN
public/app-screenshot-1.jpg
Normal file
|
After Width: | Height: | Size: 128 KiB |
|
Before Width: | Height: | Size: 731 KiB |
BIN
public/app-screenshot-2.jpg
Normal file
|
After Width: | Height: | Size: 121 KiB |
|
Before Width: | Height: | Size: 547 KiB |
BIN
public/app-screenshot-3.jpg
Normal file
|
After Width: | Height: | Size: 107 KiB |
|
Before Width: | Height: | Size: 699 KiB |
91
public/llms-en.txt
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
# MyInfoMate
|
||||||
|
|
||||||
|
> MyInfoMate is a SaaS platform that digitalizes the visitor experience for cultural venues, tourism offices, parks, hotels, and events. It enables venue managers to create, manage and distribute interactive content on mobile apps, tablet kiosks, and web — with no coding required.
|
||||||
|
|
||||||
|
Developed by **Unov**, based in Namur, Wallonia (Belgium).
|
||||||
|
Contact: contact@unov.be
|
||||||
|
Website: https://myinfomate.be
|
||||||
|
French version of this file: https://myinfomate.be/llms.txt
|
||||||
|
|
||||||
|
## What is MyInfoMate?
|
||||||
|
|
||||||
|
MyInfoMate is a content management and distribution platform (CMS) for any venue that welcomes visitors. It provides:
|
||||||
|
- A back-office web interface to create and manage interactive visitor journeys
|
||||||
|
- A white-label native mobile app (iOS & Android) for visitors on their own devices (BYOD)
|
||||||
|
- A tablet kiosk app for fixed installations
|
||||||
|
- A web app accessible from any browser, no install needed
|
||||||
|
|
||||||
|
All deployments are managed from a single CMS. Content can be updated in real time from a browser.
|
||||||
|
|
||||||
|
## Key Features
|
||||||
|
|
||||||
|
- **Interactive Maps**: Real-time geolocation, clickable points of interest, route navigation
|
||||||
|
- **Games & Quizzes**: Treasure hunts, knowledge quizzes, gamified trails, escape games with narrative and riddles
|
||||||
|
- **Audio & Video**: Immersive audio guides, HD video, multimedia content
|
||||||
|
- **Articles & PDF**: Descriptive sheets, brochures, digitized catalogs
|
||||||
|
- **Agenda & Events**: Dynamic event calendar and scheduling
|
||||||
|
- **Offline Access**: Automatic content download for areas without Wi-Fi or 4G
|
||||||
|
- **Web & Social Content**: Embedded forms, social feeds, external links
|
||||||
|
- **Statistics & Data**: Visitor behavior analytics, engagement tracking, content popularity
|
||||||
|
- **Escape Game & Trails**: The only CMS on the market with a full escape game module built in
|
||||||
|
- **AI Visitor Assistant**: Generative AI guide available 24/7, multilingual, scoped strictly to the venue's content
|
||||||
|
- **Push Notifications**: Real-time alerts to visitors
|
||||||
|
- **Automatic Translation**: Content auto-translated across languages
|
||||||
|
- **White Label**: Full interface customization with venue's brand, logo, colors, and typography
|
||||||
|
|
||||||
|
## Deployment Modes
|
||||||
|
|
||||||
|
1. **Mobile App (BYOD)** — visitors use their own smartphone; white-label app published on App Store & Google Play
|
||||||
|
2. **Tablet Kiosk** — robust pre-installed app on venue-managed tablet fleets
|
||||||
|
3. **Web App** — accessible from any modern browser, no install required
|
||||||
|
4. **VR & AR** (coming soon) — immersive experiences on Meta Quest and connected glasses
|
||||||
|
|
||||||
|
## AI Assistant
|
||||||
|
|
||||||
|
The MyInfoMate AI assistant is a generative AI guide integrated into the visitor app:
|
||||||
|
- Answers visitor questions in their own language (French, English, Dutch, German, and more)
|
||||||
|
- Knows the venue's content: points of interest, exhibitions, services
|
||||||
|
- Maintains conversation context throughout the visit
|
||||||
|
- Strictly scoped to the venue — no off-topic responses
|
||||||
|
- Available 24/7
|
||||||
|
|
||||||
|
## Target Venues
|
||||||
|
|
||||||
|
- **Museums & Heritage**: digitize collections, create multimedia trails, multilingual smart guide
|
||||||
|
- **Tourism Offices**: city/region maps, event agendas, 24/7 AI assistant
|
||||||
|
- **Parks & Natural Sites**: trail markers, biodiversity content, offline quizzes and treasure hunts
|
||||||
|
- **Hotels & Leisure**: interactive estate map, services, virtual concierge
|
||||||
|
- **Events & Exhibitions**: festivals, trade shows, fairs — interactive maps, real-time agenda
|
||||||
|
- **Education & Culture**: campuses, science centers, libraries — guided content per space
|
||||||
|
|
||||||
|
## Customer References
|
||||||
|
|
||||||
|
Real venues using MyInfoMate (Belgium):
|
||||||
|
|
||||||
|
- **Musée de la Fraise de Wépion** (2021) — first MyInfoMate customer. Started with a tablet kiosk solution (the original use case that drove the creation of MyInfoMate), then extended to a visitor mobile app covering the museum and the fruit garden trail. Demonstrates the no-code CMS autonomy for a small museum team. Case study: https://myinfomate.be/en/cas-clients/musee-de-la-fraise
|
||||||
|
|
||||||
|
- **Fort de Saint-Héribert** (2023) — first mobile deployment of MyInfoMate, on a historic underground fort. 100% offline mode (no Wi-Fi possible in the galleries), iBeacon beacons for indoor location tracking, QR codes, audio guide, iOS + Android. Case study: https://myinfomate.be/en/cas-clients/fort-de-saint-heribert
|
||||||
|
|
||||||
|
- **Visit Namur** (Tourist Office of Namur, 2024) — interactive tablet kiosks deployed at the tourism office. Interactive city map with geolocated points of interest, real-time events agenda, itinerary planning. Case study: https://myinfomate.be/en/cas-clients/visit-namur
|
||||||
|
|
||||||
|
All case studies index: https://myinfomate.be/en/cas-clients
|
||||||
|
|
||||||
|
## Pricing
|
||||||
|
|
||||||
|
Monthly subscription, prices excluding VAT. Full pricing: https://myinfomate.be/en#pricing
|
||||||
|
|
||||||
|
- **Essentiel — €39/month**: visitor web app + kiosk mode, CMS back-office, all content sections, 1 GB storage, basic visitor stats. No commitment. 14-day free trial, no credit card required.
|
||||||
|
- **Pro — €99/month**: everything in Essentiel + your own white-label mobile app on the App Store & Google Play, offline mode + BLE beacons, push notifications, 15 GB storage. Setup fee + 12-month commitment.
|
||||||
|
- **Premium — €179/month**: everything in Pro + AI visitor assistant (≈ 2,000 visitor questions / month), automatic translation, advanced stats, 50 GB storage. Setup fee + 12-month commitment.
|
||||||
|
- **Enterprise — custom quote**: multi-site organizations, unlimited storage, custom AI quota, enhanced SLA, dedicated support, custom development.
|
||||||
|
|
||||||
|
Multi-year contracts (2–3 years, annual billing) available with preferential rates.
|
||||||
|
|
||||||
|
## Company
|
||||||
|
|
||||||
|
**Unov** — software company based in Namur, Belgium.
|
||||||
|
Address: Rue René Copette 3, 5020 Namur, Belgium — VAT BE 0776.895.467
|
||||||
|
MyInfoMate is already deployed in Namur and across Wallonia.
|
||||||
|
Email: contact@unov.be
|
||||||
|
Website: https://myinfomate.be
|
||||||
|
LinkedIn: https://www.linkedin.com/showcase/myinfomate/
|
||||||
124
public/llms.txt
@ -1,85 +1,83 @@
|
|||||||
# MyInfoMate
|
# MyInfoMate
|
||||||
|
|
||||||
> MyInfoMate is a SaaS platform that digitalizes the visitor experience for cultural venues, tourism offices, parks, hotels, and events. It enables venue managers to create, manage and distribute interactive content on mobile apps, tablet kiosks, and web — with no coding required.
|
> MyInfoMate est une plateforme SaaS belge de médiation numérique pour les lieux qui accueillent du public : musées, sites patrimoniaux, offices de tourisme, parcs naturels, hôtels et événements. Depuis un seul back-office, sans code, le lieu crée ses contenus et parcours de visite et les diffuse sur une application mobile à son nom, sur des bornes tablettes et sur le web.
|
||||||
|
|
||||||
Developed by **Unov**, based in Namur, Wallonia (Belgium).
|
Éditeur : **Unov**, Namur, Wallonie (Belgique).
|
||||||
Contact: contact@unov.be
|
Contact : contact@unov.be — +32 498 07 95 35
|
||||||
Website: https://myinfomate.be
|
Site : https://myinfomate.be
|
||||||
|
English version of this file: https://myinfomate.be/llms-en.txt
|
||||||
|
|
||||||
## What is MyInfoMate?
|
## En bref
|
||||||
|
|
||||||
MyInfoMate is a content management and distribution platform (CMS) for any venue that welcomes visitors. It provides:
|
- Application guide de visite / audioguide numérique pour musées et lieux culturels
|
||||||
- A back-office web interface to create and manage interactive visitor journeys
|
- Back-office no-code : l'équipe du lieu met elle-même à jour textes, images, audio, vidéo et agenda, en temps réel
|
||||||
- A white-label native mobile app (iOS & Android) for visitors on their own devices (BYOD)
|
- Trois canaux alimentés par le même contenu : application mobile (BYOD), borne tablette (kiosk), application web sans installation
|
||||||
- A tablet kiosk app for fixed installations
|
- Application en marque blanche : logo, couleurs et typographie du lieu, publiée sur l'App Store et Google Play
|
||||||
- A web app accessible from any browser, no install needed
|
- Assistant IA visiteur multilingue, limité aux contenus du lieu
|
||||||
|
- Mode hors ligne pour les sites sans réseau (caves, forts, sites en plein air)
|
||||||
|
- Déjà déployé en Wallonie ; interface et support en français, anglais, néerlandais et allemand
|
||||||
|
|
||||||
All deployments are managed from a single CMS. Content can be updated in real time from a browser.
|
## Fonctionnalités
|
||||||
|
|
||||||
## Key Features
|
- **Cartes & plans** : carte interactive, géolocalisation en temps réel, points d'intérêt cliquables, itinéraires
|
||||||
|
- **Audio & vidéo** : audioguides, vidéos HD, témoignages
|
||||||
|
- **Jeux & quiz** : quiz, chasses au trésor, parcours gamifiés
|
||||||
|
- **Escape game & parcours** : escape games avec narration et énigmes, chasses au trésor, parcours guidés séquentiels — module d'escape game complet intégré au CMS
|
||||||
|
- **Articles & PDF** : fiches descriptives, brochures, catalogues numérisés
|
||||||
|
- **Agenda & événements** : programmation dynamique (expositions, conférences, ateliers)
|
||||||
|
- **Accès hors ligne** : téléchargement des contenus pour une visite sans 4G ni Wi-Fi ; balises BLE (iBeacon) et QR codes pour déclencher les contenus sur place
|
||||||
|
- **Contenu web & social** : formulaires, réseaux sociaux, liens externes
|
||||||
|
- **Statistiques** : fréquentation, contenus populaires, engagement
|
||||||
|
- **Notifications push** et **traduction automatique** des contenus
|
||||||
|
- **Marque blanche** : personnalisation complète de l'interface
|
||||||
|
|
||||||
- **Interactive Maps**: Real-time geolocation, clickable points of interest, route navigation
|
## Modes de déploiement
|
||||||
- **Games & Quizzes**: Treasure hunts, knowledge quizzes, gamified trails, escape games with narrative and riddles
|
|
||||||
- **Audio & Video**: Immersive audio guides, HD video, multimedia content
|
|
||||||
- **Articles & PDF**: Descriptive sheets, brochures, digitized catalogs
|
|
||||||
- **Agenda & Events**: Dynamic event calendar and scheduling
|
|
||||||
- **Offline Access**: Automatic content download for areas without Wi-Fi or 4G
|
|
||||||
- **Web & Social Content**: Embedded forms, social feeds, external links
|
|
||||||
- **Statistics & Data**: Visitor behavior analytics, engagement tracking, content popularity
|
|
||||||
- **Escape Game & Trails**: The only CMS on the market with a full escape game module built in
|
|
||||||
- **AI Visitor Assistant**: Generative AI guide available 24/7, multilingual, scoped strictly to the venue's content
|
|
||||||
- **Push Notifications**: Real-time alerts to visitors
|
|
||||||
- **Automatic Translation**: Content auto-translated across languages
|
|
||||||
- **White Label**: Full interface customization with venue's brand, logo, colors, and typography
|
|
||||||
|
|
||||||
## Deployment Modes
|
1. **Application mobile (BYOD)** — le visiteur utilise son propre smartphone ; application à la marque du lieu sur l'App Store et Google Play
|
||||||
|
2. **Borne tablette (kiosk)** — application pré-installée sur les tablettes du lieu, pour l'accueil ou les salles
|
||||||
|
3. **Application web** — ouverte depuis un navigateur ou un QR code, sans installation
|
||||||
|
4. **Réalité virtuelle & augmentée** (à venir) — expériences immersives sur Meta Quest et lunettes connectées
|
||||||
|
|
||||||
1. **Mobile App (BYOD)** — visitors use their own smartphone; white-label app published on App Store & Google Play
|
## Assistant IA visiteur
|
||||||
2. **Tablet Kiosk** — robust pre-installed app on venue-managed tablet fleets
|
|
||||||
3. **Web App** — accessible from any modern browser, no install required
|
|
||||||
4. **VR & AR** (coming soon) — immersive experiences on Meta Quest and connected glasses
|
|
||||||
|
|
||||||
## AI Assistant
|
- Répond aux questions des visiteurs dans leur langue (français, anglais, néerlandais, allemand, et d'autres)
|
||||||
|
- S'appuie uniquement sur les contenus du lieu : points d'intérêt, expositions, services — pas de réponses hors sujet
|
||||||
|
- Garde le contexte de la conversation pendant toute la visite
|
||||||
|
- Disponible 24 h/24
|
||||||
|
- Inclus dans le plan Premium (≈ 2 000 questions de visiteurs par mois)
|
||||||
|
|
||||||
The MyInfoMate AI assistant is a generative AI guide integrated into the visitor app:
|
## Pour qui
|
||||||
- Answers visitor questions in their own language (French, English, Dutch, German, and more)
|
|
||||||
- Knows the venue's content: points of interest, exhibitions, services
|
|
||||||
- Maintains conversation context throughout the visit
|
|
||||||
- Strictly scoped to the venue — no off-topic responses
|
|
||||||
- Available 24/7
|
|
||||||
|
|
||||||
## Target Venues
|
- **Musées & patrimoine** : parcours multimédias, audioguide multilingue, collections numérisées — https://myinfomate.be/fr/musees
|
||||||
|
- **Offices de tourisme** : carte de la ville ou de la région, agenda des événements, borne d'accueil, assistant 24 h/24 — https://myinfomate.be/fr/offices-tourisme
|
||||||
|
- **Parcs & sites naturels** : sentiers balisés, biodiversité, jeux de piste, visite hors ligne — https://myinfomate.be/fr/parcs-naturels
|
||||||
|
- **Hôtels & loisirs** : carte du domaine, services, concierge virtuel — https://myinfomate.be/fr/hotels-loisirs
|
||||||
|
- **Événementiel** : festivals, salons, foires — plan interactif, agenda en temps réel — https://myinfomate.be/fr/evenements
|
||||||
|
- **Éducation & culture** : campus, centres de science, bibliothèques — https://myinfomate.be/fr/education-culture
|
||||||
|
|
||||||
- **Museums & Heritage**: digitize collections, create multimedia trails, multilingual smart guide
|
## Références clients (Belgique)
|
||||||
- **Tourism Offices**: city/region maps, event agendas, 24/7 AI assistant
|
|
||||||
- **Parks & Natural Sites**: trail markers, biodiversity content, offline quizzes and treasure hunts
|
|
||||||
- **Hotels & Leisure**: interactive estate map, services, virtual concierge
|
|
||||||
- **Events & Exhibitions**: festivals, trade shows, fairs — interactive maps, real-time agenda
|
|
||||||
- **Education & Culture**: campuses, science centers, libraries — guided content per space
|
|
||||||
|
|
||||||
## Customer References
|
- **Musée de la Fraise de Wépion** (2021) — premier client MyInfoMate. Borne tablette en novembre 2021, puis application mobile couvrant le musée et le jardin de petits fruits. L'équipe du musée gère ses contenus en autonomie. https://myinfomate.be/fr/cas-clients/musee-de-la-fraise
|
||||||
|
- **Fort de Saint-Héribert** (2023) — application mobile iOS et Android 100 % hors ligne dans un fort souterrain sans réseau : contenu téléchargé à l'entrée, balises iBeacon dans les galeries, QR codes, audioguide. https://myinfomate.be/fr/cas-clients/fort-de-saint-heribert
|
||||||
|
- **Visit Namur** (office du tourisme de Namur, 2024) — bornes interactives : carte de la ville, points d'intérêt géolocalisés, agenda des événements, itinéraires. https://myinfomate.be/fr/cas-clients/visit-namur
|
||||||
|
|
||||||
Real venues using MyInfoMate (Belgium):
|
Tous les cas clients : https://myinfomate.be/fr/cas-clients
|
||||||
|
|
||||||
- **Musée de la Fraise de Wépion** (2021) — first MyInfoMate customer. Started with a tablet kiosk solution (the original use case that drove the creation of MyInfoMate), then extended to a visitor mobile app covering the museum and the fruit garden trail. Demonstrates the no-code CMS autonomy for a small museum team. Case study: https://myinfomate.be/fr/cas-clients/musee-de-la-fraise
|
## Tarifs
|
||||||
|
|
||||||
- **Fort de Saint-Héribert** (2023) — first mobile deployment of MyInfoMate, on a historic underground fort. 100% offline mode (no Wi-Fi possible in the galleries), iBeacon beacons for indoor location tracking, QR codes, audio guide, iOS + Android. Case study: https://myinfomate.be/fr/cas-clients/fort-de-saint-heribert
|
Abonnement mensuel, prix hors TVA. Grille complète : https://myinfomate.be/fr#pricing
|
||||||
|
|
||||||
- **Visit Namur** (Tourist Office of Namur, 2024) — interactive tablet kiosks deployed at the tourism office. Interactive city map with geolocated points of interest, real-time events agenda, itinerary planning. Case study: https://myinfomate.be/fr/cas-clients/visit-namur
|
- **Essentiel — 39 €/mois** : application web visiteur + mode kiosk, back-office, toutes les sections de contenu, 1 Go de stockage, statistiques de base. Sans engagement. Essai gratuit de 14 jours, sans carte bancaire.
|
||||||
|
- **Pro — 99 €/mois** : Essentiel + application mobile à votre marque sur l'App Store et Google Play, hors ligne + balises BLE, notifications push, 15 Go de stockage. Frais de mise en place + engagement 12 mois.
|
||||||
|
- **Premium — 179 €/mois** : Pro + assistant IA visiteur (≈ 2 000 questions/mois), traduction automatique, statistiques avancées, 50 Go de stockage. Frais de mise en place + engagement 12 mois.
|
||||||
|
- **Enterprise — sur devis** : organisations multi-sites, stockage illimité, quota IA sur mesure, SLA renforcé, accompagnement dédié, développements spécifiques.
|
||||||
|
|
||||||
All case studies index: https://myinfomate.be/fr/cas-clients
|
Engagements de 2 ou 3 ans possibles, avec facturation annuelle et tarif préférentiel (adapté aux financements pluriannuels).
|
||||||
|
|
||||||
## Pricing
|
## Société
|
||||||
|
|
||||||
Subscription-based (monthly, excl. VAT). Starting from **€39/month**.
|
**Unov** — éditeur de logiciels, Namur (Belgique).
|
||||||
- No commitment for basic plans
|
Rue René Copette 3, 5020 Namur — TVA BE 0776.895.467
|
||||||
- Setup fee + 12-month commitment for native mobile app plans
|
Données hébergées en Europe.
|
||||||
- Enterprise: custom quote for multi-site organizations or specific needs (custom development, enhanced SLA)
|
Mentions légales : https://myinfomate.be/mentions-legales — Confidentialité : https://myinfomate.be/confidentialite
|
||||||
- Multi-year contracts (2–3 years) available with preferential rates
|
LinkedIn : https://www.linkedin.com/showcase/myinfomate/
|
||||||
|
|
||||||
## Company
|
|
||||||
|
|
||||||
**Unov** — software company based in Namur, Belgium.
|
|
||||||
MyInfoMate is already deployed in Namur and across Wallonia.
|
|
||||||
Email: contact@unov.be
|
|
||||||
Website: https://myinfomate.be
|
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 182 KiB |
|
Before Width: | Height: | Size: 240 KiB After Width: | Height: | Size: 57 KiB |
@ -3,3 +3,6 @@ Allow: /
|
|||||||
Disallow: /api/
|
Disallow: /api/
|
||||||
|
|
||||||
Sitemap: https://myinfomate.be/sitemap.xml
|
Sitemap: https://myinfomate.be/sitemap.xml
|
||||||
|
|
||||||
|
# Résumé du produit pour les assistants IA / product summary for LLMs
|
||||||
|
# https://myinfomate.be/llms.txt (fr) — https://myinfomate.be/llms-en.txt (en)
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import Image from 'next/image';
|
import Image from 'next/image';
|
||||||
|
import Link from 'next/link';
|
||||||
import { resolveImage } from '@/data/stitch-images';
|
import { resolveImage } from '@/data/stitch-images';
|
||||||
import translations, { Language } from '@/data/translations';
|
import translations, { Language } from '@/data/translations';
|
||||||
import { getAllCasClients } from '@/data/cas-clients';
|
import { getAllCasClients } from '@/data/cas-clients';
|
||||||
@ -6,6 +7,7 @@ import NavBar from '@/components/NavBar';
|
|||||||
import Reveal from '@/components/Reveal';
|
import Reveal from '@/components/Reveal';
|
||||||
import ModulesSection from '@/components/ModulesSection';
|
import ModulesSection from '@/components/ModulesSection';
|
||||||
import ContactForm from '@/components/ContactForm';
|
import ContactForm from '@/components/ContactForm';
|
||||||
|
import PricingPlans from '@/components/PricingPlans';
|
||||||
|
|
||||||
export default function Home({ lang }: { lang: Language }) {
|
export default function Home({ lang }: { lang: Language }) {
|
||||||
const t = translations[lang];
|
const t = translations[lang];
|
||||||
@ -47,23 +49,23 @@ export default function Home({ lang }: { lang: Language }) {
|
|||||||
<div className="absolute top-0 left-0 w-full h-full lg:h-[85%] bg-slate-900 rounded-2xl lg:rounded-3xl overflow-hidden shadow-2xl border-4 border-slate-800 z-10 transform lg:-rotate-2">
|
<div className="absolute top-0 left-0 w-full h-full lg:h-[85%] bg-slate-900 rounded-2xl lg:rounded-3xl overflow-hidden shadow-2xl border-4 border-slate-800 z-10 transform lg:-rotate-2">
|
||||||
<Image
|
<Image
|
||||||
src={resolveImage("{{DATA:IMAGE:IMAGE_4}}")}
|
src={resolveImage("{{DATA:IMAGE:IMAGE_4}}")}
|
||||||
alt="Modern Interactive Map Interface"
|
alt={t.imgAlt.map}
|
||||||
fill
|
fill
|
||||||
className="object-cover object-top opacity-80"
|
className="object-cover object-center"
|
||||||
priority
|
priority
|
||||||
sizes="(max-width: 1024px) 100vw, 50vw"
|
sizes="(max-width: 1024px) 100vw, 50vw"
|
||||||
/>
|
/>
|
||||||
<div className="absolute top-4 left-6 bg-white/90 backdrop-blur px-4 py-2 rounded-xl shadow-lg border border-primary/20">
|
<div className="absolute bottom-4 left-6 bg-white/90 backdrop-blur px-4 py-2 rounded-xl shadow-lg border border-primary/20">
|
||||||
<p className="text-[10px] font-bold text-slate-400 uppercase">{t.mockup.mapTitle}</p>
|
<p className="text-[10px] font-bold text-slate-400 uppercase">{t.mockup.mapTitle}</p>
|
||||||
<p className="text-xs font-extrabold text-slate-900">{t.mockup.mapSubtitle}</p>
|
<p className="text-xs font-extrabold text-slate-900">{t.mockup.mapSubtitle}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="hidden sm:block absolute -bottom-6 -left-6 lg:-bottom-10 lg:-left-10 w-1/3 aspect-[9/19] bg-white rounded-[1.5rem] lg:rounded-[2rem] shadow-2xl border-2 lg:border-4 border-slate-900 z-30 transform rotate-3 overflow-hidden">
|
<div className="hidden sm:block absolute -bottom-6 -left-6 lg:-bottom-10 lg:-left-10 w-1/3 aspect-[9/19] bg-white rounded-[1.5rem] lg:rounded-[2rem] shadow-2xl border-2 lg:border-4 border-slate-900 z-30 transform rotate-3 overflow-hidden">
|
||||||
<Image src={resolveImage("{{DATA:IMAGE:IMAGE_5}}")} alt="MyInfoMate agenda module on mobile" fill className="object-cover object-top" sizes="20vw" />
|
<Image src={resolveImage("{{DATA:IMAGE:IMAGE_5}}")} alt={t.imgAlt.appHome} fill className="object-cover object-top" sizes="20vw" />
|
||||||
<div className="absolute top-1 left-1/2 -translate-x-1/2 w-6 lg:w-8 h-1 lg:h-2 bg-slate-900 rounded-full"></div>
|
<div className="absolute top-1 left-1/2 -translate-x-1/2 w-6 lg:w-8 h-1 lg:h-2 bg-slate-900 rounded-full"></div>
|
||||||
</div>
|
</div>
|
||||||
<div className="absolute -bottom-4 -right-4 lg:-bottom-6 lg:-right-6 w-1/3 lg:w-[35%] aspect-[9/19] bg-white rounded-[1.5rem] lg:rounded-[2rem] shadow-2xl border-2 lg:border-4 border-slate-900 z-20 transform -rotate-6 overflow-hidden">
|
<div className="absolute -bottom-4 -right-4 lg:-bottom-6 lg:-right-6 w-1/3 lg:w-[35%] aspect-[9/19] bg-white rounded-[1.5rem] lg:rounded-[2rem] shadow-2xl border-2 lg:border-4 border-slate-900 z-20 transform -rotate-6 overflow-hidden">
|
||||||
<Image src={resolveImage("{{DATA:IMAGE:IMAGE_7}}")} alt="MyInfoMate tours module on mobile" fill className="object-cover object-top" sizes="20vw" />
|
<Image src={resolveImage("{{DATA:IMAGE:IMAGE_7}}")} alt={t.imgAlt.appArticle} fill className="object-cover object-top" sizes="20vw" />
|
||||||
<div className="absolute top-1 left-1/2 -translate-x-1/2 w-6 lg:w-8 h-1 lg:h-2 bg-slate-900 rounded-full"></div>
|
<div className="absolute top-1 left-1/2 -translate-x-1/2 w-6 lg:w-8 h-1 lg:h-2 bg-slate-900 rounded-full"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -75,8 +77,8 @@ export default function Home({ lang }: { lang: Language }) {
|
|||||||
<section className="py-24 bg-white" id="points">
|
<section className="py-24 bg-white" id="points">
|
||||||
<div className="max-w-5xl mx-auto px-6">
|
<div className="max-w-5xl mx-auto px-6">
|
||||||
<Reveal className="text-center mb-16">
|
<Reveal className="text-center mb-16">
|
||||||
<h2 className="text-accent-violet font-extrabold uppercase tracking-widest text-sm mb-4">{t.strategic.sectionLabel}</h2>
|
<p className="text-accent-violet font-extrabold uppercase tracking-widest text-sm mb-4">{t.strategic.sectionLabel}</p>
|
||||||
<h3 className="text-3xl lg:text-5xl font-extrabold text-slate-900 tracking-tight">{t.strategic.sectionTitle}</h3>
|
<h2 className="text-3xl lg:text-5xl font-extrabold text-slate-900 tracking-tight">{t.strategic.sectionTitle}</h2>
|
||||||
</Reveal>
|
</Reveal>
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-x-16 gap-y-10">
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-x-16 gap-y-10">
|
||||||
<Reveal delay={0} className="flex items-start gap-5">
|
<Reveal delay={0} className="flex items-start gap-5">
|
||||||
@ -84,7 +86,7 @@ export default function Home({ lang }: { lang: Language }) {
|
|||||||
<span className="material-symbols-outlined text-2xl">sync</span>
|
<span className="material-symbols-outlined text-2xl">sync</span>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h4 className="text-lg font-extrabold text-slate-900 mb-1">{t.strategic.feature1Title}</h4>
|
<h3 className="text-lg font-extrabold text-slate-900 mb-1">{t.strategic.feature1Title}</h3>
|
||||||
<p className="text-slate-500 leading-relaxed text-sm">{t.strategic.feature1Desc}</p>
|
<p className="text-slate-500 leading-relaxed text-sm">{t.strategic.feature1Desc}</p>
|
||||||
</div>
|
</div>
|
||||||
</Reveal>
|
</Reveal>
|
||||||
@ -93,7 +95,7 @@ export default function Home({ lang }: { lang: Language }) {
|
|||||||
<span className="material-symbols-outlined text-2xl">code_off</span>
|
<span className="material-symbols-outlined text-2xl">code_off</span>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h4 className="text-lg font-extrabold text-slate-900 mb-1">{t.strategic.feature2Title}</h4>
|
<h3 className="text-lg font-extrabold text-slate-900 mb-1">{t.strategic.feature2Title}</h3>
|
||||||
<p className="text-slate-500 leading-relaxed text-sm">{t.strategic.feature2Desc}</p>
|
<p className="text-slate-500 leading-relaxed text-sm">{t.strategic.feature2Desc}</p>
|
||||||
</div>
|
</div>
|
||||||
</Reveal>
|
</Reveal>
|
||||||
@ -102,8 +104,12 @@ export default function Home({ lang }: { lang: Language }) {
|
|||||||
<span className="material-symbols-outlined text-2xl">download_for_offline</span>
|
<span className="material-symbols-outlined text-2xl">download_for_offline</span>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h4 className="text-lg font-extrabold text-slate-900 mb-1">{t.strategic.feature3Title}</h4>
|
<h3 className="text-lg font-extrabold text-slate-900 mb-1">{t.strategic.feature3Title}</h3>
|
||||||
<p className="text-slate-500 leading-relaxed text-sm">{t.strategic.feature3Desc}</p>
|
<p className="text-slate-500 leading-relaxed text-sm">{t.strategic.feature3Desc}</p>
|
||||||
|
<Link href={`/${lang}/visite-hors-ligne`} className="inline-flex items-center gap-1 mt-2 text-primary font-bold text-sm hover:gap-2 transition-all">
|
||||||
|
{t.footer.pageOffline}
|
||||||
|
<span className="material-symbols-outlined text-base">arrow_forward</span>
|
||||||
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</Reveal>
|
</Reveal>
|
||||||
<Reveal delay={240} className="flex items-start gap-5">
|
<Reveal delay={240} className="flex items-start gap-5">
|
||||||
@ -111,7 +117,7 @@ export default function Home({ lang }: { lang: Language }) {
|
|||||||
<span className="material-symbols-outlined text-2xl">dashboard_customize</span>
|
<span className="material-symbols-outlined text-2xl">dashboard_customize</span>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h4 className="text-lg font-extrabold text-slate-900 mb-1">{t.strategic.feature4Title}</h4>
|
<h3 className="text-lg font-extrabold text-slate-900 mb-1">{t.strategic.feature4Title}</h3>
|
||||||
<p className="text-slate-500 leading-relaxed text-sm">{t.strategic.feature4Desc}</p>
|
<p className="text-slate-500 leading-relaxed text-sm">{t.strategic.feature4Desc}</p>
|
||||||
</div>
|
</div>
|
||||||
</Reveal>
|
</Reveal>
|
||||||
@ -123,8 +129,8 @@ export default function Home({ lang }: { lang: Language }) {
|
|||||||
<section className="py-24 bg-slate-50 border-y border-slate-100" id="deployment-modes">
|
<section className="py-24 bg-slate-50 border-y border-slate-100" id="deployment-modes">
|
||||||
<div className="max-w-7xl mx-auto px-6">
|
<div className="max-w-7xl mx-auto px-6">
|
||||||
<Reveal className="text-center mb-16">
|
<Reveal className="text-center mb-16">
|
||||||
<h2 className="text-primary font-extrabold uppercase tracking-widest text-sm mb-4">{t.deployment.sectionLabel}</h2>
|
<p className="text-primary font-extrabold uppercase tracking-widest text-sm mb-4">{t.deployment.sectionLabel}</p>
|
||||||
<h3 className="text-3xl lg:text-5xl font-extrabold text-slate-900 leading-tight mb-6">{t.deployment.sectionTitle}</h3>
|
<h2 className="text-3xl lg:text-5xl font-extrabold text-slate-900 leading-tight mb-6">{t.deployment.sectionTitle}</h2>
|
||||||
<p className="text-lg text-slate-600 max-w-2xl mx-auto">{t.deployment.sectionDesc}</p>
|
<p className="text-lg text-slate-600 max-w-2xl mx-auto">{t.deployment.sectionDesc}</p>
|
||||||
</Reveal>
|
</Reveal>
|
||||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-8">
|
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-8">
|
||||||
@ -132,21 +138,25 @@ export default function Home({ lang }: { lang: Language }) {
|
|||||||
<div className="w-14 h-14 rounded-2xl bg-primary/10 text-primary flex items-center justify-center mb-6 group-hover:bg-primary group-hover:text-white transition-all">
|
<div className="w-14 h-14 rounded-2xl bg-primary/10 text-primary flex items-center justify-center mb-6 group-hover:bg-primary group-hover:text-white transition-all">
|
||||||
<span className="material-symbols-outlined text-3xl">smartphone</span>
|
<span className="material-symbols-outlined text-3xl">smartphone</span>
|
||||||
</div>
|
</div>
|
||||||
<h4 className="text-xl font-extrabold text-slate-900 mb-4">{t.deployment.mode1Title}</h4>
|
<h3 className="text-xl font-extrabold text-slate-900 mb-4">{t.deployment.mode1Title}</h3>
|
||||||
<p className="text-slate-600 text-sm leading-relaxed">{t.deployment.mode1Desc}</p>
|
<p className="text-slate-600 text-sm leading-relaxed">{t.deployment.mode1Desc}</p>
|
||||||
</div></Reveal>
|
</div></Reveal>
|
||||||
<Reveal delay={80}><div className="group p-8 rounded-[2.5rem] bg-white border border-slate-100 shadow-sm hover:shadow-xl transition-all duration-300">
|
<Reveal delay={80}><div className="group p-8 rounded-[2.5rem] bg-white border border-slate-100 shadow-sm hover:shadow-xl transition-all duration-300">
|
||||||
<div className="w-14 h-14 rounded-2xl bg-accent-violet/10 text-accent-violet flex items-center justify-center mb-6 group-hover:bg-accent-violet group-hover:text-white transition-all">
|
<div className="w-14 h-14 rounded-2xl bg-accent-violet/10 text-accent-violet flex items-center justify-center mb-6 group-hover:bg-accent-violet group-hover:text-white transition-all">
|
||||||
<span className="material-symbols-outlined text-3xl">tablet_android</span>
|
<span className="material-symbols-outlined text-3xl">tablet_android</span>
|
||||||
</div>
|
</div>
|
||||||
<h4 className="text-xl font-extrabold text-slate-900 mb-4">{t.deployment.mode2Title}</h4>
|
<h3 className="text-xl font-extrabold text-slate-900 mb-4">{t.deployment.mode2Title}</h3>
|
||||||
<p className="text-slate-600 text-sm leading-relaxed">{t.deployment.mode2Desc}</p>
|
<p className="text-slate-600 text-sm leading-relaxed">{t.deployment.mode2Desc}</p>
|
||||||
|
<Link href={`/${lang}/borne-kiosk`} className="inline-flex items-center gap-1 mt-4 text-accent-violet font-bold text-sm hover:gap-2 transition-all">
|
||||||
|
{t.footer.pageKiosk}
|
||||||
|
<span className="material-symbols-outlined text-base">arrow_forward</span>
|
||||||
|
</Link>
|
||||||
</div></Reveal>
|
</div></Reveal>
|
||||||
<Reveal delay={160}><div className="group p-8 rounded-[2.5rem] bg-white border border-slate-100 shadow-sm hover:shadow-xl transition-all duration-300">
|
<Reveal delay={160}><div className="group p-8 rounded-[2.5rem] bg-white border border-slate-100 shadow-sm hover:shadow-xl transition-all duration-300">
|
||||||
<div className="w-14 h-14 rounded-2xl bg-accent-orange/10 text-accent-orange flex items-center justify-center mb-6 group-hover:bg-accent-orange group-hover:text-white transition-all">
|
<div className="w-14 h-14 rounded-2xl bg-accent-orange/10 text-accent-orange flex items-center justify-center mb-6 group-hover:bg-accent-orange group-hover:text-white transition-all">
|
||||||
<span className="material-symbols-outlined text-3xl">language</span>
|
<span className="material-symbols-outlined text-3xl">language</span>
|
||||||
</div>
|
</div>
|
||||||
<h4 className="text-xl font-extrabold text-slate-900 mb-4">{t.deployment.mode3Title}</h4>
|
<h3 className="text-xl font-extrabold text-slate-900 mb-4">{t.deployment.mode3Title}</h3>
|
||||||
<p className="text-slate-600 text-sm leading-relaxed">{t.deployment.mode3Desc}</p>
|
<p className="text-slate-600 text-sm leading-relaxed">{t.deployment.mode3Desc}</p>
|
||||||
</div></Reveal>
|
</div></Reveal>
|
||||||
<Reveal delay={240}><div className="group p-8 rounded-[2.5rem] bg-slate-900 text-white shadow-xl relative overflow-hidden">
|
<Reveal delay={240}><div className="group p-8 rounded-[2.5rem] bg-slate-900 text-white shadow-xl relative overflow-hidden">
|
||||||
@ -156,7 +166,7 @@ export default function Home({ lang }: { lang: Language }) {
|
|||||||
<div className="w-14 h-14 rounded-2xl bg-white/10 text-primary flex items-center justify-center mb-6">
|
<div className="w-14 h-14 rounded-2xl bg-white/10 text-primary flex items-center justify-center mb-6">
|
||||||
<span className="material-symbols-outlined text-3xl">view_in_ar</span>
|
<span className="material-symbols-outlined text-3xl">view_in_ar</span>
|
||||||
</div>
|
</div>
|
||||||
<h4 className="text-xl font-extrabold mb-4">{t.deployment.mode4Title}</h4>
|
<h3 className="text-xl font-extrabold mb-4">{t.deployment.mode4Title}</h3>
|
||||||
<p className="text-slate-400 text-sm leading-relaxed">{t.deployment.mode4Desc}</p>
|
<p className="text-slate-400 text-sm leading-relaxed">{t.deployment.mode4Desc}</p>
|
||||||
</div></Reveal>
|
</div></Reveal>
|
||||||
</div>
|
</div>
|
||||||
@ -178,11 +188,15 @@ export default function Home({ lang }: { lang: Language }) {
|
|||||||
<span className="material-symbols-outlined text-sm">auto_awesome</span>
|
<span className="material-symbols-outlined text-sm">auto_awesome</span>
|
||||||
{t.ai.badge}
|
{t.ai.badge}
|
||||||
</div>
|
</div>
|
||||||
<h2 className="text-primary font-extrabold uppercase tracking-widest text-sm mb-4">{t.ai.sectionLabel}</h2>
|
<p className="text-primary font-extrabold uppercase tracking-widest text-sm mb-4">{t.ai.sectionLabel}</p>
|
||||||
<h3 className="text-3xl lg:text-5xl font-extrabold text-white leading-tight mb-6">
|
<h2 className="text-3xl lg:text-5xl font-extrabold text-white leading-tight mb-6">
|
||||||
{t.ai.titleBefore}<span className="gradient-text">{t.ai.titleHighlight}</span>{t.ai.titleAfter}
|
{t.ai.titleBefore}<span className="gradient-text">{t.ai.titleHighlight}</span>{t.ai.titleAfter}
|
||||||
</h3>
|
</h2>
|
||||||
<p className="text-slate-400 text-lg max-w-2xl mx-auto">{t.ai.desc}</p>
|
<p className="text-slate-400 text-lg max-w-2xl mx-auto">{t.ai.desc}</p>
|
||||||
|
<Link href={`/${lang}/assistant-ia`} className="inline-flex items-center gap-1 mt-6 text-primary font-bold text-sm hover:gap-2 transition-all">
|
||||||
|
{t.ai.learnMore}
|
||||||
|
<span className="material-symbols-outlined text-base">arrow_forward</span>
|
||||||
|
</Link>
|
||||||
</Reveal>
|
</Reveal>
|
||||||
<div className="flex flex-col lg:flex-row items-center gap-12 lg:gap-20">
|
<div className="flex flex-col lg:flex-row items-center gap-12 lg:gap-20">
|
||||||
<Reveal delay={80} className="w-full lg:w-auto flex justify-center">
|
<Reveal delay={80} className="w-full lg:w-auto flex justify-center">
|
||||||
@ -229,28 +243,28 @@ export default function Home({ lang }: { lang: Language }) {
|
|||||||
<div className="w-11 h-11 bg-primary/10 rounded-xl flex items-center justify-center mb-4 group-hover:bg-primary/20 transition-colors">
|
<div className="w-11 h-11 bg-primary/10 rounded-xl flex items-center justify-center mb-4 group-hover:bg-primary/20 transition-colors">
|
||||||
<span className="material-symbols-outlined text-primary">translate</span>
|
<span className="material-symbols-outlined text-primary">translate</span>
|
||||||
</div>
|
</div>
|
||||||
<h4 className="text-white font-bold mb-2">{t.ai.feature1Title}</h4>
|
<h3 className="text-white font-bold mb-2">{t.ai.feature1Title}</h3>
|
||||||
<p className="text-slate-400 text-sm leading-relaxed">{t.ai.feature1Desc}</p>
|
<p className="text-slate-400 text-sm leading-relaxed">{t.ai.feature1Desc}</p>
|
||||||
</div></Reveal>
|
</div></Reveal>
|
||||||
<Reveal delay={80}><div className="bg-slate-800/60 border border-slate-700 rounded-2xl p-6 hover:border-accent-violet/40 transition-colors group">
|
<Reveal delay={80}><div className="bg-slate-800/60 border border-slate-700 rounded-2xl p-6 hover:border-accent-violet/40 transition-colors group">
|
||||||
<div className="w-11 h-11 bg-accent-violet/10 rounded-xl flex items-center justify-center mb-4 group-hover:bg-accent-violet/20 transition-colors">
|
<div className="w-11 h-11 bg-accent-violet/10 rounded-xl flex items-center justify-center mb-4 group-hover:bg-accent-violet/20 transition-colors">
|
||||||
<span className="material-symbols-outlined text-accent-violet">manage_search</span>
|
<span className="material-symbols-outlined text-accent-violet">manage_search</span>
|
||||||
</div>
|
</div>
|
||||||
<h4 className="text-white font-bold mb-2">{t.ai.feature2Title}</h4>
|
<h3 className="text-white font-bold mb-2">{t.ai.feature2Title}</h3>
|
||||||
<p className="text-slate-400 text-sm leading-relaxed">{t.ai.feature2Desc}</p>
|
<p className="text-slate-400 text-sm leading-relaxed">{t.ai.feature2Desc}</p>
|
||||||
</div></Reveal>
|
</div></Reveal>
|
||||||
<Reveal delay={160}><div className="bg-slate-800/60 border border-slate-700 rounded-2xl p-6 hover:border-accent-orange/40 transition-colors group">
|
<Reveal delay={160}><div className="bg-slate-800/60 border border-slate-700 rounded-2xl p-6 hover:border-accent-orange/40 transition-colors group">
|
||||||
<div className="w-11 h-11 bg-accent-orange/10 rounded-xl flex items-center justify-center mb-4 group-hover:bg-accent-orange/20 transition-colors">
|
<div className="w-11 h-11 bg-accent-orange/10 rounded-xl flex items-center justify-center mb-4 group-hover:bg-accent-orange/20 transition-colors">
|
||||||
<span className="material-symbols-outlined text-accent-orange">forum</span>
|
<span className="material-symbols-outlined text-accent-orange">forum</span>
|
||||||
</div>
|
</div>
|
||||||
<h4 className="text-white font-bold mb-2">{t.ai.feature3Title}</h4>
|
<h3 className="text-white font-bold mb-2">{t.ai.feature3Title}</h3>
|
||||||
<p className="text-slate-400 text-sm leading-relaxed">{t.ai.feature3Desc}</p>
|
<p className="text-slate-400 text-sm leading-relaxed">{t.ai.feature3Desc}</p>
|
||||||
</div></Reveal>
|
</div></Reveal>
|
||||||
<Reveal delay={240}><div className="bg-slate-800/60 border border-slate-700 rounded-2xl p-6 hover:border-primary/40 transition-colors group">
|
<Reveal delay={240}><div className="bg-slate-800/60 border border-slate-700 rounded-2xl p-6 hover:border-primary/40 transition-colors group">
|
||||||
<div className="w-11 h-11 bg-primary/10 rounded-xl flex items-center justify-center mb-4 group-hover:bg-primary/20 transition-colors">
|
<div className="w-11 h-11 bg-primary/10 rounded-xl flex items-center justify-center mb-4 group-hover:bg-primary/20 transition-colors">
|
||||||
<span className="material-symbols-outlined text-primary">tune</span>
|
<span className="material-symbols-outlined text-primary">tune</span>
|
||||||
</div>
|
</div>
|
||||||
<h4 className="text-white font-bold mb-2">{t.ai.feature4Title}</h4>
|
<h3 className="text-white font-bold mb-2">{t.ai.feature4Title}</h3>
|
||||||
<p className="text-slate-400 text-sm leading-relaxed">{t.ai.feature4Desc}</p>
|
<p className="text-slate-400 text-sm leading-relaxed">{t.ai.feature4Desc}</p>
|
||||||
</div></Reveal>
|
</div></Reveal>
|
||||||
</div>
|
</div>
|
||||||
@ -270,8 +284,14 @@ export default function Home({ lang }: { lang: Language }) {
|
|||||||
<div className="h-4 w-32 bg-slate-100 rounded-full"></div>
|
<div className="h-4 w-32 bg-slate-100 rounded-full"></div>
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<div className="h-40 bg-slate-50 rounded-2xl flex items-center justify-center overflow-hidden border border-dashed border-slate-200">
|
<div className="relative h-40 bg-slate-50 rounded-2xl overflow-hidden border border-slate-200">
|
||||||
<span className="material-symbols-outlined text-slate-300 text-5xl">palette</span>
|
<Image
|
||||||
|
src={resolveImage("{{DATA:IMAGE:IMAGE_6}}")}
|
||||||
|
alt={t.imgAlt.appWhitelabel}
|
||||||
|
fill
|
||||||
|
className="object-cover object-top"
|
||||||
|
sizes="(max-width: 1024px) 90vw, 30vw"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="h-4 w-full bg-slate-100 rounded-full"></div>
|
<div className="h-4 w-full bg-slate-100 rounded-full"></div>
|
||||||
<div className="h-4 w-2/3 bg-slate-100 rounded-full"></div>
|
<div className="h-4 w-2/3 bg-slate-100 rounded-full"></div>
|
||||||
@ -298,8 +318,8 @@ export default function Home({ lang }: { lang: Language }) {
|
|||||||
</div>
|
</div>
|
||||||
</Reveal>
|
</Reveal>
|
||||||
<Reveal delay={120} className="flex-1 order-1 lg:order-2">
|
<Reveal delay={120} className="flex-1 order-1 lg:order-2">
|
||||||
<h2 className="text-accent-orange font-extrabold uppercase tracking-widest text-sm mb-4">{t.whitelabel.sectionLabel}</h2>
|
<p className="text-accent-orange font-extrabold uppercase tracking-widest text-sm mb-4">{t.whitelabel.sectionLabel}</p>
|
||||||
<h3 className="text-3xl lg:text-5xl font-extrabold text-slate-900 leading-tight mb-8">{t.whitelabel.title}</h3>
|
<h2 className="text-3xl lg:text-5xl font-extrabold text-slate-900 leading-tight mb-8">{t.whitelabel.title}</h2>
|
||||||
<p className="text-lg text-slate-600 leading-relaxed mb-8" dangerouslySetInnerHTML={{ __html: t.whitelabel.desc }} />
|
<p className="text-lg text-slate-600 leading-relaxed mb-8" dangerouslySetInnerHTML={{ __html: t.whitelabel.desc }} />
|
||||||
<ul className="space-y-4 mb-10 text-slate-700 font-semibold">
|
<ul className="space-y-4 mb-10 text-slate-700 font-semibold">
|
||||||
<li className="flex items-center gap-3">
|
<li className="flex items-center gap-3">
|
||||||
@ -324,7 +344,7 @@ export default function Home({ lang }: { lang: Language }) {
|
|||||||
<section className="py-24 bg-white" id="audience">
|
<section className="py-24 bg-white" id="audience">
|
||||||
<div className="max-w-7xl mx-auto px-6">
|
<div className="max-w-7xl mx-auto px-6">
|
||||||
<Reveal className="text-center mb-16">
|
<Reveal className="text-center mb-16">
|
||||||
<h3 className="text-3xl lg:text-4xl font-extrabold text-slate-900 mb-4">{t.audience.title}</h3>
|
<h2 className="text-3xl lg:text-4xl font-extrabold text-slate-900 mb-4">{t.audience.title}</h2>
|
||||||
<p className="text-slate-600 max-w-2xl mx-auto">{t.audience.subtitle}</p>
|
<p className="text-slate-600 max-w-2xl mx-auto">{t.audience.subtitle}</p>
|
||||||
</Reveal>
|
</Reveal>
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
|
||||||
@ -333,7 +353,7 @@ export default function Home({ lang }: { lang: Language }) {
|
|||||||
<div className="w-20 h-20 icon-circle mb-5 text-accent-violet group-hover:scale-110 transition-transform">
|
<div className="w-20 h-20 icon-circle mb-5 text-accent-violet group-hover:scale-110 transition-transform">
|
||||||
<span className="material-symbols-outlined text-4xl">museum</span>
|
<span className="material-symbols-outlined text-4xl">museum</span>
|
||||||
</div>
|
</div>
|
||||||
<h4 className="text-xl font-extrabold mb-2 text-slate-900">{t.audience.item1Title}</h4>
|
<h3 className="text-xl font-extrabold mb-2 text-slate-900">{t.audience.item1Title}</h3>
|
||||||
<p className="text-slate-500 text-sm leading-relaxed mb-4">{t.audience.item1Desc}</p>
|
<p className="text-slate-500 text-sm leading-relaxed mb-4">{t.audience.item1Desc}</p>
|
||||||
<span className="text-xs font-extrabold text-primary uppercase tracking-widest flex items-center gap-1 group-hover:gap-2 transition-all">
|
<span className="text-xs font-extrabold text-primary uppercase tracking-widest flex items-center gap-1 group-hover:gap-2 transition-all">
|
||||||
{t.audience.item1Cta}
|
{t.audience.item1Cta}
|
||||||
@ -346,7 +366,7 @@ export default function Home({ lang }: { lang: Language }) {
|
|||||||
<div className="w-20 h-20 icon-circle mb-5 text-primary group-hover:scale-110 transition-transform">
|
<div className="w-20 h-20 icon-circle mb-5 text-primary group-hover:scale-110 transition-transform">
|
||||||
<span className="material-symbols-outlined text-4xl">travel_explore</span>
|
<span className="material-symbols-outlined text-4xl">travel_explore</span>
|
||||||
</div>
|
</div>
|
||||||
<h4 className="text-xl font-extrabold mb-2 text-slate-900">{t.audience.item2Title}</h4>
|
<h3 className="text-xl font-extrabold mb-2 text-slate-900">{t.audience.item2Title}</h3>
|
||||||
<p className="text-slate-500 text-sm leading-relaxed mb-4">{t.audience.item2Desc}</p>
|
<p className="text-slate-500 text-sm leading-relaxed mb-4">{t.audience.item2Desc}</p>
|
||||||
<span className="text-xs font-extrabold text-primary uppercase tracking-widest flex items-center gap-1 group-hover:gap-2 transition-all">
|
<span className="text-xs font-extrabold text-primary uppercase tracking-widest flex items-center gap-1 group-hover:gap-2 transition-all">
|
||||||
{t.audience.item2Cta}
|
{t.audience.item2Cta}
|
||||||
@ -359,7 +379,7 @@ export default function Home({ lang }: { lang: Language }) {
|
|||||||
<div className="w-20 h-20 icon-circle mb-5 text-emerald-500 group-hover:scale-110 transition-transform">
|
<div className="w-20 h-20 icon-circle mb-5 text-emerald-500 group-hover:scale-110 transition-transform">
|
||||||
<span className="material-symbols-outlined text-4xl">park</span>
|
<span className="material-symbols-outlined text-4xl">park</span>
|
||||||
</div>
|
</div>
|
||||||
<h4 className="text-xl font-extrabold mb-2 text-slate-900">{t.audience.item3Title}</h4>
|
<h3 className="text-xl font-extrabold mb-2 text-slate-900">{t.audience.item3Title}</h3>
|
||||||
<p className="text-slate-500 text-sm leading-relaxed mb-4">{t.audience.item3Desc}</p>
|
<p className="text-slate-500 text-sm leading-relaxed mb-4">{t.audience.item3Desc}</p>
|
||||||
<span className="text-xs font-extrabold text-primary uppercase tracking-widest flex items-center gap-1 group-hover:gap-2 transition-all">
|
<span className="text-xs font-extrabold text-primary uppercase tracking-widest flex items-center gap-1 group-hover:gap-2 transition-all">
|
||||||
{t.audience.item3Cta}
|
{t.audience.item3Cta}
|
||||||
@ -372,7 +392,7 @@ export default function Home({ lang }: { lang: Language }) {
|
|||||||
<div className="w-20 h-20 icon-circle mb-5 text-accent-orange group-hover:scale-110 transition-transform">
|
<div className="w-20 h-20 icon-circle mb-5 text-accent-orange group-hover:scale-110 transition-transform">
|
||||||
<span className="material-symbols-outlined text-4xl">hotel</span>
|
<span className="material-symbols-outlined text-4xl">hotel</span>
|
||||||
</div>
|
</div>
|
||||||
<h4 className="text-xl font-extrabold mb-2 text-slate-900">{t.audience.item4Title}</h4>
|
<h3 className="text-xl font-extrabold mb-2 text-slate-900">{t.audience.item4Title}</h3>
|
||||||
<p className="text-slate-500 text-sm leading-relaxed mb-4">{t.audience.item4Desc}</p>
|
<p className="text-slate-500 text-sm leading-relaxed mb-4">{t.audience.item4Desc}</p>
|
||||||
<span className="text-xs font-extrabold text-primary uppercase tracking-widest flex items-center gap-1 group-hover:gap-2 transition-all">
|
<span className="text-xs font-extrabold text-primary uppercase tracking-widest flex items-center gap-1 group-hover:gap-2 transition-all">
|
||||||
{t.audience.item4Cta}
|
{t.audience.item4Cta}
|
||||||
@ -385,7 +405,7 @@ export default function Home({ lang }: { lang: Language }) {
|
|||||||
<div className="w-20 h-20 icon-circle mb-5 text-rose-500 group-hover:scale-110 transition-transform">
|
<div className="w-20 h-20 icon-circle mb-5 text-rose-500 group-hover:scale-110 transition-transform">
|
||||||
<span className="material-symbols-outlined text-4xl">festival</span>
|
<span className="material-symbols-outlined text-4xl">festival</span>
|
||||||
</div>
|
</div>
|
||||||
<h4 className="text-xl font-extrabold mb-2 text-slate-900">{t.audience.item5Title}</h4>
|
<h3 className="text-xl font-extrabold mb-2 text-slate-900">{t.audience.item5Title}</h3>
|
||||||
<p className="text-slate-500 text-sm leading-relaxed mb-4">{t.audience.item5Desc}</p>
|
<p className="text-slate-500 text-sm leading-relaxed mb-4">{t.audience.item5Desc}</p>
|
||||||
<span className="text-xs font-extrabold text-primary uppercase tracking-widest flex items-center gap-1 group-hover:gap-2 transition-all">
|
<span className="text-xs font-extrabold text-primary uppercase tracking-widest flex items-center gap-1 group-hover:gap-2 transition-all">
|
||||||
{t.audience.item5Cta}
|
{t.audience.item5Cta}
|
||||||
@ -398,7 +418,7 @@ export default function Home({ lang }: { lang: Language }) {
|
|||||||
<div className="w-20 h-20 icon-circle mb-5 text-indigo-500 group-hover:scale-110 transition-transform">
|
<div className="w-20 h-20 icon-circle mb-5 text-indigo-500 group-hover:scale-110 transition-transform">
|
||||||
<span className="material-symbols-outlined text-4xl">school</span>
|
<span className="material-symbols-outlined text-4xl">school</span>
|
||||||
</div>
|
</div>
|
||||||
<h4 className="text-xl font-extrabold mb-2 text-slate-900">{t.audience.item6Title}</h4>
|
<h3 className="text-xl font-extrabold mb-2 text-slate-900">{t.audience.item6Title}</h3>
|
||||||
<p className="text-slate-500 text-sm leading-relaxed mb-4">{t.audience.item6Desc}</p>
|
<p className="text-slate-500 text-sm leading-relaxed mb-4">{t.audience.item6Desc}</p>
|
||||||
<span className="text-xs font-extrabold text-primary uppercase tracking-widest flex items-center gap-1 group-hover:gap-2 transition-all">
|
<span className="text-xs font-extrabold text-primary uppercase tracking-widest flex items-center gap-1 group-hover:gap-2 transition-all">
|
||||||
{t.audience.item6Cta}
|
{t.audience.item6Cta}
|
||||||
@ -418,8 +438,8 @@ export default function Home({ lang }: { lang: Language }) {
|
|||||||
</div>
|
</div>
|
||||||
<div className="max-w-7xl mx-auto px-6 relative z-10">
|
<div className="max-w-7xl mx-auto px-6 relative z-10">
|
||||||
<Reveal className="text-center mb-16">
|
<Reveal className="text-center mb-16">
|
||||||
<h2 className="text-primary font-extrabold uppercase tracking-widest text-sm mb-4">{t.casClients.sectionLabel}</h2>
|
<p className="text-primary font-extrabold uppercase tracking-widest text-sm mb-4">{t.casClients.sectionLabel}</p>
|
||||||
<h3 className="text-3xl lg:text-5xl font-extrabold text-white leading-tight mb-6">{t.casClients.title}</h3>
|
<h2 className="text-3xl lg:text-5xl font-extrabold text-white leading-tight mb-6">{t.casClients.title}</h2>
|
||||||
<p className="text-slate-400 text-lg max-w-2xl mx-auto">{t.casClients.subtitle}</p>
|
<p className="text-slate-400 text-lg max-w-2xl mx-auto">{t.casClients.subtitle}</p>
|
||||||
</Reveal>
|
</Reveal>
|
||||||
|
|
||||||
@ -438,9 +458,9 @@ export default function Home({ lang }: { lang: Language }) {
|
|||||||
</span>
|
</span>
|
||||||
<span className="text-xs text-slate-500 font-semibold">{client.year}</span>
|
<span className="text-xs text-slate-500 font-semibold">{client.year}</span>
|
||||||
</div>
|
</div>
|
||||||
<h4 className="text-2xl font-extrabold text-white mb-3 group-hover:text-primary transition-colors leading-tight">
|
<h3 className="text-2xl font-extrabold text-white mb-3 group-hover:text-primary transition-colors leading-tight">
|
||||||
{client.client}
|
{client.client}
|
||||||
</h4>
|
</h3>
|
||||||
<p className="text-slate-400 text-sm leading-relaxed mb-6 flex-1">
|
<p className="text-slate-400 text-sm leading-relaxed mb-6 flex-1">
|
||||||
{ct.description}
|
{ct.description}
|
||||||
</p>
|
</p>
|
||||||
@ -471,232 +491,34 @@ export default function Home({ lang }: { lang: Language }) {
|
|||||||
<div className="max-w-7xl mx-auto px-6">
|
<div className="max-w-7xl mx-auto px-6">
|
||||||
<Reveal>
|
<Reveal>
|
||||||
<div className="text-center mb-16">
|
<div className="text-center mb-16">
|
||||||
<h2 className="text-accent-orange font-extrabold uppercase tracking-widest text-sm mb-4">{t.pricing.sectionLabel}</h2>
|
<p className="text-accent-orange font-extrabold uppercase tracking-widest text-sm mb-4">{t.pricing.sectionLabel}</p>
|
||||||
<h3 className="text-4xl lg:text-5xl font-extrabold text-slate-900 mb-4">{t.pricing.sectionTitle}</h3>
|
<h2 className="text-4xl lg:text-5xl font-extrabold text-slate-900 mb-4">{t.pricing.sectionTitle}</h2>
|
||||||
<p className="text-slate-500 max-w-xl mx-auto">{t.pricing.sectionDesc}</p>
|
<p className="text-slate-500 max-w-xl mx-auto">{t.pricing.sectionDesc}</p>
|
||||||
</div>
|
</div>
|
||||||
</Reveal>
|
</Reveal>
|
||||||
<div className="grid grid-cols-1 sm:grid-cols-2 xl:grid-cols-4 gap-6 items-stretch pt-6">
|
<PricingPlans lang={lang} contactHref="#contact" />
|
||||||
<Reveal delay={0}>
|
|
||||||
<div className="flex flex-col h-full bg-white rounded-3xl border border-slate-200 p-8 shadow-sm hover:shadow-md transition-shadow relative">
|
|
||||||
<div className="mb-6">
|
|
||||||
<p className="text-sm font-bold text-slate-400 uppercase tracking-widest mb-2">Essentiel</p>
|
|
||||||
<span className="inline-flex items-center gap-1 text-xs font-semibold px-2.5 py-1 rounded-full bg-slate-100 text-slate-500 mb-3">
|
|
||||||
<span className="material-symbols-outlined" style={{fontSize: '14px'}}>language</span>
|
|
||||||
{t.pricing.channelWeb}
|
|
||||||
</span>
|
|
||||||
<div className="flex items-end gap-1">
|
|
||||||
<span className="text-4xl font-extrabold text-slate-900">€39</span>
|
|
||||||
<span className="text-slate-400 mb-1">{t.pricing.perMonth}</span>
|
|
||||||
</div>
|
|
||||||
<p className="text-xs text-slate-400 mt-1">{t.pricing.htva} · {t.pricing.noCommitment}</p>
|
|
||||||
</div>
|
|
||||||
<ul className="space-y-3 flex-1 mb-8">
|
|
||||||
{[t.pricing.features.webAndKiosk, t.pricing.features.backoffice, t.pricing.features.sections].map((f) => (
|
|
||||||
<li key={f} className="flex items-center gap-3 text-sm text-slate-700">
|
|
||||||
<span className="material-symbols-outlined text-primary text-base shrink-0">check_circle</span>
|
|
||||||
{f}
|
|
||||||
</li>
|
|
||||||
))}
|
|
||||||
<li className="flex items-center gap-3 text-sm text-slate-700">
|
|
||||||
<span className="material-symbols-outlined text-primary text-base shrink-0">check_circle</span>
|
|
||||||
1 GB {t.pricing.features.storage}
|
|
||||||
</li>
|
|
||||||
<li className="flex items-center gap-3 text-sm text-slate-700">
|
|
||||||
<span className="material-symbols-outlined text-primary text-base shrink-0">check_circle</span>
|
|
||||||
{t.pricing.features.stats} — {t.pricing.features.statsBasicLabel}
|
|
||||||
</li>
|
|
||||||
{[t.pricing.features.nativeApp, t.pricing.features.offlineBeacons, t.pricing.features.pushNotif, t.pricing.features.ai, t.pricing.features.autoTranslation].map((f) => (
|
|
||||||
<li key={f} className="flex items-center gap-3 text-sm text-slate-400">
|
|
||||||
<span className="material-symbols-outlined text-slate-300 text-base shrink-0">cancel</span>
|
|
||||||
{f}
|
|
||||||
</li>
|
|
||||||
))}
|
|
||||||
</ul>
|
|
||||||
<a href={`/${lang}/signup`} className="block w-full py-3 rounded-2xl border-2 border-slate-200 text-slate-700 font-bold text-sm hover:border-primary hover:text-primary transition-all text-center">
|
|
||||||
{t.pricing.ctaStartTrial}
|
|
||||||
</a>
|
|
||||||
</div>
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* FAQ */}
|
||||||
|
<section className="py-24 bg-white" id="faq">
|
||||||
|
<div className="max-w-3xl mx-auto px-6">
|
||||||
|
<Reveal className="text-center mb-12">
|
||||||
|
<p className="text-primary font-extrabold uppercase tracking-widest text-sm mb-4">{t.homeFaq.sectionLabel}</p>
|
||||||
|
<h2 className="text-3xl lg:text-4xl font-extrabold text-slate-900">{t.homeFaq.title}</h2>
|
||||||
</Reveal>
|
</Reveal>
|
||||||
<Reveal delay={60}>
|
<div className="space-y-4">
|
||||||
<div className="animated-card-border relative p-[2px] rounded-3xl shadow-xl shadow-primary/10 h-full">
|
{t.homeFaq.items.map((item) => (
|
||||||
<div className="flex flex-col h-full bg-white rounded-[22px] p-8 relative">
|
<details key={item.question} className="group bg-slate-50 rounded-2xl border border-slate-100 p-6">
|
||||||
<div className="absolute -top-4 left-1/2 -translate-x-1/2">
|
<summary className="flex items-center justify-between gap-4 cursor-pointer list-none">
|
||||||
<span className="bg-primary text-slate-900 text-xs font-extrabold px-4 py-1.5 rounded-full uppercase tracking-wider">{t.pricing.recommended}</span>
|
<h3 className="font-extrabold text-slate-900">{item.question}</h3>
|
||||||
</div>
|
<span className="material-symbols-outlined text-slate-400 transition-transform group-open:rotate-180">expand_more</span>
|
||||||
<div className="mb-6">
|
</summary>
|
||||||
<p className="text-sm font-bold text-slate-400 uppercase tracking-widest mb-2">Pro</p>
|
<p className="text-slate-600 leading-relaxed mt-4">{item.answer}</p>
|
||||||
<span className="inline-flex items-center gap-1 text-xs font-semibold px-2.5 py-1 rounded-full bg-primary/10 text-primary mb-3">
|
</details>
|
||||||
<span className="material-symbols-outlined" style={{fontSize: '14px'}}>smartphone</span>
|
|
||||||
{t.pricing.channelNative}
|
|
||||||
</span>
|
|
||||||
<div className="flex items-end gap-1">
|
|
||||||
<span className="text-4xl font-extrabold text-slate-900">€99</span>
|
|
||||||
<span className="text-slate-400 mb-1">{t.pricing.perMonth}</span>
|
|
||||||
</div>
|
|
||||||
<p className="text-xs text-slate-400 mt-1">{t.pricing.htva}</p>
|
|
||||||
<p className="text-xs text-slate-400 mt-1">{t.pricing.setupFeeNote}</p>
|
|
||||||
</div>
|
|
||||||
<ul className="space-y-3 flex-1 mb-8">
|
|
||||||
{[t.pricing.features.webAndKiosk, t.pricing.features.nativeApp, t.pricing.features.backoffice, t.pricing.features.sections].map((f) => (
|
|
||||||
<li key={f} className="flex items-center gap-3 text-sm text-slate-700">
|
|
||||||
<span className="material-symbols-outlined text-primary text-base shrink-0">check_circle</span>
|
|
||||||
{f}
|
|
||||||
</li>
|
|
||||||
))}
|
))}
|
||||||
<li className="flex items-center gap-3 text-sm text-slate-700">
|
|
||||||
<span className="material-symbols-outlined text-primary text-base shrink-0">check_circle</span>
|
|
||||||
15 GB {t.pricing.features.storage}
|
|
||||||
</li>
|
|
||||||
{[t.pricing.features.offlineBeacons, t.pricing.features.pushNotif].map((f) => (
|
|
||||||
<li key={f} className="flex items-center gap-3 text-sm text-slate-700">
|
|
||||||
<span className="material-symbols-outlined text-primary text-base shrink-0">check_circle</span>
|
|
||||||
{f}
|
|
||||||
</li>
|
|
||||||
))}
|
|
||||||
<li className="flex items-center gap-3 text-sm text-slate-700">
|
|
||||||
<span className="material-symbols-outlined text-primary text-base shrink-0">check_circle</span>
|
|
||||||
{t.pricing.features.stats} — {t.pricing.features.statsBasicLabel}
|
|
||||||
</li>
|
|
||||||
{[t.pricing.features.statsAdvancedFeature, t.pricing.features.ai, t.pricing.features.autoTranslation].map((f) => (
|
|
||||||
<li key={f} className="flex items-center gap-3 text-sm text-slate-400">
|
|
||||||
<span className="material-symbols-outlined text-slate-300 text-base shrink-0">cancel</span>
|
|
||||||
{f}
|
|
||||||
</li>
|
|
||||||
))}
|
|
||||||
</ul>
|
|
||||||
<a href="#contact" className="block w-full py-3 rounded-2xl bg-primary text-slate-900 font-extrabold text-sm hover:brightness-110 transition-all shadow-lg shadow-primary/20 text-center">
|
|
||||||
{t.pricing.ctaStart}
|
|
||||||
</a>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Reveal>
|
|
||||||
<Reveal delay={120}>
|
|
||||||
<div className="flex flex-col h-full bg-gradient-to-br from-slate-900 to-slate-800 rounded-3xl p-8 shadow-xl">
|
|
||||||
<div className="mb-6">
|
|
||||||
<p className="text-sm font-bold text-slate-400 uppercase tracking-widest mb-2">Premium</p>
|
|
||||||
<span className="inline-flex items-center gap-1 text-xs font-semibold px-2.5 py-1 rounded-full bg-primary/10 text-primary mb-3">
|
|
||||||
<span className="material-symbols-outlined" style={{fontSize: '14px'}}>smartphone</span>
|
|
||||||
{t.pricing.channelNative}
|
|
||||||
</span>
|
|
||||||
<div className="flex items-end gap-1">
|
|
||||||
<span className="text-4xl font-extrabold text-white">€179</span>
|
|
||||||
<span className="text-slate-400 mb-1">{t.pricing.perMonth}</span>
|
|
||||||
</div>
|
|
||||||
<p className="text-xs text-slate-400 mt-1">{t.pricing.htva}</p>
|
|
||||||
<p className="text-xs text-slate-500 mt-1">{t.pricing.setupFeeNote}</p>
|
|
||||||
</div>
|
|
||||||
<ul className="space-y-3 flex-1 mb-8">
|
|
||||||
{[t.pricing.features.webAndKiosk, t.pricing.features.nativeApp, t.pricing.features.backoffice, t.pricing.features.sections].map((f) => (
|
|
||||||
<li key={f} className="flex items-center gap-3 text-sm text-slate-300">
|
|
||||||
<span className="material-symbols-outlined text-primary text-base shrink-0">check_circle</span>
|
|
||||||
{f}
|
|
||||||
</li>
|
|
||||||
))}
|
|
||||||
<li className="flex items-center gap-3 text-sm text-slate-300">
|
|
||||||
<span className="material-symbols-outlined text-primary text-base shrink-0">check_circle</span>
|
|
||||||
50 GB {t.pricing.features.storage}
|
|
||||||
</li>
|
|
||||||
{[t.pricing.features.offlineBeacons, t.pricing.features.pushNotif].map((f) => (
|
|
||||||
<li key={f} className="flex items-center gap-3 text-sm text-slate-300">
|
|
||||||
<span className="material-symbols-outlined text-primary text-base shrink-0">check_circle</span>
|
|
||||||
{f}
|
|
||||||
</li>
|
|
||||||
))}
|
|
||||||
<li className="flex items-center gap-3 text-sm text-slate-300">
|
|
||||||
<span className="material-symbols-outlined text-primary text-base shrink-0">check_circle</span>
|
|
||||||
{t.pricing.features.statsAdvancedFeature}
|
|
||||||
</li>
|
|
||||||
<li className="flex items-start gap-3 text-sm text-slate-300">
|
|
||||||
<span className="material-symbols-outlined text-primary text-base shrink-0 mt-0.5">check_circle</span>
|
|
||||||
<span>
|
|
||||||
{t.pricing.features.ai} — ≈ 2 000 {t.pricing.features.questionsPerMonth}
|
|
||||||
<span className="block text-xs text-slate-500 mt-0.5">{t.pricing.features.aiNeedMore} → Enterprise</span>
|
|
||||||
</span>
|
|
||||||
</li>
|
|
||||||
<li className="flex items-center gap-3 text-sm text-slate-300">
|
|
||||||
<span className="material-symbols-outlined text-primary text-base shrink-0">check_circle</span>
|
|
||||||
{t.pricing.features.autoTranslation}
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<a href="#contact" className="block w-full py-3 rounded-2xl bg-white/10 text-white font-bold text-sm hover:bg-white/20 transition-all border border-white/10 text-center">
|
|
||||||
{t.pricing.ctaContact}
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</Reveal>
|
|
||||||
<Reveal delay={180}>
|
|
||||||
<div className="flex flex-col h-full bg-gradient-to-br from-violet-950 to-slate-900 rounded-3xl p-8 shadow-xl border border-violet-800/40 relative">
|
|
||||||
<div className="mb-6">
|
|
||||||
<p className="text-sm font-bold text-violet-400 uppercase tracking-widest mb-2">Enterprise</p>
|
|
||||||
<span className="inline-flex items-center gap-1 text-xs font-semibold px-2.5 py-1 rounded-full bg-violet-500/10 text-violet-400 mb-3">
|
|
||||||
<span className="material-symbols-outlined" style={{fontSize: '14px'}}>smartphone</span>
|
|
||||||
{t.pricing.channelNative}
|
|
||||||
</span>
|
|
||||||
<div className="flex items-end gap-1">
|
|
||||||
<span className="text-3xl font-extrabold text-white">{t.pricing.enterprisePrice}</span>
|
|
||||||
</div>
|
|
||||||
<p className="text-xs text-slate-400 mt-2 leading-relaxed">{t.pricing.enterpriseDesc}</p>
|
|
||||||
</div>
|
|
||||||
<ul className="space-y-3 flex-1 mb-8">
|
|
||||||
{[
|
|
||||||
t.pricing.features.webAndKiosk,
|
|
||||||
t.pricing.features.nativeApp,
|
|
||||||
t.pricing.features.backoffice,
|
|
||||||
t.pricing.features.sections,
|
|
||||||
t.pricing.features.multiSite,
|
|
||||||
].map((f) => (
|
|
||||||
<li key={f} className="flex items-center gap-3 text-sm text-slate-300">
|
|
||||||
<span className="material-symbols-outlined text-violet-400 text-base shrink-0">check_circle</span>
|
|
||||||
{f}
|
|
||||||
</li>
|
|
||||||
))}
|
|
||||||
<li className="flex items-center gap-3 text-sm text-slate-300">
|
|
||||||
<span className="material-symbols-outlined text-violet-400 text-base shrink-0">check_circle</span>
|
|
||||||
{t.pricing.features.customStorage}
|
|
||||||
</li>
|
|
||||||
<li className="flex items-center gap-3 text-sm text-slate-300">
|
|
||||||
<span className="material-symbols-outlined text-violet-400 text-base shrink-0">check_circle</span>
|
|
||||||
{t.pricing.features.customAiQuota}
|
|
||||||
</li>
|
|
||||||
{[
|
|
||||||
t.pricing.features.statsAdvancedFeature,
|
|
||||||
t.pricing.features.offlineBeacons,
|
|
||||||
t.pricing.features.pushNotif,
|
|
||||||
t.pricing.features.autoTranslation,
|
|
||||||
t.pricing.features.slaEnhanced,
|
|
||||||
t.pricing.features.dedicatedSupport,
|
|
||||||
t.pricing.features.customDev,
|
|
||||||
].map((f) => (
|
|
||||||
<li key={f} className="flex items-center gap-3 text-sm text-slate-300">
|
|
||||||
<span className="material-symbols-outlined text-violet-400 text-base shrink-0">check_circle</span>
|
|
||||||
{f}
|
|
||||||
</li>
|
|
||||||
))}
|
|
||||||
</ul>
|
|
||||||
<a href="#contact" className="block w-full py-3 rounded-2xl bg-violet-600 text-white font-bold text-sm hover:bg-violet-500 transition-all shadow-lg shadow-violet-900/40 text-center">
|
|
||||||
{t.pricing.ctaContact}
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</Reveal>
|
|
||||||
</div>
|
|
||||||
<Reveal delay={100}>
|
|
||||||
<div className="mt-12 flex flex-col sm:flex-row items-center justify-between gap-6 bg-white rounded-2xl border border-slate-200 px-8 py-6">
|
|
||||||
<div className="flex items-center gap-4">
|
|
||||||
<span className="material-symbols-outlined text-primary text-3xl shrink-0">calendar_month</span>
|
|
||||||
<div>
|
|
||||||
<p className="font-extrabold text-slate-900">{t.pricing.multiYearLabel}</p>
|
|
||||||
<p className="text-sm text-slate-500">{t.pricing.multiYearDesc}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<a
|
|
||||||
href="#contact"
|
|
||||||
className="shrink-0 px-6 py-3 rounded-full border-2 border-primary text-primary font-bold text-sm hover:bg-primary hover:text-slate-900 transition-all whitespace-nowrap"
|
|
||||||
>
|
|
||||||
{t.pricing.multiYearCta}
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</Reveal>
|
|
||||||
</div>
|
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
{/* Final CTA */}
|
{/* Final CTA */}
|
||||||
@ -736,8 +558,8 @@ export default function Home({ lang }: { lang: Language }) {
|
|||||||
<div className="max-w-4xl mx-auto px-6">
|
<div className="max-w-4xl mx-auto px-6">
|
||||||
<div className="bg-white rounded-[3rem] shadow-2xl border border-slate-100 p-10 lg:p-16 relative">
|
<div className="bg-white rounded-[3rem] shadow-2xl border border-slate-100 p-10 lg:p-16 relative">
|
||||||
<div className="text-center mb-12">
|
<div className="text-center mb-12">
|
||||||
<h2 className="text-accent-orange font-extrabold uppercase tracking-widest text-sm mb-4">{t.contact.sectionLabel}</h2>
|
<p className="text-accent-orange font-extrabold uppercase tracking-widest text-sm mb-4">{t.contact.sectionLabel}</p>
|
||||||
<h3 className="text-3xl lg:text-4xl font-extrabold text-slate-900 mb-4">{t.contact.title}</h3>
|
<h2 className="text-3xl lg:text-4xl font-extrabold text-slate-900 mb-4">{t.contact.title}</h2>
|
||||||
<p className="text-slate-600">{t.contact.subtitle}</p>
|
<p className="text-slate-600">{t.contact.subtitle}</p>
|
||||||
</div>
|
</div>
|
||||||
<ContactForm lang={lang} />
|
<ContactForm lang={lang} />
|
||||||
@ -763,7 +585,7 @@ export default function Home({ lang }: { lang: Language }) {
|
|||||||
</div>
|
</div>
|
||||||
<p className="text-slate-500 text-sm leading-relaxed mb-6">{t.footer.desc}</p>
|
<p className="text-slate-500 text-sm leading-relaxed mb-6">{t.footer.desc}</p>
|
||||||
<div className="flex gap-4">
|
<div className="flex gap-4">
|
||||||
<a className="w-10 h-10 rounded-full bg-slate-200 flex items-center justify-center text-slate-600 hover:bg-primary hover:text-slate-900 transition-all" href="#">
|
<a className="w-10 h-10 rounded-full bg-slate-200 flex items-center justify-center text-slate-600 hover:bg-primary hover:text-slate-900 transition-all" href="https://unov.be" aria-label="Unov">
|
||||||
<span className="material-symbols-outlined">public</span>
|
<span className="material-symbols-outlined">public</span>
|
||||||
</a>
|
</a>
|
||||||
<a className="w-10 h-10 rounded-full bg-slate-200 flex items-center justify-center text-slate-600 hover:bg-primary hover:text-slate-900 transition-all" href="mailto:contact@unov.be">
|
<a className="w-10 h-10 rounded-full bg-slate-200 flex items-center justify-center text-slate-600 hover:bg-primary hover:text-slate-900 transition-all" href="mailto:contact@unov.be">
|
||||||
@ -771,9 +593,33 @@ export default function Home({ lang }: { lang: Language }) {
|
|||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div></div>
|
|
||||||
<div>
|
<div>
|
||||||
<h4 className="font-bold text-slate-900 mb-6 uppercase text-xs tracking-widest">{t.footer.casClientsLink}</h4>
|
<h3 className="font-bold text-slate-900 mb-6 uppercase text-xs tracking-widest">{t.footer.pagesTitle}</h3>
|
||||||
|
<ul className="space-y-4">
|
||||||
|
{[
|
||||||
|
{ href: `/${lang}/tarifs`, label: t.footer.pageTarifs },
|
||||||
|
{ href: `/${lang}/assistant-ia`, label: t.footer.pageAssistant },
|
||||||
|
{ href: `/${lang}/borne-kiosk`, label: t.footer.pageKiosk },
|
||||||
|
{ href: `/${lang}/visite-hors-ligne`, label: t.footer.pageOffline },
|
||||||
|
{ href: `/${lang}/marches-publics`, label: t.footer.pagePublic },
|
||||||
|
// Blog en français uniquement pour l'instant.
|
||||||
|
...(lang === 'fr'
|
||||||
|
? [
|
||||||
|
{ href: '/fr/ressources', label: 'Ressources' },
|
||||||
|
{ href: '/fr/comparatif/myinfomate-vs-smartify', label: 'Comparatifs' },
|
||||||
|
]
|
||||||
|
: []),
|
||||||
|
].map((page) => (
|
||||||
|
<li key={page.href}>
|
||||||
|
<Link className="text-sm text-slate-500 hover:text-primary transition-colors" href={page.href}>
|
||||||
|
{page.label}
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 className="font-bold text-slate-900 mb-6 uppercase text-xs tracking-widest">{t.footer.casClientsLink}</h3>
|
||||||
<ul className="space-y-4">
|
<ul className="space-y-4">
|
||||||
{casClients.map((c) => (
|
{casClients.map((c) => (
|
||||||
<li key={c.slug}>
|
<li key={c.slug}>
|
||||||
@ -790,7 +636,7 @@ export default function Home({ lang }: { lang: Language }) {
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h4 className="font-bold text-slate-900 mb-6 uppercase text-xs tracking-widest">{t.footer.contactTitle}</h4>
|
<h3 className="font-bold text-slate-900 mb-6 uppercase text-xs tracking-widest">{t.footer.contactTitle}</h3>
|
||||||
<ul className="space-y-4">
|
<ul className="space-y-4">
|
||||||
<li className="flex items-start gap-3 text-sm text-slate-500">
|
<li className="flex items-start gap-3 text-sm text-slate-500">
|
||||||
<span className="material-symbols-outlined text-primary text-sm">location_on</span>
|
<span className="material-symbols-outlined text-primary text-sm">location_on</span>
|
||||||
@ -810,8 +656,9 @@ export default function Home({ lang }: { lang: Language }) {
|
|||||||
<div className="pt-8 border-t border-slate-200 flex flex-col md:flex-row justify-between items-center gap-4">
|
<div className="pt-8 border-t border-slate-200 flex flex-col md:flex-row justify-between items-center gap-4">
|
||||||
<p className="text-xs text-slate-400">{t.footer.copyright}</p>
|
<p className="text-xs text-slate-400">{t.footer.copyright}</p>
|
||||||
<div className="flex gap-8">
|
<div className="flex gap-8">
|
||||||
<a className="text-xs text-slate-400 hover:text-slate-600" href="/mentions-legales">{t.footer.legal}</a>
|
<Link className="text-xs text-slate-400 hover:text-slate-600" href={`/${lang}/mentions-legales`}>{t.footer.legal}</Link>
|
||||||
<a className="text-xs text-slate-400 hover:text-slate-600" href="/confidentialite">{t.footer.privacy}</a>
|
<Link className="text-xs text-slate-400 hover:text-slate-600" href={`/${lang}/confidentialite`}>{t.footer.privacy}</Link>
|
||||||
|
<Link className="text-xs text-slate-400 hover:text-slate-600" href={`/${lang}/conditions-generales`}>{t.footer.terms}</Link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import { useRouter } from 'next/navigation';
|
|||||||
import { resolveImage } from '@/data/stitch-images';
|
import { resolveImage } from '@/data/stitch-images';
|
||||||
import translations, { Language } from '@/data/translations';
|
import translations, { Language } from '@/data/translations';
|
||||||
import type { Segment } from '@/data/segments';
|
import type { Segment } from '@/data/segments';
|
||||||
|
import PricingPlans from '@/components/PricingPlans';
|
||||||
|
|
||||||
const LANGUAGES: { code: Language; label: string; name: string }[] = [
|
const LANGUAGES: { code: Language; label: string; name: string }[] = [
|
||||||
{ code: 'fr', label: 'FR', name: 'Français' },
|
{ code: 'fr', label: 'FR', name: 'Français' },
|
||||||
@ -156,7 +157,7 @@ export default function SegmentPageClient({ data, lang }: { data: Segment; lang:
|
|||||||
{t.nav.ai}
|
{t.nav.ai}
|
||||||
</Link>
|
</Link>
|
||||||
<Link href={`/${lang}#audience`} className="text-sm font-semibold text-slate-600 hover:text-primary transition-colors">{t.nav.audience}</Link>
|
<Link href={`/${lang}#audience`} className="text-sm font-semibold text-slate-600 hover:text-primary transition-colors">{t.nav.audience}</Link>
|
||||||
<button onClick={scrollToPricing} className="text-sm font-semibold text-slate-600 hover:text-primary transition-colors">{t.pricing.sectionLabel}</button>
|
<Link href={`/${lang}/tarifs`} className="text-sm font-semibold text-slate-600 hover:text-primary transition-colors">{t.pricing.sectionLabel}</Link>
|
||||||
</nav>
|
</nav>
|
||||||
<div className="flex items-center gap-4">
|
<div className="flex items-center gap-4">
|
||||||
<a href="https://manager.myinfomate.be" className="hidden lg:block text-sm font-bold text-slate-900 hover:text-primary px-4 py-2 transition-colors">
|
<a href="https://manager.myinfomate.be" className="hidden lg:block text-sm font-bold text-slate-900 hover:text-primary px-4 py-2 transition-colors">
|
||||||
@ -222,7 +223,7 @@ export default function SegmentPageClient({ data, lang }: { data: Segment; lang:
|
|||||||
{ label: t.mobileMenu.features, href: `/${lang}#features` },
|
{ label: t.mobileMenu.features, href: `/${lang}#features` },
|
||||||
{ label: t.mobileMenu.ai, href: `/${lang}#ai-assistant` },
|
{ label: t.mobileMenu.ai, href: `/${lang}#ai-assistant` },
|
||||||
{ label: t.mobileMenu.audience, href: `/${lang}#audience` },
|
{ label: t.mobileMenu.audience, href: `/${lang}#audience` },
|
||||||
{ label: t.pricing.sectionLabel.toUpperCase(), href: '#pricing' },
|
{ label: t.pricing.sectionLabel.toUpperCase(), href: `/${lang}/tarifs` },
|
||||||
{ label: t.mobileMenu.contact, href: '#contact' },
|
{ label: t.mobileMenu.contact, href: '#contact' },
|
||||||
].map((item) => (
|
].map((item) => (
|
||||||
<a
|
<a
|
||||||
@ -307,8 +308,8 @@ export default function SegmentPageClient({ data, lang }: { data: Segment; lang:
|
|||||||
<section className="py-20 bg-white">
|
<section className="py-20 bg-white">
|
||||||
<div className="max-w-7xl mx-auto px-6">
|
<div className="max-w-7xl mx-auto px-6">
|
||||||
<Reveal className="text-center mb-12">
|
<Reveal className="text-center mb-12">
|
||||||
<h2 className="text-accent-orange font-extrabold uppercase tracking-widest text-sm mb-4">{s.painPoints.label}</h2>
|
<p className="text-accent-orange font-extrabold uppercase tracking-widest text-sm mb-4">{s.painPoints.label}</p>
|
||||||
<h3 className="text-3xl lg:text-4xl font-extrabold text-slate-900">{s.painPoints.title}</h3>
|
<h2 className="text-3xl lg:text-4xl font-extrabold text-slate-900">{s.painPoints.title}</h2>
|
||||||
</Reveal>
|
</Reveal>
|
||||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
|
||||||
{s.painPoints.items.map((item, i) => (
|
{s.painPoints.items.map((item, i) => (
|
||||||
@ -317,7 +318,7 @@ export default function SegmentPageClient({ data, lang }: { data: Segment; lang:
|
|||||||
<div className="w-16 h-16 bg-red-50 text-red-400 rounded-2xl flex items-center justify-center mb-5">
|
<div className="w-16 h-16 bg-red-50 text-red-400 rounded-2xl flex items-center justify-center mb-5">
|
||||||
<span className="material-symbols-outlined text-3xl">{item.icon}</span>
|
<span className="material-symbols-outlined text-3xl">{item.icon}</span>
|
||||||
</div>
|
</div>
|
||||||
<h4 className="text-lg font-extrabold text-slate-900 mb-3">{item.title}</h4>
|
<h3 className="text-lg font-extrabold text-slate-900 mb-3">{item.title}</h3>
|
||||||
<p className="text-sm text-slate-500 leading-relaxed">{item.desc}</p>
|
<p className="text-sm text-slate-500 leading-relaxed">{item.desc}</p>
|
||||||
</div>
|
</div>
|
||||||
</Reveal>
|
</Reveal>
|
||||||
@ -330,8 +331,8 @@ export default function SegmentPageClient({ data, lang }: { data: Segment; lang:
|
|||||||
<section className="py-20 bg-slate-50">
|
<section className="py-20 bg-slate-50">
|
||||||
<div className="max-w-7xl mx-auto px-6">
|
<div className="max-w-7xl mx-auto px-6">
|
||||||
<Reveal className="text-center mb-12">
|
<Reveal className="text-center mb-12">
|
||||||
<h2 className="text-accent-orange font-extrabold uppercase tracking-widest text-sm mb-4">{s.features.label}</h2>
|
<p className="text-accent-orange font-extrabold uppercase tracking-widest text-sm mb-4">{s.features.label}</p>
|
||||||
<h3 className="text-3xl lg:text-4xl font-extrabold text-slate-900 mb-4">{s.features.title}</h3>
|
<h2 className="text-3xl lg:text-4xl font-extrabold text-slate-900 mb-4">{s.features.title}</h2>
|
||||||
<p className="text-slate-500 max-w-xl mx-auto">{s.features.desc}</p>
|
<p className="text-slate-500 max-w-xl mx-auto">{s.features.desc}</p>
|
||||||
</Reveal>
|
</Reveal>
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
|
||||||
@ -341,7 +342,7 @@ export default function SegmentPageClient({ data, lang }: { data: Segment; lang:
|
|||||||
<div className="w-14 h-14 bg-primary/10 text-primary rounded-2xl flex items-center justify-center mb-5 shrink-0">
|
<div className="w-14 h-14 bg-primary/10 text-primary rounded-2xl flex items-center justify-center mb-5 shrink-0">
|
||||||
<span className="material-symbols-outlined text-2xl">{item.icon}</span>
|
<span className="material-symbols-outlined text-2xl">{item.icon}</span>
|
||||||
</div>
|
</div>
|
||||||
<h4 className="text-lg font-extrabold text-slate-900 mb-3">{item.title}</h4>
|
<h3 className="text-lg font-extrabold text-slate-900 mb-3">{item.title}</h3>
|
||||||
<p className="text-sm text-slate-500 leading-relaxed flex-1 mb-4">{item.desc}</p>
|
<p className="text-sm text-slate-500 leading-relaxed flex-1 mb-4">{item.desc}</p>
|
||||||
<div className="pt-4 border-t border-slate-100">
|
<div className="pt-4 border-t border-slate-100">
|
||||||
<p className="text-xs text-primary font-bold">
|
<p className="text-xs text-primary font-bold">
|
||||||
@ -360,8 +361,20 @@ export default function SegmentPageClient({ data, lang }: { data: Segment; lang:
|
|||||||
<section className="py-20 bg-white">
|
<section className="py-20 bg-white">
|
||||||
<div className="max-w-7xl mx-auto px-6">
|
<div className="max-w-7xl mx-auto px-6">
|
||||||
<Reveal className="text-center mb-12">
|
<Reveal className="text-center mb-12">
|
||||||
<h2 className="text-accent-orange font-extrabold uppercase tracking-widest text-sm mb-4">{s.comparison.label}</h2>
|
<p className="text-accent-orange font-extrabold uppercase tracking-widest text-sm mb-4">{s.comparison.label}</p>
|
||||||
<h3 className="text-3xl lg:text-4xl font-extrabold text-slate-900">{s.comparison.title}</h3>
|
<h2 className="text-3xl lg:text-4xl font-extrabold text-slate-900">{s.comparison.title}</h2>
|
||||||
|
{lang === 'fr' && (
|
||||||
|
<div className="mt-4 flex flex-wrap justify-center gap-4">
|
||||||
|
<Link href="/fr/comparatif/myinfomate-vs-smartify" className="inline-flex items-center gap-1 text-primary font-bold text-sm hover:gap-2 transition-all">
|
||||||
|
MyInfoMate ou Smartify
|
||||||
|
<span className="material-symbols-outlined text-base">arrow_forward</span>
|
||||||
|
</Link>
|
||||||
|
<Link href="/fr/comparatif/myinfomate-vs-stqry" className="inline-flex items-center gap-1 text-primary font-bold text-sm hover:gap-2 transition-all">
|
||||||
|
MyInfoMate ou STQRY
|
||||||
|
<span className="material-symbols-outlined text-base">arrow_forward</span>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</Reveal>
|
</Reveal>
|
||||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
|
||||||
{s.comparison.items.map((item, i) => (
|
{s.comparison.items.map((item, i) => (
|
||||||
@ -395,237 +408,11 @@ export default function SegmentPageClient({ data, lang }: { data: Segment; lang:
|
|||||||
<section className="py-20 bg-slate-50" id="pricing">
|
<section className="py-20 bg-slate-50" id="pricing">
|
||||||
<div className="max-w-7xl mx-auto px-6">
|
<div className="max-w-7xl mx-auto px-6">
|
||||||
<Reveal className="text-center mb-12">
|
<Reveal className="text-center mb-12">
|
||||||
<h2 className="text-accent-orange font-extrabold uppercase tracking-widest text-sm mb-4">{t.pricing.sectionLabel}</h2>
|
<p className="text-accent-orange font-extrabold uppercase tracking-widest text-sm mb-4">{t.pricing.sectionLabel}</p>
|
||||||
<h3 className="text-3xl lg:text-4xl font-extrabold text-slate-900 mb-4">{t.pricing.sectionTitle}</h3>
|
<h2 className="text-3xl lg:text-4xl font-extrabold text-slate-900 mb-4">{t.pricing.sectionTitle}</h2>
|
||||||
<p className="text-slate-500 max-w-xl mx-auto">{t.pricing.sectionDesc}</p>
|
<p className="text-slate-500 max-w-xl mx-auto">{t.pricing.sectionDesc}</p>
|
||||||
</Reveal>
|
</Reveal>
|
||||||
<div className="grid grid-cols-1 sm:grid-cols-2 xl:grid-cols-4 gap-6 items-stretch pt-6">
|
<PricingPlans lang={lang} contactHref="#contact" />
|
||||||
|
|
||||||
{/* Essentiel */}
|
|
||||||
<Reveal delay={0}>
|
|
||||||
<div className="flex flex-col h-full bg-white rounded-3xl border border-slate-200 p-8 shadow-sm hover:shadow-md transition-shadow relative">
|
|
||||||
<div className="mb-6">
|
|
||||||
<p className="text-sm font-bold text-slate-400 uppercase tracking-widest mb-2">Essentiel</p>
|
|
||||||
<span className="inline-flex items-center gap-1 text-xs font-semibold px-2.5 py-1 rounded-full bg-slate-100 text-slate-500 mb-3">
|
|
||||||
<span className="material-symbols-outlined" style={{fontSize: '14px'}}>language</span>
|
|
||||||
{t.pricing.channelWeb}
|
|
||||||
</span>
|
|
||||||
<div className="flex items-end gap-1">
|
|
||||||
<span className="text-4xl font-extrabold text-slate-900">€39</span>
|
|
||||||
<span className="text-slate-400 mb-1">{t.pricing.perMonth}</span>
|
|
||||||
</div>
|
|
||||||
<p className="text-xs text-slate-400 mt-1">{t.pricing.htva} · {t.pricing.noCommitment}</p>
|
|
||||||
</div>
|
|
||||||
<ul className="space-y-3 flex-1 mb-8">
|
|
||||||
{[t.pricing.features.webAndKiosk, t.pricing.features.backoffice, t.pricing.features.sections].map((f) => (
|
|
||||||
<li key={f} className="flex items-center gap-3 text-sm text-slate-700">
|
|
||||||
<span className="material-symbols-outlined text-primary text-base shrink-0">check_circle</span>
|
|
||||||
{f}
|
|
||||||
</li>
|
|
||||||
))}
|
|
||||||
<li className="flex items-center gap-3 text-sm text-slate-700">
|
|
||||||
<span className="material-symbols-outlined text-primary text-base shrink-0">check_circle</span>
|
|
||||||
1 GB {t.pricing.features.storage}
|
|
||||||
</li>
|
|
||||||
<li className="flex items-center gap-3 text-sm text-slate-700">
|
|
||||||
<span className="material-symbols-outlined text-primary text-base shrink-0">check_circle</span>
|
|
||||||
{t.pricing.features.stats} — {t.pricing.features.statsBasicLabel}
|
|
||||||
</li>
|
|
||||||
{[t.pricing.features.nativeApp, t.pricing.features.offlineBeacons, t.pricing.features.pushNotif, t.pricing.features.ai, t.pricing.features.autoTranslation].map((f) => (
|
|
||||||
<li key={f} className="flex items-center gap-3 text-sm text-slate-400">
|
|
||||||
<span className="material-symbols-outlined text-slate-300 text-base shrink-0">cancel</span>
|
|
||||||
{f}
|
|
||||||
</li>
|
|
||||||
))}
|
|
||||||
</ul>
|
|
||||||
<a href={`/${lang}/signup`} className="block w-full py-3 rounded-2xl border-2 border-slate-200 text-slate-700 font-bold text-sm hover:border-primary hover:text-primary transition-all text-center">
|
|
||||||
{t.pricing.ctaStartTrial}
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</Reveal>
|
|
||||||
|
|
||||||
{/* Pro */}
|
|
||||||
<Reveal delay={60}>
|
|
||||||
<div className="flex flex-col h-full bg-white rounded-3xl border-2 border-primary p-8 shadow-xl shadow-primary/10 relative">
|
|
||||||
<div className="absolute -top-4 left-1/2 -translate-x-1/2">
|
|
||||||
<span className="bg-primary text-slate-900 text-xs font-extrabold px-4 py-1.5 rounded-full uppercase tracking-wider">{t.pricing.recommended}</span>
|
|
||||||
</div>
|
|
||||||
<div className="mb-6">
|
|
||||||
<p className="text-sm font-bold text-slate-400 uppercase tracking-widest mb-2">Pro</p>
|
|
||||||
<span className="inline-flex items-center gap-1 text-xs font-semibold px-2.5 py-1 rounded-full bg-primary/10 text-primary mb-3">
|
|
||||||
<span className="material-symbols-outlined" style={{fontSize: '14px'}}>smartphone</span>
|
|
||||||
{t.pricing.channelNative}
|
|
||||||
</span>
|
|
||||||
<div className="flex items-end gap-1">
|
|
||||||
<span className="text-4xl font-extrabold text-slate-900">€99</span>
|
|
||||||
<span className="text-slate-400 mb-1">{t.pricing.perMonth}</span>
|
|
||||||
</div>
|
|
||||||
<p className="text-xs text-slate-400 mt-1">{t.pricing.htva}</p>
|
|
||||||
<p className="text-xs text-slate-400 mt-1">{t.pricing.setupFeeNote}</p>
|
|
||||||
</div>
|
|
||||||
<ul className="space-y-3 flex-1 mb-8">
|
|
||||||
{[t.pricing.features.webAndKiosk, t.pricing.features.nativeApp, t.pricing.features.backoffice, t.pricing.features.sections].map((f) => (
|
|
||||||
<li key={f} className="flex items-center gap-3 text-sm text-slate-700">
|
|
||||||
<span className="material-symbols-outlined text-primary text-base shrink-0">check_circle</span>
|
|
||||||
{f}
|
|
||||||
</li>
|
|
||||||
))}
|
|
||||||
<li className="flex items-center gap-3 text-sm text-slate-700">
|
|
||||||
<span className="material-symbols-outlined text-primary text-base shrink-0">check_circle</span>
|
|
||||||
15 GB {t.pricing.features.storage}
|
|
||||||
</li>
|
|
||||||
{[t.pricing.features.offlineBeacons, t.pricing.features.pushNotif].map((f) => (
|
|
||||||
<li key={f} className="flex items-center gap-3 text-sm text-slate-700">
|
|
||||||
<span className="material-symbols-outlined text-primary text-base shrink-0">check_circle</span>
|
|
||||||
{f}
|
|
||||||
</li>
|
|
||||||
))}
|
|
||||||
<li className="flex items-center gap-3 text-sm text-slate-700">
|
|
||||||
<span className="material-symbols-outlined text-primary text-base shrink-0">check_circle</span>
|
|
||||||
{t.pricing.features.stats} — {t.pricing.features.statsBasicLabel}
|
|
||||||
</li>
|
|
||||||
{[t.pricing.features.statsAdvancedFeature, t.pricing.features.ai, t.pricing.features.autoTranslation].map((f) => (
|
|
||||||
<li key={f} className="flex items-center gap-3 text-sm text-slate-400">
|
|
||||||
<span className="material-symbols-outlined text-slate-300 text-base shrink-0">cancel</span>
|
|
||||||
{f}
|
|
||||||
</li>
|
|
||||||
))}
|
|
||||||
</ul>
|
|
||||||
<button onClick={scrollToContact} className="w-full py-3 rounded-2xl bg-primary text-slate-900 font-extrabold text-sm hover:brightness-110 transition-all shadow-lg shadow-primary/20">
|
|
||||||
{t.pricing.ctaStart}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</Reveal>
|
|
||||||
|
|
||||||
{/* Premium */}
|
|
||||||
<Reveal delay={120}>
|
|
||||||
<div className="flex flex-col h-full bg-gradient-to-br from-slate-900 to-slate-800 rounded-3xl p-8 shadow-xl">
|
|
||||||
<div className="mb-6">
|
|
||||||
<p className="text-sm font-bold text-slate-400 uppercase tracking-widest mb-2">Premium</p>
|
|
||||||
<span className="inline-flex items-center gap-1 text-xs font-semibold px-2.5 py-1 rounded-full bg-primary/10 text-primary mb-3">
|
|
||||||
<span className="material-symbols-outlined" style={{fontSize: '14px'}}>smartphone</span>
|
|
||||||
{t.pricing.channelNative}
|
|
||||||
</span>
|
|
||||||
<div className="flex items-end gap-1">
|
|
||||||
<span className="text-4xl font-extrabold text-white">€179</span>
|
|
||||||
<span className="text-slate-400 mb-1">{t.pricing.perMonth}</span>
|
|
||||||
</div>
|
|
||||||
<p className="text-xs text-slate-400 mt-1">{t.pricing.htva}</p>
|
|
||||||
<p className="text-xs text-slate-500 mt-1">{t.pricing.setupFeeNote}</p>
|
|
||||||
</div>
|
|
||||||
<ul className="space-y-3 flex-1 mb-8">
|
|
||||||
{[t.pricing.features.webAndKiosk, t.pricing.features.nativeApp, t.pricing.features.backoffice, t.pricing.features.sections].map((f) => (
|
|
||||||
<li key={f} className="flex items-center gap-3 text-sm text-slate-300">
|
|
||||||
<span className="material-symbols-outlined text-primary text-base shrink-0">check_circle</span>
|
|
||||||
{f}
|
|
||||||
</li>
|
|
||||||
))}
|
|
||||||
<li className="flex items-center gap-3 text-sm text-slate-300">
|
|
||||||
<span className="material-symbols-outlined text-primary text-base shrink-0">check_circle</span>
|
|
||||||
50 GB {t.pricing.features.storage}
|
|
||||||
</li>
|
|
||||||
{[t.pricing.features.offlineBeacons, t.pricing.features.pushNotif].map((f) => (
|
|
||||||
<li key={f} className="flex items-center gap-3 text-sm text-slate-300">
|
|
||||||
<span className="material-symbols-outlined text-primary text-base shrink-0">check_circle</span>
|
|
||||||
{f}
|
|
||||||
</li>
|
|
||||||
))}
|
|
||||||
<li className="flex items-center gap-3 text-sm text-slate-300">
|
|
||||||
<span className="material-symbols-outlined text-primary text-base shrink-0">check_circle</span>
|
|
||||||
{t.pricing.features.statsAdvancedFeature}
|
|
||||||
</li>
|
|
||||||
<li className="flex items-start gap-3 text-sm text-slate-300">
|
|
||||||
<span className="material-symbols-outlined text-primary text-base shrink-0 mt-0.5">check_circle</span>
|
|
||||||
<span>
|
|
||||||
{t.pricing.features.ai} — ≈ 2 000 {t.pricing.features.questionsPerMonth}
|
|
||||||
<span className="block text-xs text-slate-500 mt-0.5">{t.pricing.features.aiNeedMore} → Enterprise</span>
|
|
||||||
</span>
|
|
||||||
</li>
|
|
||||||
<li className="flex items-center gap-3 text-sm text-slate-300">
|
|
||||||
<span className="material-symbols-outlined text-primary text-base shrink-0">check_circle</span>
|
|
||||||
{t.pricing.features.autoTranslation}
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<button onClick={scrollToContact} className="w-full py-3 rounded-2xl bg-white/10 text-white font-bold text-sm hover:bg-white/20 transition-all border border-white/10">
|
|
||||||
{t.pricing.ctaContact}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</Reveal>
|
|
||||||
|
|
||||||
{/* Enterprise */}
|
|
||||||
<Reveal delay={180}>
|
|
||||||
<div className="flex flex-col h-full bg-gradient-to-br from-violet-950 to-slate-900 rounded-3xl p-8 shadow-xl border border-violet-800/40 relative">
|
|
||||||
<div className="mb-6">
|
|
||||||
<p className="text-sm font-bold text-violet-400 uppercase tracking-widest mb-2">Enterprise</p>
|
|
||||||
<span className="inline-flex items-center gap-1 text-xs font-semibold px-2.5 py-1 rounded-full bg-violet-500/10 text-violet-400 mb-3">
|
|
||||||
<span className="material-symbols-outlined" style={{fontSize: '14px'}}>smartphone</span>
|
|
||||||
{t.pricing.channelNative}
|
|
||||||
</span>
|
|
||||||
<div className="flex items-end gap-1">
|
|
||||||
<span className="text-3xl font-extrabold text-white">{t.pricing.enterprisePrice}</span>
|
|
||||||
</div>
|
|
||||||
<p className="text-xs text-slate-400 mt-2 leading-relaxed">{t.pricing.enterpriseDesc}</p>
|
|
||||||
</div>
|
|
||||||
<ul className="space-y-3 flex-1 mb-8">
|
|
||||||
{[
|
|
||||||
t.pricing.features.webAndKiosk,
|
|
||||||
t.pricing.features.nativeApp,
|
|
||||||
t.pricing.features.backoffice,
|
|
||||||
t.pricing.features.sections,
|
|
||||||
t.pricing.features.multiSite,
|
|
||||||
].map((f) => (
|
|
||||||
<li key={f} className="flex items-center gap-3 text-sm text-slate-300">
|
|
||||||
<span className="material-symbols-outlined text-violet-400 text-base shrink-0">check_circle</span>
|
|
||||||
{f}
|
|
||||||
</li>
|
|
||||||
))}
|
|
||||||
<li className="flex items-center gap-3 text-sm text-slate-300">
|
|
||||||
<span className="material-symbols-outlined text-violet-400 text-base shrink-0">check_circle</span>
|
|
||||||
{t.pricing.features.customStorage}
|
|
||||||
</li>
|
|
||||||
<li className="flex items-center gap-3 text-sm text-slate-300">
|
|
||||||
<span className="material-symbols-outlined text-violet-400 text-base shrink-0">check_circle</span>
|
|
||||||
{t.pricing.features.customAiQuota}
|
|
||||||
</li>
|
|
||||||
{[
|
|
||||||
t.pricing.features.statsAdvancedFeature,
|
|
||||||
t.pricing.features.offlineBeacons,
|
|
||||||
t.pricing.features.pushNotif,
|
|
||||||
t.pricing.features.autoTranslation,
|
|
||||||
t.pricing.features.slaEnhanced,
|
|
||||||
t.pricing.features.dedicatedSupport,
|
|
||||||
t.pricing.features.customDev,
|
|
||||||
].map((f) => (
|
|
||||||
<li key={f} className="flex items-center gap-3 text-sm text-slate-300">
|
|
||||||
<span className="material-symbols-outlined text-violet-400 text-base shrink-0">check_circle</span>
|
|
||||||
{f}
|
|
||||||
</li>
|
|
||||||
))}
|
|
||||||
</ul>
|
|
||||||
<button onClick={scrollToContact} className="w-full py-3 rounded-2xl bg-violet-600 text-white font-bold text-sm hover:bg-violet-500 transition-all shadow-lg shadow-violet-900/40">
|
|
||||||
{t.pricing.ctaContact}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</Reveal>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<Reveal delay={100}>
|
|
||||||
<div className="mt-12 flex flex-col sm:flex-row items-center justify-between gap-6 bg-white rounded-2xl border border-slate-200 px-8 py-6">
|
|
||||||
<div className="flex items-center gap-4">
|
|
||||||
<span className="material-symbols-outlined text-primary text-3xl shrink-0">calendar_month</span>
|
|
||||||
<div>
|
|
||||||
<p className="font-extrabold text-slate-900">{t.pricing.multiYearLabel}</p>
|
|
||||||
<p className="text-sm text-slate-500">{t.pricing.multiYearDesc}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<button
|
|
||||||
onClick={scrollToContact}
|
|
||||||
className="shrink-0 px-6 py-3 rounded-full border-2 border-primary text-primary font-bold text-sm hover:bg-primary hover:text-slate-900 transition-all whitespace-nowrap"
|
|
||||||
>
|
|
||||||
{t.pricing.multiYearCta}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</Reveal>
|
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
@ -633,8 +420,8 @@ export default function SegmentPageClient({ data, lang }: { data: Segment; lang:
|
|||||||
<section className="py-20 bg-white">
|
<section className="py-20 bg-white">
|
||||||
<div className="max-w-3xl mx-auto px-6">
|
<div className="max-w-3xl mx-auto px-6">
|
||||||
<Reveal className="text-center mb-12">
|
<Reveal className="text-center mb-12">
|
||||||
<h2 className="text-accent-orange font-extrabold uppercase tracking-widest text-sm mb-4">{s.faq.label}</h2>
|
<p className="text-accent-orange font-extrabold uppercase tracking-widest text-sm mb-4">{s.faq.label}</p>
|
||||||
<h3 className="text-3xl lg:text-4xl font-extrabold text-slate-900">{s.faq.title}</h3>
|
<h2 className="text-3xl lg:text-4xl font-extrabold text-slate-900">{s.faq.title}</h2>
|
||||||
</Reveal>
|
</Reveal>
|
||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
{s.faq.items.map((item, i) => (
|
{s.faq.items.map((item, i) => (
|
||||||
@ -696,8 +483,8 @@ export default function SegmentPageClient({ data, lang }: { data: Segment; lang:
|
|||||||
<div className="max-w-4xl mx-auto px-6">
|
<div className="max-w-4xl mx-auto px-6">
|
||||||
<div className="bg-white rounded-[3rem] shadow-2xl border border-slate-100 p-10 lg:p-16 relative">
|
<div className="bg-white rounded-[3rem] shadow-2xl border border-slate-100 p-10 lg:p-16 relative">
|
||||||
<div className="text-center mb-12">
|
<div className="text-center mb-12">
|
||||||
<h2 className="text-accent-orange font-extrabold uppercase tracking-widest text-sm mb-4">{t.contact.sectionLabel}</h2>
|
<p className="text-accent-orange font-extrabold uppercase tracking-widest text-sm mb-4">{t.contact.sectionLabel}</p>
|
||||||
<h3 className="text-3xl lg:text-4xl font-extrabold text-slate-900 mb-4">{t.contact.title}</h3>
|
<h2 className="text-3xl lg:text-4xl font-extrabold text-slate-900 mb-4">{t.contact.title}</h2>
|
||||||
<p className="text-slate-600">{t.contact.subtitle}</p>
|
<p className="text-slate-600">{t.contact.subtitle}</p>
|
||||||
</div>
|
</div>
|
||||||
{status === 'success' ? (
|
{status === 'success' ? (
|
||||||
@ -781,7 +568,7 @@ export default function SegmentPageClient({ data, lang }: { data: Segment; lang:
|
|||||||
</div>
|
</div>
|
||||||
<p className="text-slate-500 text-sm leading-relaxed mb-6">{t.footer.desc}</p>
|
<p className="text-slate-500 text-sm leading-relaxed mb-6">{t.footer.desc}</p>
|
||||||
<div className="flex gap-4">
|
<div className="flex gap-4">
|
||||||
<a className="w-10 h-10 rounded-full bg-slate-200 flex items-center justify-center text-slate-600 hover:bg-primary hover:text-slate-900 transition-all" href="#">
|
<a className="w-10 h-10 rounded-full bg-slate-200 flex items-center justify-center text-slate-600 hover:bg-primary hover:text-slate-900 transition-all" href="https://unov.be" aria-label="Unov">
|
||||||
<span className="material-symbols-outlined">public</span>
|
<span className="material-symbols-outlined">public</span>
|
||||||
</a>
|
</a>
|
||||||
<a className="w-10 h-10 rounded-full bg-slate-200 flex items-center justify-center text-slate-600 hover:bg-primary hover:text-slate-900 transition-all" href="mailto:contact@unov.be">
|
<a className="w-10 h-10 rounded-full bg-slate-200 flex items-center justify-center text-slate-600 hover:bg-primary hover:text-slate-900 transition-all" href="mailto:contact@unov.be">
|
||||||
@ -790,9 +577,33 @@ export default function SegmentPageClient({ data, lang }: { data: Segment; lang:
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div></div>
|
<div></div>
|
||||||
<div></div>
|
|
||||||
<div>
|
<div>
|
||||||
<h4 className="font-bold text-slate-900 mb-6 uppercase text-xs tracking-widest">{t.footer.contactTitle}</h4>
|
<h3 className="font-bold text-slate-900 mb-6 uppercase text-xs tracking-widest">{t.footer.pagesTitle}</h3>
|
||||||
|
<ul className="space-y-4">
|
||||||
|
{[
|
||||||
|
{ href: `/${lang}/tarifs`, label: t.footer.pageTarifs },
|
||||||
|
{ href: `/${lang}/assistant-ia`, label: t.footer.pageAssistant },
|
||||||
|
{ href: `/${lang}/borne-kiosk`, label: t.footer.pageKiosk },
|
||||||
|
{ href: `/${lang}/visite-hors-ligne`, label: t.footer.pageOffline },
|
||||||
|
{ href: `/${lang}/marches-publics`, label: t.footer.pagePublic },
|
||||||
|
// Blog en français uniquement pour l'instant.
|
||||||
|
...(lang === 'fr'
|
||||||
|
? [
|
||||||
|
{ href: '/fr/ressources', label: 'Ressources' },
|
||||||
|
{ href: '/fr/comparatif/myinfomate-vs-smartify', label: 'Comparatifs' },
|
||||||
|
]
|
||||||
|
: []),
|
||||||
|
].map((page) => (
|
||||||
|
<li key={page.href}>
|
||||||
|
<Link className="text-sm text-slate-500 hover:text-primary transition-colors" href={page.href}>
|
||||||
|
{page.label}
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 className="font-bold text-slate-900 mb-6 uppercase text-xs tracking-widest">{t.footer.contactTitle}</h3>
|
||||||
<ul className="space-y-4">
|
<ul className="space-y-4">
|
||||||
<li className="flex items-start gap-3 text-sm text-slate-500">
|
<li className="flex items-start gap-3 text-sm text-slate-500">
|
||||||
<span className="material-symbols-outlined text-primary text-sm">location_on</span>
|
<span className="material-symbols-outlined text-primary text-sm">location_on</span>
|
||||||
@ -812,8 +623,9 @@ export default function SegmentPageClient({ data, lang }: { data: Segment; lang:
|
|||||||
<div className="pt-8 border-t border-slate-200 flex flex-col md:flex-row justify-between items-center gap-4">
|
<div className="pt-8 border-t border-slate-200 flex flex-col md:flex-row justify-between items-center gap-4">
|
||||||
<p className="text-xs text-slate-400">{t.footer.copyright}</p>
|
<p className="text-xs text-slate-400">{t.footer.copyright}</p>
|
||||||
<div className="flex gap-8">
|
<div className="flex gap-8">
|
||||||
<a className="text-xs text-slate-400 hover:text-slate-600" href="/mentions-legales">{t.footer.legal}</a>
|
<Link className="text-xs text-slate-400 hover:text-slate-600" href={`/${lang}/mentions-legales`}>{t.footer.legal}</Link>
|
||||||
<a className="text-xs text-slate-400 hover:text-slate-600" href="/confidentialite">{t.footer.privacy}</a>
|
<Link className="text-xs text-slate-400 hover:text-slate-600" href={`/${lang}/confidentialite`}>{t.footer.privacy}</Link>
|
||||||
|
<Link className="text-xs text-slate-400 hover:text-slate-600" href={`/${lang}/conditions-generales`}>{t.footer.terms}</Link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import type { Metadata } from 'next';
|
|||||||
import { notFound } from 'next/navigation';
|
import { notFound } from 'next/navigation';
|
||||||
import { getSegmentData, getAllSegmentSlugs } from '@/data/segments';
|
import { getSegmentData, getAllSegmentSlugs } from '@/data/segments';
|
||||||
import { LOCALES, LOCALE_HTML_LANG, LOCALE_OG, DEFAULT_LOCALE, isLocale } from '@/i18n';
|
import { LOCALES, LOCALE_HTML_LANG, LOCALE_OG, DEFAULT_LOCALE, isLocale } from '@/i18n';
|
||||||
|
import { MYINFOMATE_LINKEDIN, breadcrumbSchema, softwareOffers } from '@/data/structured-data';
|
||||||
import SegmentPageClient from './SegmentPageClient';
|
import SegmentPageClient from './SegmentPageClient';
|
||||||
|
|
||||||
const SITE_URL = 'https://myinfomate.be';
|
const SITE_URL = 'https://myinfomate.be';
|
||||||
@ -81,23 +82,23 @@ export default async function SegmentPage({
|
|||||||
name: 'MyInfoMate',
|
name: 'MyInfoMate',
|
||||||
applicationCategory: 'BusinessApplication',
|
applicationCategory: 'BusinessApplication',
|
||||||
operatingSystem: 'iOS, Android, Web',
|
operatingSystem: 'iOS, Android, Web',
|
||||||
offers: {
|
offers: softwareOffers,
|
||||||
'@type': 'Offer',
|
sameAs: [MYINFOMATE_LINKEDIN],
|
||||||
price: '39',
|
|
||||||
priceCurrency: 'EUR',
|
|
||||||
priceSpecification: {
|
|
||||||
'@type': 'UnitPriceSpecification',
|
|
||||||
price: '39',
|
|
||||||
priceCurrency: 'EUR',
|
|
||||||
unitText: 'MONTH',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
description: data.meta[lang].description,
|
description: data.meta[lang].description,
|
||||||
url: `${SITE_URL}/${lang}/${segment}`,
|
url: `${SITE_URL}/${lang}/${segment}`,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const breadcrumb = breadcrumbSchema([
|
||||||
|
{ name: 'MyInfoMate', path: `/${lang}` },
|
||||||
|
{ name: data.translations[lang].hero.badge, path: `/${lang}/${segment}` },
|
||||||
|
]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
<script
|
||||||
|
type="application/ld+json"
|
||||||
|
dangerouslySetInnerHTML={{ __html: JSON.stringify(breadcrumb) }}
|
||||||
|
/>
|
||||||
<script
|
<script
|
||||||
type="application/ld+json"
|
type="application/ld+json"
|
||||||
dangerouslySetInnerHTML={{ __html: JSON.stringify(faqSchema) }}
|
dangerouslySetInnerHTML={{ __html: JSON.stringify(faqSchema) }}
|
||||||
|
|||||||
660
src/app/[lang]/assistant-ia/page.tsx
Normal file
@ -0,0 +1,660 @@
|
|||||||
|
import type { Metadata } from 'next';
|
||||||
|
import Link from 'next/link';
|
||||||
|
import { notFound } from 'next/navigation';
|
||||||
|
import { LOCALES, LOCALE_HTML_LANG, LOCALE_OG, DEFAULT_LOCALE, isLocale, type Locale } from '@/i18n';
|
||||||
|
import { MYINFOMATE_LINKEDIN, breadcrumbSchema, softwareOffers } from '@/data/structured-data';
|
||||||
|
|
||||||
|
const SITE_URL = 'https://myinfomate.be';
|
||||||
|
|
||||||
|
type Item = { icon: string; title: string; text: string };
|
||||||
|
|
||||||
|
type PageText = {
|
||||||
|
meta: { title: string; description: string };
|
||||||
|
back: string;
|
||||||
|
badge: string;
|
||||||
|
h1Before: string;
|
||||||
|
h1Highlight: string;
|
||||||
|
heroText: string;
|
||||||
|
ctaDemo: string;
|
||||||
|
ctaPricing: string;
|
||||||
|
howTitle: string;
|
||||||
|
howIntro: string;
|
||||||
|
stepLabel: string;
|
||||||
|
steps: Item[];
|
||||||
|
benefitsTitle: string;
|
||||||
|
benefits: Item[];
|
||||||
|
guardTitle: string;
|
||||||
|
guardIntro: string;
|
||||||
|
guardrails: string[];
|
||||||
|
priceTitle: string;
|
||||||
|
priceBefore: string;
|
||||||
|
priceStrong: string;
|
||||||
|
priceAfter: string;
|
||||||
|
priceEnterprise: string;
|
||||||
|
priceCta: string;
|
||||||
|
faqTitle: string;
|
||||||
|
faq: { question: string; answer: string }[];
|
||||||
|
ctaTitle: string;
|
||||||
|
ctaButton: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const TEXT_BY_LOCALE: Record<Locale, PageText> = {
|
||||||
|
fr: {
|
||||||
|
meta: {
|
||||||
|
title: 'Assistant IA pour musées et lieux culturels | MyInfoMate',
|
||||||
|
description: "Un guide IA intégré à votre application visiteur : il répond 24 h/24, dans la langue du visiteur, en s'appuyant uniquement sur les contenus de votre lieu. Inclus dès 179 €/mois.",
|
||||||
|
},
|
||||||
|
back: "Retour à l'accueil",
|
||||||
|
badge: 'Assistant IA',
|
||||||
|
h1Before: 'Un guide qui répond à vos visiteurs ',
|
||||||
|
h1Highlight: '24 h/24, dans leur langue',
|
||||||
|
heroText: "L'assistant IA de MyInfoMate est intégré à votre application visiteur. Il répond aux questions de vos visiteurs en s'appuyant uniquement sur les contenus de votre lieu — et décline tout le reste.",
|
||||||
|
ctaDemo: 'Demander une démo sur vos contenus',
|
||||||
|
ctaPricing: 'Voir les tarifs',
|
||||||
|
howTitle: 'Comment ça marche',
|
||||||
|
howIntro: "Aucun scénario à écrire, aucune liste de questions à prévoir : l'assistant se nourrit du contenu que vous gérez déjà.",
|
||||||
|
stepLabel: 'Étape',
|
||||||
|
steps: [
|
||||||
|
{
|
||||||
|
icon: 'upload_file',
|
||||||
|
title: "Vous écrivez vos contenus, comme d'habitude",
|
||||||
|
text: "Points d'intérêt, expositions, horaires, services : vous les saisissez dans le back-office MyInfoMate. Il n'y a rien de plus à faire, aucun paramétrage d'IA, aucune liste de questions à préparer.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'manage_search',
|
||||||
|
title: "L'assistant apprend votre lieu",
|
||||||
|
text: "Il s'appuie sur ces contenus pour répondre. Quand vous modifiez une fiche ou ajoutez une salle, ses réponses suivent : c'est la même source de vérité que le reste de votre application.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'forum',
|
||||||
|
title: 'Le visiteur pose sa question, en langage normal',
|
||||||
|
text: "« Où est la salle des impressionnistes ? », « C'est adapté à des enfants de 6 ans ? », « Qu'est-ce qu'il faut voir si je n'ai qu'une heure ? » L'assistant garde le fil de la conversation pendant toute la visite.",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
benefitsTitle: 'Ce que ça change dans un lieu culturel',
|
||||||
|
benefits: [
|
||||||
|
{
|
||||||
|
icon: 'translate',
|
||||||
|
title: 'Chaque visiteur dans sa langue',
|
||||||
|
text: "Français, anglais, néerlandais, allemand et d'autres. Vous n'avez pas à traduire tout votre lieu pour répondre à un visiteur étranger devant une œuvre.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'schedule',
|
||||||
|
title: "Disponible quand personne ne l'est",
|
||||||
|
text: "Un mardi à 16 h dans une salle sans médiateur, un dimanche, une visite en autonomie : la question trouve une réponse au moment où elle se pose.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'support_agent',
|
||||||
|
title: "Moins de questions répétitives à l'accueil",
|
||||||
|
text: "Les horaires, les toilettes, la durée du parcours, le tarif famille : votre équipe garde son temps pour les échanges qui en valent la peine.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'auto_stories',
|
||||||
|
title: 'Vos contenus enfin lus',
|
||||||
|
text: "Un visiteur pose rarement une question à un panneau. L'assistant transforme le contenu que vous avez déjà écrit en conversation — et le rend utile.",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
guardTitle: "Ce qu'il ne fait pas",
|
||||||
|
guardIntro: "Un assistant utile dans un musée est d'abord un assistant qui se tait quand il ne sait pas.",
|
||||||
|
guardrails: [
|
||||||
|
"Il ne parle que de votre lieu. Une question hors sujet est déclinée, pas improvisée.",
|
||||||
|
"Il s'appuie sur vos contenus, pas sur le web : ce qui n'est pas dans votre back-office n'est pas inventé.",
|
||||||
|
"Il ne remplace ni un médiateur ni une visite guidée — il prend le relais quand il n'y a personne.",
|
||||||
|
"Il a besoin d'une connexion. Les contenus téléchargés pour le mode hors ligne, eux, restent consultables sans réseau.",
|
||||||
|
],
|
||||||
|
priceTitle: 'Combien ça coûte',
|
||||||
|
priceBefore: "L'assistant IA est inclus dans le plan ",
|
||||||
|
priceStrong: 'Premium, à 179 €/mois hors TVA',
|
||||||
|
priceAfter: ', avec environ 2 000 questions de visiteurs par mois — la traduction automatique de vos contenus y est comprise.',
|
||||||
|
priceEnterprise: "Pour un réseau de plusieurs sites ou un volume plus élevé, le plan Enterprise permet de fixer un quota sur mesure.",
|
||||||
|
priceCta: 'Voir la grille tarifaire',
|
||||||
|
faqTitle: "Questions fréquentes sur l'assistant IA",
|
||||||
|
faq: [
|
||||||
|
{
|
||||||
|
question: "Qu'est-ce qu'un assistant IA pour musée ?",
|
||||||
|
answer: "C'est un guide conversationnel intégré à l'application visiteur du lieu. Le visiteur pose sa question en langage naturel — sur une œuvre, un parcours, un horaire, un service — et l'assistant répond en s'appuyant sur les contenus publiés par le lieu dans son back-office. Il est disponible 24 h/24 et répond dans la langue du visiteur.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: "Est-ce que l'assistant peut inventer des réponses ?",
|
||||||
|
answer: "Il est délibérément limité aux contenus de votre lieu : points d'intérêt, expositions, services, agenda. Une question qui sort de ce périmètre est déclinée plutôt qu'improvisée. C'est ce qui le distingue d'un assistant généraliste, où un visiteur peut recevoir une réponse plausible mais fausse sur vos collections.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Dans quelles langues répond-il ?',
|
||||||
|
answer: "Il répond dans la langue du visiteur : français, anglais, néerlandais, allemand, et d'autres. Vos contenus peuvent par ailleurs être traduits automatiquement, une fonctionnalité incluse dans le même plan que l'assistant.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: "Faut-il préparer les questions et les réponses à l'avance ?",
|
||||||
|
answer: "Non. Il n'y a pas d'arbre de décision à construire, contrairement à un chatbot classique. Vous rédigez vos contenus de visite normalement dans le back-office, et l'assistant s'appuie dessus. Quand vous modifiez un contenu, ses réponses suivent.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: "Combien coûte l'assistant IA ?",
|
||||||
|
answer: "Il est inclus dans le plan Premium, à 179 €/mois hors TVA, avec environ 2 000 questions de visiteurs par mois. Pour un volume plus élevé ou un réseau de plusieurs sites, le plan Enterprise permet de fixer un quota sur mesure.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Fonctionne-t-il sans connexion internet ?',
|
||||||
|
answer: "Non : l'assistant a besoin d'une connexion pour répondre. En revanche, le mode hors ligne de MyInfoMate permet de télécharger les contenus de la visite à l'entrée du site, pour les consulter ensuite sans réseau — comme au Fort de Saint-Héribert, dont les galeries souterraines ne captent pas.",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
ctaTitle: 'Envie de le voir répondre sur vos propres contenus ?',
|
||||||
|
ctaButton: 'Demander une démo gratuite',
|
||||||
|
},
|
||||||
|
en: {
|
||||||
|
meta: {
|
||||||
|
title: 'AI Assistant for Museums & Cultural Venues | MyInfoMate',
|
||||||
|
description: 'An AI guide built into your visitor app: it answers 24/7, in the visitor’s language, drawing only on your venue’s own content. Included from €179/month.',
|
||||||
|
},
|
||||||
|
back: 'Back to home',
|
||||||
|
badge: 'AI assistant',
|
||||||
|
h1Before: 'A guide that answers your visitors ',
|
||||||
|
h1Highlight: '24/7, in their own language',
|
||||||
|
heroText: "The MyInfoMate AI assistant is built into your visitor app. It answers your visitors' questions drawing only on your venue's own content — and declines everything else.",
|
||||||
|
ctaDemo: 'Request a demo on your content',
|
||||||
|
ctaPricing: 'See pricing',
|
||||||
|
howTitle: 'How it works',
|
||||||
|
howIntro: 'No script to write, no list of questions to anticipate: the assistant feeds on the content you already manage.',
|
||||||
|
stepLabel: 'Step',
|
||||||
|
steps: [
|
||||||
|
{
|
||||||
|
icon: 'upload_file',
|
||||||
|
title: 'You write your content, as usual',
|
||||||
|
text: 'Points of interest, exhibitions, opening hours, services: you enter them in the MyInfoMate back-office. Nothing else to do — no AI settings, no list of questions to prepare.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'manage_search',
|
||||||
|
title: 'The assistant learns your venue',
|
||||||
|
text: 'It relies on that content to answer. When you edit an entry or add a room, its answers follow: it is the same source of truth as the rest of your app.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'forum',
|
||||||
|
title: 'The visitor simply asks',
|
||||||
|
text: '"Where is the impressionist room?", "Is this suitable for a six-year-old?", "What should I see if I only have an hour?" The assistant keeps the thread of the conversation throughout the visit.',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
benefitsTitle: 'What it changes in a cultural venue',
|
||||||
|
benefits: [
|
||||||
|
{
|
||||||
|
icon: 'translate',
|
||||||
|
title: "Every visitor in their own language",
|
||||||
|
text: "French, English, Dutch, German and more. You don't have to translate your whole venue to answer a foreign visitor standing in front of an artwork.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'schedule',
|
||||||
|
title: 'Available when nobody else is',
|
||||||
|
text: 'A Tuesday at 4 pm in a room with no guide, a Sunday, a self-guided visit: the question gets an answer the moment it comes up.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'support_agent',
|
||||||
|
title: 'Fewer repetitive questions at the desk',
|
||||||
|
text: 'Opening hours, toilets, how long the trail takes, the family rate: your team keeps its time for the conversations that deserve it.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'auto_stories',
|
||||||
|
title: 'Your content finally read',
|
||||||
|
text: 'Visitors rarely ask a wall panel a question. The assistant turns the content you already wrote into a conversation — and makes it useful.',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
guardTitle: "What it does not do",
|
||||||
|
guardIntro: 'A useful assistant in a museum is first of all an assistant that stays silent when it does not know.',
|
||||||
|
guardrails: [
|
||||||
|
'It only talks about your venue. An off-topic question is declined, not improvised.',
|
||||||
|
'It draws on your content, not the web: what is not in your back-office is not invented.',
|
||||||
|
'It replaces neither a guide nor a guided tour — it takes over when nobody is around.',
|
||||||
|
'It needs a connection. Content downloaded for offline mode, however, stays available without a network.',
|
||||||
|
],
|
||||||
|
priceTitle: 'What it costs',
|
||||||
|
priceBefore: 'The AI assistant is included in the ',
|
||||||
|
priceStrong: 'Premium plan, at €179/month excl. VAT',
|
||||||
|
priceAfter: ', with around 2,000 visitor questions per month — automatic translation of your content is included too.',
|
||||||
|
priceEnterprise: 'For a network of several sites or a higher volume, the Enterprise plan allows a custom quota.',
|
||||||
|
priceCta: 'See the pricing table',
|
||||||
|
faqTitle: 'AI assistant FAQ',
|
||||||
|
faq: [
|
||||||
|
{
|
||||||
|
question: 'What is an AI assistant for a museum?',
|
||||||
|
answer: "It is a conversational guide built into the venue's visitor app. The visitor asks a question in natural language — about an artwork, a trail, opening hours, a service — and the assistant answers based on the content the venue published in its back-office. It is available 24/7 and answers in the visitor's language.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Can the assistant make up answers?',
|
||||||
|
answer: 'It is deliberately limited to your own content: points of interest, exhibitions, services, agenda. A question outside that scope is declined rather than improvised. That is what sets it apart from a general-purpose assistant, where a visitor may get a plausible but wrong answer about your collections.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Which languages does it answer in?',
|
||||||
|
answer: "It answers in the visitor's language: French, English, Dutch, German and more. Your content can also be translated automatically, a feature included in the same plan as the assistant.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Do questions and answers have to be prepared upfront?',
|
||||||
|
answer: 'No. There is no decision tree to build, unlike a classic chatbot. You write your visit content normally in the back-office and the assistant relies on it. When you edit content, its answers follow.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'How much does the AI assistant cost?',
|
||||||
|
answer: 'It is included in the Premium plan, at €179/month excluding VAT, with around 2,000 visitor questions per month. For a higher volume or a network of several sites, the Enterprise plan allows a custom quota.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Does it work without an internet connection?',
|
||||||
|
answer: 'No: the assistant needs a connection to answer. MyInfoMate\'s offline mode, however, lets visitors download the visit content at the entrance and browse it without a network afterwards — as at Fort de Saint-Héribert, whose underground galleries have no coverage.',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
ctaTitle: 'Want to see it answer on your own content?',
|
||||||
|
ctaButton: 'Request a free demo',
|
||||||
|
},
|
||||||
|
nl: {
|
||||||
|
meta: {
|
||||||
|
title: 'AI-assistent voor musea & culturele locaties | MyInfoMate',
|
||||||
|
description: 'Een AI-gids in uw bezoekersapp: hij antwoordt 24/7, in de taal van de bezoeker, uitsluitend op basis van de inhoud van uw locatie. Inbegrepen vanaf €179/maand.',
|
||||||
|
},
|
||||||
|
back: 'Terug naar home',
|
||||||
|
badge: 'AI-assistent',
|
||||||
|
h1Before: 'Een gids die uw bezoekers antwoordt, ',
|
||||||
|
h1Highlight: '24/7 en in hun eigen taal',
|
||||||
|
heroText: 'De AI-assistent van MyInfoMate zit in uw bezoekersapp. Hij antwoordt op vragen van bezoekers uitsluitend op basis van de inhoud van uw locatie — al het andere wijst hij af.',
|
||||||
|
ctaDemo: 'Demo aanvragen met uw inhoud',
|
||||||
|
ctaPricing: 'Tarieven bekijken',
|
||||||
|
howTitle: 'Hoe het werkt',
|
||||||
|
howIntro: 'Geen scenario om te schrijven, geen lijst met vragen om te voorzien: de assistent voedt zich met de inhoud die u al beheert.',
|
||||||
|
stepLabel: 'Stap',
|
||||||
|
steps: [
|
||||||
|
{
|
||||||
|
icon: 'upload_file',
|
||||||
|
title: 'U schrijft uw inhoud, zoals altijd',
|
||||||
|
text: 'Bezienswaardigheden, tentoonstellingen, openingsuren, diensten: u voert ze in de MyInfoMate-back-office in. Meer is er niet nodig — geen AI-instellingen, geen lijst met vragen om voor te bereiden.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'manage_search',
|
||||||
|
title: 'De assistent leert uw locatie',
|
||||||
|
text: 'Hij baseert zijn antwoorden op die inhoud. Wijzigt u een fiche of voegt u een zaal toe, dan volgen zijn antwoorden: het is dezelfde bron als de rest van uw app.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'forum',
|
||||||
|
title: 'De bezoeker stelt zijn vraag, gewoon in eigen woorden',
|
||||||
|
text: '"Waar is de zaal met de impressionisten?", "Is dit geschikt voor een kind van zes?", "Wat moet ik zien als ik maar een uur heb?" De assistent houdt de draad van het gesprek vast tijdens het hele bezoek.',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
benefitsTitle: 'Wat het verandert in een culturele locatie',
|
||||||
|
benefits: [
|
||||||
|
{
|
||||||
|
icon: 'translate',
|
||||||
|
title: 'Elke bezoeker in zijn eigen taal',
|
||||||
|
text: 'Nederlands, Frans, Engels, Duits en meer. U hoeft niet uw hele locatie te vertalen om een buitenlandse bezoeker voor een kunstwerk te woord te staan.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'schedule',
|
||||||
|
title: 'Beschikbaar wanneer niemand anders het is',
|
||||||
|
text: 'Een dinsdag om 16 u in een zaal zonder begeleider, een zondag, een bezoek op eigen tempo: de vraag krijgt een antwoord op het moment dat ze opkomt.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'support_agent',
|
||||||
|
title: 'Minder herhaalde vragen aan de balie',
|
||||||
|
text: 'Openingsuren, toiletten, de duur van het parcours, het gezinstarief: uw team houdt tijd over voor de gesprekken die dat verdienen.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'auto_stories',
|
||||||
|
title: 'Uw inhoud wordt eindelijk gelezen',
|
||||||
|
text: 'Een bezoeker stelt zelden een vraag aan een infopaneel. De assistent maakt van de inhoud die u al schreef een gesprek — en maakt ze nuttig.',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
guardTitle: 'Wat hij niet doet',
|
||||||
|
guardIntro: 'Een nuttige assistent in een museum is in de eerste plaats een assistent die zwijgt wanneer hij het niet weet.',
|
||||||
|
guardrails: [
|
||||||
|
'Hij spreekt alleen over uw locatie. Een vraag buiten het onderwerp wordt afgewezen, niet geïmproviseerd.',
|
||||||
|
'Hij baseert zich op uw inhoud, niet op het web: wat niet in uw back-office staat, wordt niet verzonnen.',
|
||||||
|
'Hij vervangt geen begeleider en geen gegidst bezoek — hij neemt over wanneer er niemand is.',
|
||||||
|
'Hij heeft een verbinding nodig. De inhoud die voor de offline modus is gedownload, blijft wél beschikbaar zonder netwerk.',
|
||||||
|
],
|
||||||
|
priceTitle: 'Wat het kost',
|
||||||
|
priceBefore: 'De AI-assistent zit in het ',
|
||||||
|
priceStrong: 'Premium-abonnement, aan €179/maand excl. btw',
|
||||||
|
priceAfter: ', met ongeveer 2.000 bezoekersvragen per maand — de automatische vertaling van uw inhoud is inbegrepen.',
|
||||||
|
priceEnterprise: 'Voor een netwerk van meerdere sites of een hoger volume laat het Enterprise-abonnement een quotum op maat toe.',
|
||||||
|
priceCta: 'Tarievenoverzicht bekijken',
|
||||||
|
faqTitle: 'Veelgestelde vragen over de AI-assistent',
|
||||||
|
faq: [
|
||||||
|
{
|
||||||
|
question: 'Wat is een AI-assistent voor een museum?',
|
||||||
|
answer: 'Het is een gesprekgids die in de bezoekersapp van de locatie zit. De bezoeker stelt zijn vraag in gewone taal — over een kunstwerk, een parcours, een openingsuur, een dienst — en de assistent antwoordt op basis van de inhoud die de locatie in haar back-office publiceerde. Hij is 24/7 beschikbaar en antwoordt in de taal van de bezoeker.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Kan de assistent antwoorden verzinnen?',
|
||||||
|
answer: 'Hij is bewust beperkt tot de inhoud van uw locatie: bezienswaardigheden, tentoonstellingen, diensten, agenda. Een vraag buiten dat kader wordt afgewezen in plaats van geïmproviseerd. Dat onderscheidt hem van een algemene assistent, waar een bezoeker een plausibel maar fout antwoord over uw collectie kan krijgen.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'In welke talen antwoordt hij?',
|
||||||
|
answer: 'Hij antwoordt in de taal van de bezoeker: Nederlands, Frans, Engels, Duits en meer. Uw inhoud kan bovendien automatisch worden vertaald, een functie die in hetzelfde abonnement als de assistent zit.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Moeten de vragen en antwoorden vooraf worden voorbereid?',
|
||||||
|
answer: 'Nee. Er is geen beslissingsboom te bouwen, anders dan bij een klassieke chatbot. U schrijft uw bezoekinhoud gewoon in de back-office en de assistent baseert zich daarop. Wijzigt u die inhoud, dan volgen zijn antwoorden.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Hoeveel kost de AI-assistent?',
|
||||||
|
answer: 'Hij zit in het Premium-abonnement, aan €179/maand excl. btw, met ongeveer 2.000 bezoekersvragen per maand. Voor een hoger volume of een netwerk van meerdere sites laat het Enterprise-abonnement een quotum op maat toe.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Werkt hij zonder internetverbinding?',
|
||||||
|
answer: 'Nee: de assistent heeft een verbinding nodig om te antwoorden. De offline modus van MyInfoMate laat wel toe om de inhoud van het bezoek aan de ingang te downloaden en ze daarna zonder netwerk te bekijken — zoals in het Fort de Saint-Héribert, waar de ondergrondse galerijen geen bereik hebben.',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
ctaTitle: 'Wilt u hem zien antwoorden op uw eigen inhoud?',
|
||||||
|
ctaButton: 'Gratis demo aanvragen',
|
||||||
|
},
|
||||||
|
de: {
|
||||||
|
meta: {
|
||||||
|
title: 'KI-Assistent für Museen & Kulturstätten | MyInfoMate',
|
||||||
|
description: 'Ein KI-Guide in Ihrer Besucher-App: Er antwortet rund um die Uhr, in der Sprache des Besuchers, ausschließlich auf Basis Ihrer eigenen Inhalte. Enthalten ab 179 €/Monat.',
|
||||||
|
},
|
||||||
|
back: 'Zurück zur Startseite',
|
||||||
|
badge: 'KI-Assistent',
|
||||||
|
h1Before: 'Ein Guide, der Ihren Besuchern antwortet — ',
|
||||||
|
h1Highlight: 'rund um die Uhr, in ihrer Sprache',
|
||||||
|
heroText: 'Der KI-Assistent von MyInfoMate ist in Ihre Besucher-App integriert. Er beantwortet die Fragen Ihrer Besucher ausschließlich auf Basis der Inhalte Ihres Ortes — alles andere lehnt er ab.',
|
||||||
|
ctaDemo: 'Demo mit Ihren Inhalten anfragen',
|
||||||
|
ctaPricing: 'Preise ansehen',
|
||||||
|
howTitle: 'So funktioniert es',
|
||||||
|
howIntro: 'Kein Skript zu schreiben, keine Liste möglicher Fragen: Der Assistent nutzt die Inhalte, die Sie ohnehin pflegen.',
|
||||||
|
stepLabel: 'Schritt',
|
||||||
|
steps: [
|
||||||
|
{
|
||||||
|
icon: 'upload_file',
|
||||||
|
title: 'Sie schreiben Ihre Inhalte wie gewohnt',
|
||||||
|
text: 'Sehenswürdigkeiten, Ausstellungen, Öffnungszeiten, Services: Sie erfassen sie im MyInfoMate-Back-Office. Mehr ist nicht nötig — keine KI-Einstellungen, keine Liste vorbereiteter Fragen.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'manage_search',
|
||||||
|
title: 'Der Assistent lernt Ihren Ort',
|
||||||
|
text: 'Er stützt seine Antworten auf diese Inhalte. Ändern Sie einen Eintrag oder ergänzen Sie einen Raum, folgen seine Antworten: dieselbe Quelle wie der Rest Ihrer App.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'forum',
|
||||||
|
title: 'Der Besucher fragt einfach nach',
|
||||||
|
text: '„Wo ist der Saal mit den Impressionisten?“, „Ist das für ein sechsjähriges Kind geeignet?“, „Was sollte ich sehen, wenn ich nur eine Stunde habe?“ Der Assistent behält den Gesprächsfaden über den ganzen Besuch.',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
benefitsTitle: 'Was sich an einem Kulturort ändert',
|
||||||
|
benefits: [
|
||||||
|
{
|
||||||
|
icon: 'translate',
|
||||||
|
title: 'Jeder Besucher in seiner Sprache',
|
||||||
|
text: 'Deutsch, Französisch, Englisch, Niederländisch und mehr. Sie müssen nicht Ihren ganzen Ort übersetzen, um einem ausländischen Besucher vor einem Werk zu antworten.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'schedule',
|
||||||
|
title: 'Verfügbar, wenn sonst niemand da ist',
|
||||||
|
text: 'Dienstag um 16 Uhr in einem Saal ohne Betreuung, ein Sonntag, ein Besuch auf eigene Faust: Die Frage findet eine Antwort in dem Moment, in dem sie entsteht.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'support_agent',
|
||||||
|
title: 'Weniger wiederkehrende Fragen am Empfang',
|
||||||
|
text: 'Öffnungszeiten, Toiletten, Dauer des Rundgangs, Familientarif: Ihr Team behält Zeit für die Gespräche, die es wert sind.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'auto_stories',
|
||||||
|
title: 'Ihre Inhalte werden endlich gelesen',
|
||||||
|
text: 'Kaum ein Besucher stellt einer Texttafel eine Frage. Der Assistent macht aus den Inhalten, die Sie längst geschrieben haben, ein Gespräch — und damit etwas Nützliches.',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
guardTitle: 'Was er nicht tut',
|
||||||
|
guardIntro: 'Ein nützlicher Assistent im Museum ist zuerst einer, der schweigt, wenn er es nicht weiß.',
|
||||||
|
guardrails: [
|
||||||
|
'Er spricht nur über Ihren Ort. Eine Frage außerhalb des Themas wird abgelehnt, nicht improvisiert.',
|
||||||
|
'Er stützt sich auf Ihre Inhalte, nicht auf das Web: Was nicht in Ihrem Back-Office steht, wird nicht erfunden.',
|
||||||
|
'Er ersetzt weder eine Betreuung noch eine Führung — er übernimmt, wenn niemand da ist.',
|
||||||
|
'Er braucht eine Verbindung. Die für den Offline-Modus heruntergeladenen Inhalte bleiben dagegen ohne Netz verfügbar.',
|
||||||
|
],
|
||||||
|
priceTitle: 'Was es kostet',
|
||||||
|
priceBefore: 'Der KI-Assistent ist im ',
|
||||||
|
priceStrong: 'Premium-Plan für 179 €/Monat zzgl. MwSt.',
|
||||||
|
priceAfter: ' enthalten, mit rund 2.000 Besucherfragen pro Monat — die automatische Übersetzung Ihrer Inhalte inklusive.',
|
||||||
|
priceEnterprise: 'Für ein Netz mehrerer Standorte oder ein höheres Volumen erlaubt der Enterprise-Plan ein individuelles Kontingent.',
|
||||||
|
priceCta: 'Preisübersicht ansehen',
|
||||||
|
faqTitle: 'Häufige Fragen zum KI-Assistenten',
|
||||||
|
faq: [
|
||||||
|
{
|
||||||
|
question: 'Was ist ein KI-Assistent für ein Museum?',
|
||||||
|
answer: 'Es ist ein dialogfähiger Guide in der Besucher-App des Ortes. Der Besucher stellt seine Frage in natürlicher Sprache — zu einem Werk, einem Rundgang, einer Öffnungszeit, einem Service — und der Assistent antwortet auf Basis der Inhalte, die der Ort in seinem Back-Office veröffentlicht hat. Er ist rund um die Uhr verfügbar und antwortet in der Sprache des Besuchers.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Kann der Assistent Antworten erfinden?',
|
||||||
|
answer: 'Er ist bewusst auf die Inhalte Ihres Ortes beschränkt: Sehenswürdigkeiten, Ausstellungen, Services, Agenda. Eine Frage außerhalb dieses Rahmens wird abgelehnt statt improvisiert. Das unterscheidet ihn von einem allgemeinen Assistenten, bei dem ein Besucher eine plausible, aber falsche Antwort über Ihre Sammlung erhalten kann.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'In welchen Sprachen antwortet er?',
|
||||||
|
answer: 'Er antwortet in der Sprache des Besuchers: Deutsch, Französisch, Englisch, Niederländisch und mehr. Ihre Inhalte können zudem automatisch übersetzt werden — eine Funktion, die im selben Plan wie der Assistent enthalten ist.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Müssen Fragen und Antworten vorab vorbereitet werden?',
|
||||||
|
answer: 'Nein. Es gibt keinen Entscheidungsbaum zu bauen, anders als bei einem klassischen Chatbot. Sie schreiben Ihre Besuchsinhalte normal im Back-Office, und der Assistent stützt sich darauf. Ändern Sie einen Inhalt, folgen seine Antworten.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Was kostet der KI-Assistent?',
|
||||||
|
answer: 'Er ist im Premium-Plan für 179 €/Monat zzgl. MwSt. enthalten, mit rund 2.000 Besucherfragen pro Monat. Für ein höheres Volumen oder ein Netz mehrerer Standorte erlaubt der Enterprise-Plan ein individuelles Kontingent.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Funktioniert er ohne Internetverbindung?',
|
||||||
|
answer: 'Nein: Der Assistent braucht eine Verbindung, um zu antworten. Der Offline-Modus von MyInfoMate erlaubt es jedoch, die Inhalte des Besuchs am Eingang herunterzuladen und sie danach ohne Netz zu nutzen — wie im Fort de Saint-Héribert, dessen unterirdische Galerien keinen Empfang haben.',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
ctaTitle: 'Möchten Sie ihn auf Ihren eigenen Inhalten erleben?',
|
||||||
|
ctaButton: 'Kostenlose Demo anfordern',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export function generateStaticParams() {
|
||||||
|
return LOCALES.map((lang) => ({ lang }));
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function generateMetadata({
|
||||||
|
params,
|
||||||
|
}: {
|
||||||
|
params: Promise<{ lang: string }>;
|
||||||
|
}): Promise<Metadata> {
|
||||||
|
const { lang } = await params;
|
||||||
|
if (!isLocale(lang)) return {};
|
||||||
|
const m = TEXT_BY_LOCALE[lang].meta;
|
||||||
|
const languages = Object.fromEntries(LOCALES.map((l) => [LOCALE_HTML_LANG[l], `/${l}/assistant-ia`]));
|
||||||
|
return {
|
||||||
|
title: m.title,
|
||||||
|
description: m.description,
|
||||||
|
openGraph: {
|
||||||
|
title: m.title,
|
||||||
|
description: m.description,
|
||||||
|
url: `${SITE_URL}/${lang}/assistant-ia`,
|
||||||
|
siteName: 'MyInfoMate',
|
||||||
|
locale: LOCALE_OG[lang],
|
||||||
|
type: 'website',
|
||||||
|
},
|
||||||
|
alternates: {
|
||||||
|
canonical: `/${lang}/assistant-ia`,
|
||||||
|
languages: { ...languages, 'x-default': `/${DEFAULT_LOCALE}/assistant-ia` },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default async function AssistantIaPage({ params }: { params: Promise<{ lang: string }> }) {
|
||||||
|
const { lang } = await params;
|
||||||
|
if (!isLocale(lang)) notFound();
|
||||||
|
const text = TEXT_BY_LOCALE[lang];
|
||||||
|
|
||||||
|
const faqSchema = {
|
||||||
|
'@context': 'https://schema.org',
|
||||||
|
'@type': 'FAQPage',
|
||||||
|
mainEntity: text.faq.map((item) => ({
|
||||||
|
'@type': 'Question',
|
||||||
|
name: item.question,
|
||||||
|
acceptedAnswer: { '@type': 'Answer', text: item.answer },
|
||||||
|
})),
|
||||||
|
};
|
||||||
|
|
||||||
|
const softwareSchema = {
|
||||||
|
'@context': 'https://schema.org',
|
||||||
|
'@type': 'SoftwareApplication',
|
||||||
|
name: 'MyInfoMate',
|
||||||
|
applicationCategory: 'BusinessApplication',
|
||||||
|
operatingSystem: 'iOS, Android, Web',
|
||||||
|
offers: softwareOffers,
|
||||||
|
sameAs: [MYINFOMATE_LINKEDIN],
|
||||||
|
description: text.meta.description,
|
||||||
|
url: `${SITE_URL}/${lang}/assistant-ia`,
|
||||||
|
inLanguage: [...LOCALES],
|
||||||
|
};
|
||||||
|
|
||||||
|
const breadcrumb = breadcrumbSchema([
|
||||||
|
{ name: 'MyInfoMate', path: `/${lang}` },
|
||||||
|
{ name: text.badge, path: `/${lang}/assistant-ia` },
|
||||||
|
]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<main className="bg-slate-50 text-slate-900 min-h-screen font-display">
|
||||||
|
<script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(breadcrumb) }} />
|
||||||
|
<script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(faqSchema) }} />
|
||||||
|
<script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(softwareSchema) }} />
|
||||||
|
|
||||||
|
<header className="fixed top-0 left-0 right-0 z-50 bg-white/80 backdrop-blur-md border-b border-slate-200">
|
||||||
|
<div className="max-w-7xl mx-auto px-6 h-16 flex items-center gap-4">
|
||||||
|
<Link href={`/${lang}`} className="flex items-center gap-2 text-sm font-bold text-slate-600 hover:text-primary transition-colors">
|
||||||
|
<span className="material-symbols-outlined text-base">arrow_back</span>
|
||||||
|
{text.back}
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div className="pt-16">
|
||||||
|
{/* Hero */}
|
||||||
|
<section className="py-20 lg:py-28 bg-slate-900 relative overflow-hidden">
|
||||||
|
<div className="absolute inset-0 pointer-events-none">
|
||||||
|
<div className="absolute top-10 left-1/4 w-96 h-96 bg-primary/10 rounded-full blur-3xl"></div>
|
||||||
|
<div className="absolute bottom-10 right-1/4 w-80 h-80 bg-accent-violet/10 rounded-full blur-3xl"></div>
|
||||||
|
</div>
|
||||||
|
<div className="max-w-4xl mx-auto px-6 text-center relative z-10">
|
||||||
|
<div className="inline-flex items-center gap-2 bg-primary/10 border border-primary/30 text-primary text-xs font-extrabold uppercase tracking-widest px-4 py-2 rounded-full mb-6">
|
||||||
|
<span className="material-symbols-outlined text-sm">auto_awesome</span>
|
||||||
|
{text.badge}
|
||||||
|
</div>
|
||||||
|
<h1 className="text-4xl lg:text-6xl font-extrabold text-white leading-[1.1] mb-6">
|
||||||
|
{text.h1Before}<span className="gradient-text">{text.h1Highlight}</span>
|
||||||
|
</h1>
|
||||||
|
<p className="text-lg text-slate-400 max-w-2xl mx-auto mb-10">{text.heroText}</p>
|
||||||
|
<div className="flex flex-col sm:flex-row gap-4 justify-center">
|
||||||
|
<Link
|
||||||
|
href={`/${lang}#contact`}
|
||||||
|
className="px-8 py-4 bg-primary text-slate-900 font-extrabold rounded-full shadow-xl shadow-primary/30 hover:brightness-110 transition-all"
|
||||||
|
>
|
||||||
|
{text.ctaDemo}
|
||||||
|
</Link>
|
||||||
|
<Link
|
||||||
|
href={`/${lang}/tarifs`}
|
||||||
|
className="px-8 py-4 bg-white/10 text-white font-bold rounded-full border border-white/20 hover:bg-white/20 transition-all"
|
||||||
|
>
|
||||||
|
{text.ctaPricing}
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* Comment ça marche */}
|
||||||
|
<section className="py-20 bg-white">
|
||||||
|
<div className="max-w-5xl mx-auto px-6">
|
||||||
|
<h2 className="text-3xl lg:text-4xl font-extrabold text-slate-900 text-center mb-4">{text.howTitle}</h2>
|
||||||
|
<p className="text-slate-500 text-center max-w-2xl mx-auto mb-14">{text.howIntro}</p>
|
||||||
|
<ol className="grid grid-cols-1 md:grid-cols-3 gap-8">
|
||||||
|
{text.steps.map((step, index) => (
|
||||||
|
<li key={step.title} className="bg-slate-50 rounded-3xl border border-slate-100 p-8">
|
||||||
|
<div className="w-12 h-12 rounded-2xl bg-primary/10 flex items-center justify-center mb-5">
|
||||||
|
<span className="material-symbols-outlined text-primary">{step.icon}</span>
|
||||||
|
</div>
|
||||||
|
<p className="text-xs font-extrabold text-primary uppercase tracking-widest mb-2">
|
||||||
|
{text.stepLabel} {index + 1}
|
||||||
|
</p>
|
||||||
|
<h3 className="text-lg font-extrabold text-slate-900 mb-3">{step.title}</h3>
|
||||||
|
<p className="text-slate-600 text-sm leading-relaxed">{step.text}</p>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ol>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* Bénéfices */}
|
||||||
|
<section className="py-20 bg-slate-50 border-y border-slate-100">
|
||||||
|
<div className="max-w-5xl mx-auto px-6">
|
||||||
|
<h2 className="text-3xl lg:text-4xl font-extrabold text-slate-900 text-center mb-14">{text.benefitsTitle}</h2>
|
||||||
|
<div className="grid grid-cols-1 sm:grid-cols-2 gap-6">
|
||||||
|
{text.benefits.map((benefit) => (
|
||||||
|
<div key={benefit.title} className="bg-white rounded-3xl border border-slate-100 p-8">
|
||||||
|
<div className="w-12 h-12 rounded-2xl bg-primary/10 flex items-center justify-center mb-5">
|
||||||
|
<span className="material-symbols-outlined text-primary">{benefit.icon}</span>
|
||||||
|
</div>
|
||||||
|
<h3 className="text-lg font-extrabold text-slate-900 mb-3">{benefit.title}</h3>
|
||||||
|
<p className="text-slate-600 text-sm leading-relaxed">{benefit.text}</p>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* Garde-fous */}
|
||||||
|
<section className="py-20 bg-white">
|
||||||
|
<div className="max-w-3xl mx-auto px-6">
|
||||||
|
<h2 className="text-3xl lg:text-4xl font-extrabold text-slate-900 mb-4">{text.guardTitle}</h2>
|
||||||
|
<p className="text-slate-500 mb-10">{text.guardIntro}</p>
|
||||||
|
<ul className="space-y-5">
|
||||||
|
{text.guardrails.map((item) => (
|
||||||
|
<li key={item} className="flex items-start gap-4">
|
||||||
|
<span className="material-symbols-outlined text-primary shrink-0">check_circle</span>
|
||||||
|
<p className="text-slate-700 leading-relaxed">{item}</p>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* Prix */}
|
||||||
|
<section className="py-20 bg-slate-50 border-y border-slate-100">
|
||||||
|
<div className="max-w-3xl mx-auto px-6 text-center">
|
||||||
|
<h2 className="text-3xl lg:text-4xl font-extrabold text-slate-900 mb-6">{text.priceTitle}</h2>
|
||||||
|
<p className="text-slate-600 leading-relaxed mb-4">
|
||||||
|
{text.priceBefore}<strong>{text.priceStrong}</strong>{text.priceAfter}
|
||||||
|
</p>
|
||||||
|
<p className="text-slate-600 leading-relaxed mb-10">{text.priceEnterprise}</p>
|
||||||
|
<Link
|
||||||
|
href={`/${lang}/tarifs`}
|
||||||
|
className="inline-flex items-center gap-2 px-8 py-4 bg-white border-2 border-primary text-primary font-extrabold rounded-full hover:bg-primary hover:text-slate-900 transition-all"
|
||||||
|
>
|
||||||
|
{text.priceCta}
|
||||||
|
<span className="material-symbols-outlined">arrow_forward</span>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* FAQ */}
|
||||||
|
<section className="py-20 bg-white">
|
||||||
|
<div className="max-w-3xl mx-auto px-6">
|
||||||
|
<h2 className="text-3xl lg:text-4xl font-extrabold text-slate-900 text-center mb-12">{text.faqTitle}</h2>
|
||||||
|
<div className="space-y-4">
|
||||||
|
{text.faq.map((item) => (
|
||||||
|
<details key={item.question} className="group bg-slate-50 rounded-2xl border border-slate-100 p-6">
|
||||||
|
<summary className="flex items-center justify-between gap-4 cursor-pointer list-none">
|
||||||
|
<h3 className="font-extrabold text-slate-900">{item.question}</h3>
|
||||||
|
<span className="material-symbols-outlined text-slate-400 transition-transform group-open:rotate-180">expand_more</span>
|
||||||
|
</summary>
|
||||||
|
<p className="text-slate-600 leading-relaxed mt-4">{item.answer}</p>
|
||||||
|
</details>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* CTA */}
|
||||||
|
<section className="py-16 bg-slate-900 text-center">
|
||||||
|
<div className="max-w-2xl mx-auto px-6">
|
||||||
|
<h2 className="text-2xl lg:text-3xl font-extrabold text-white mb-4">{text.ctaTitle}</h2>
|
||||||
|
<Link
|
||||||
|
href={`/${lang}#contact`}
|
||||||
|
className="inline-flex items-center gap-2 mt-6 px-8 py-4 bg-primary text-slate-900 font-extrabold rounded-full shadow-xl shadow-primary/30 hover:brightness-110 transition-all"
|
||||||
|
>
|
||||||
|
{text.ctaButton}
|
||||||
|
<span className="material-symbols-outlined">arrow_forward</span>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
}
|
||||||
311
src/app/[lang]/borne-kiosk/page.tsx
Normal file
@ -0,0 +1,311 @@
|
|||||||
|
import type { Metadata } from 'next';
|
||||||
|
import { notFound } from 'next/navigation';
|
||||||
|
import { LOCALES, LOCALE_HTML_LANG, LOCALE_OG, DEFAULT_LOCALE, isLocale, type Locale } from '@/i18n';
|
||||||
|
import { MYINFOMATE_LINKEDIN, breadcrumbSchema, softwareOffers } from '@/data/structured-data';
|
||||||
|
import ContentPage, { type ContentPageText } from '@/components/ContentPage';
|
||||||
|
|
||||||
|
const SITE_URL = 'https://myinfomate.be';
|
||||||
|
const PATH = 'borne-kiosk';
|
||||||
|
|
||||||
|
const META: Record<Locale, { title: string; description: string }> = {
|
||||||
|
fr: {
|
||||||
|
title: 'Borne interactive pour musée et office de tourisme | MyInfoMate',
|
||||||
|
description: 'Une borne tactile qui accueille vos visiteurs : carte de la ville, agenda des événements, parcours. Même back-office que votre app mobile. Dès 39 €/mois.',
|
||||||
|
},
|
||||||
|
en: {
|
||||||
|
title: 'Interactive Kiosk for Museums & Tourism Offices | MyInfoMate',
|
||||||
|
description: 'A touch kiosk that welcomes your visitors: city map, events agenda, trails. Same back-office as your mobile app. From €39/month.',
|
||||||
|
},
|
||||||
|
nl: {
|
||||||
|
title: 'Interactieve kiosk voor musea & toerismekantoren | MyInfoMate',
|
||||||
|
description: 'Een touchkiosk die uw bezoekers ontvangt: stadsplan, evenementenagenda, parcours. Dezelfde back-office als uw mobiele app. Vanaf €39/maand.',
|
||||||
|
},
|
||||||
|
de: {
|
||||||
|
title: 'Interaktiver Kiosk für Museen & Tourismusbüros | MyInfoMate',
|
||||||
|
description: 'Ein Touch-Kiosk, der Ihre Besucher empfängt: Stadtplan, Veranstaltungskalender, Rundgänge. Dasselbe Back-Office wie Ihre App. Ab 39 €/Monat.',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const TEXT: Record<Locale, ContentPageText> = {
|
||||||
|
fr: {
|
||||||
|
back: "Retour à l'accueil",
|
||||||
|
badge: 'Mode borne',
|
||||||
|
h1Before: 'Une borne tactile qui répond ',
|
||||||
|
h1Highlight: 'aux questions du hall d\'accueil',
|
||||||
|
intro: "Le mode borne de MyInfoMate transforme une tablette en point d'information : carte du lieu ou de la ville, agenda tenu à jour, parcours de visite. Le contenu vient du même back-office que votre application mobile.",
|
||||||
|
ctaPrimary: 'Demander une démo',
|
||||||
|
ctaSecondary: 'Voir les tarifs',
|
||||||
|
pointsTitle: 'Ce qu\'une borne change à l\'accueil',
|
||||||
|
points: [
|
||||||
|
{
|
||||||
|
icon: 'support_agent',
|
||||||
|
title: 'Elle absorbe les questions répétitives',
|
||||||
|
text: "Horaires, plan, événements du week-end, itinéraire : la borne répond pendant que votre équipe s'occupe des demandes qui méritent une conversation.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'sync',
|
||||||
|
title: 'Un seul contenu, deux canaux',
|
||||||
|
text: "La borne et l'application mobile affichent les mêmes contenus, gérés au même endroit. Vous publiez une fois, tout suit — sans double saisie.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'accessibility_new',
|
||||||
|
title: 'Accessible à ceux qui n\'installent rien',
|
||||||
|
text: "Tous vos visiteurs n'ont pas envie de télécharger une application, ni un smartphone récent. La borne leur donne le même accès, sans compte ni installation.",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
caseTitle: 'Visit Namur, des bornes en service depuis 2024',
|
||||||
|
caseText: "L'office du tourisme de Namur a déployé des bornes tactiles XXL : carte de la ville avec ses points d'intérêt géolocalisés, agenda des événements mis à jour par l'équipe, planification d'itinéraires. Le projet a été attribué à l'issue d'un cahier des charges publié.",
|
||||||
|
caseLink: 'Lire le cas Visit Namur',
|
||||||
|
caseSlug: 'visit-namur',
|
||||||
|
faqTitle: 'Questions fréquentes sur le mode borne',
|
||||||
|
faq: [
|
||||||
|
{
|
||||||
|
question: 'Faut-il acheter du matériel spécifique ?',
|
||||||
|
answer: "L'application kiosk s'installe sur des tablettes Android standard, celles que vous avez déjà ou celles que vous choisissez. Pour un grand écran d'accueil comme à Visit Namur, parlons du matériel avant le déploiement : c'est le seul point qui demande un choix en amont.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Le contenu est-il le même que sur l\'application mobile ?',
|
||||||
|
answer: "Oui, c'est le principe : un seul back-office alimente la borne, l'application mobile et l'application web. Une modification est visible partout dès la publication, sans double saisie ni intervention technique.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Que se passe-t-il si la connexion tombe ?',
|
||||||
|
answer: "Le mode hors ligne, inclus dès le plan Pro, permet de télécharger les contenus sur l'appareil : la borne continue alors d'afficher les contenus déjà téléchargés. Sans ce mode, la borne a besoin d'une connexion.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'La borne est-elle comprise dans le prix ?',
|
||||||
|
answer: "Le mode borne est inclus dès le plan Essentiel, à 39 €/mois hors TVA, au même titre que l'application web. Le matériel — tablette ou écran — reste à votre charge et n'est pas facturé par MyInfoMate.",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
ctaTitle: 'Envie de voir une borne tourner avec vos contenus ?',
|
||||||
|
ctaButton: 'Demander une démo gratuite',
|
||||||
|
},
|
||||||
|
en: {
|
||||||
|
back: 'Back to home',
|
||||||
|
badge: 'Kiosk mode',
|
||||||
|
h1Before: 'A touch kiosk that answers ',
|
||||||
|
h1Highlight: 'the questions asked at the desk',
|
||||||
|
intro: 'MyInfoMate kiosk mode turns a tablet into an information point: a map of your venue or city, a live events agenda, visitor trails. The content comes from the same back-office as your mobile app.',
|
||||||
|
ctaPrimary: 'Request a demo',
|
||||||
|
ctaSecondary: 'See pricing',
|
||||||
|
pointsTitle: 'What a kiosk changes at the front desk',
|
||||||
|
points: [
|
||||||
|
{
|
||||||
|
icon: 'support_agent',
|
||||||
|
title: 'It absorbs the repetitive questions',
|
||||||
|
text: 'Opening hours, the map, this weekend\'s events, directions: the kiosk answers while your team handles the requests that deserve a conversation.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'sync',
|
||||||
|
title: 'One content set, two channels',
|
||||||
|
text: 'The kiosk and the mobile app show the same content, managed in the same place. You publish once and everything follows — no double entry.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'accessibility_new',
|
||||||
|
title: 'Open to those who install nothing',
|
||||||
|
text: 'Not every visitor wants to download an app, or owns a recent smartphone. The kiosk gives them the same access, with no account and no install.',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
caseTitle: 'Visit Namur, kiosks in service since 2024',
|
||||||
|
caseText: 'The Namur tourism office deployed XXL touch kiosks: a city map with geolocated points of interest, an events agenda kept up to date by the team, and itinerary planning. The project was awarded following a published call for tenders.',
|
||||||
|
caseLink: 'Read the Visit Namur case',
|
||||||
|
caseSlug: 'visit-namur',
|
||||||
|
faqTitle: 'Kiosk mode FAQ',
|
||||||
|
faq: [
|
||||||
|
{
|
||||||
|
question: 'Do we need specific hardware?',
|
||||||
|
answer: 'The kiosk app installs on standard Android tablets — the ones you already have, or the ones you choose. For a large welcome screen like at Visit Namur, let\'s discuss hardware before deployment: it is the one point that needs an upfront decision.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Is the content the same as on the mobile app?',
|
||||||
|
answer: 'Yes, that is the whole point: a single back-office feeds the kiosk, the mobile app and the web app. A change is visible everywhere as soon as it is published, with no double entry and no technical work.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'What happens if the connection drops?',
|
||||||
|
answer: 'Offline mode, included from the Pro plan, downloads the content onto the device: the kiosk keeps showing what has already been downloaded. Without it, the kiosk needs a connection.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Is the kiosk included in the price?',
|
||||||
|
answer: 'Kiosk mode is included from the Essential plan, at €39/month excluding VAT, alongside the web app. The hardware — tablet or screen — is yours to buy and is not billed by MyInfoMate.',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
ctaTitle: 'Want to see a kiosk running on your own content?',
|
||||||
|
ctaButton: 'Request a free demo',
|
||||||
|
},
|
||||||
|
nl: {
|
||||||
|
back: 'Terug naar home',
|
||||||
|
badge: 'Kioskmodus',
|
||||||
|
h1Before: 'Een touchkiosk die antwoordt ',
|
||||||
|
h1Highlight: 'op de vragen aan de balie',
|
||||||
|
intro: 'De kioskmodus van MyInfoMate maakt van een tablet een informatiepunt: plattegrond van uw locatie of stad, actuele evenementenagenda, bezoekersparcours. De inhoud komt uit dezelfde back-office als uw mobiele app.',
|
||||||
|
ctaPrimary: 'Demo aanvragen',
|
||||||
|
ctaSecondary: 'Tarieven bekijken',
|
||||||
|
pointsTitle: 'Wat een kiosk verandert aan het onthaal',
|
||||||
|
points: [
|
||||||
|
{
|
||||||
|
icon: 'support_agent',
|
||||||
|
title: 'Hij vangt de herhaalde vragen op',
|
||||||
|
text: 'Openingsuren, plattegrond, evenementen dit weekend, de route: de kiosk antwoordt terwijl uw team zich bezighoudt met vragen die een gesprek verdienen.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'sync',
|
||||||
|
title: 'Eén inhoud, twee kanalen',
|
||||||
|
text: 'De kiosk en de mobiele app tonen dezelfde inhoud, beheerd op één plek. U publiceert één keer en alles volgt — zonder dubbele invoer.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'accessibility_new',
|
||||||
|
title: 'Ook voor wie niets installeert',
|
||||||
|
text: 'Niet elke bezoeker wil een app downloaden of heeft een recente smartphone. De kiosk geeft hen dezelfde toegang, zonder account en zonder installatie.',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
caseTitle: 'Visit Namen, kiosken in dienst sinds 2024',
|
||||||
|
caseText: 'Het toerismekantoor van Namen plaatste XXL-touchkiosken: een stadsplan met gelokaliseerde bezienswaardigheden, een evenementenagenda die het team zelf bijhoudt, en routeplanning. De opdracht werd gegund na een gepubliceerd bestek.',
|
||||||
|
caseLink: 'Lees de case Visit Namen',
|
||||||
|
caseSlug: 'visit-namur',
|
||||||
|
faqTitle: 'Veelgestelde vragen over de kioskmodus',
|
||||||
|
faq: [
|
||||||
|
{
|
||||||
|
question: 'Is er specifieke hardware nodig?',
|
||||||
|
answer: 'De kiosk-app installeert op gewone Android-tablets — die u al hebt of die u kiest. Voor een groot onthaalscherm zoals bij Visit Namen bespreken we de hardware vóór de uitrol: dat is het enige punt dat een keuze vooraf vraagt.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Is de inhoud dezelfde als in de mobiele app?',
|
||||||
|
answer: 'Ja, dat is net de bedoeling: één back-office voedt de kiosk, de mobiele app en de web-app. Een wijziging is overal zichtbaar zodra ze gepubliceerd is, zonder dubbele invoer en zonder technisch werk.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Wat als de verbinding wegvalt?',
|
||||||
|
answer: 'De offline modus, inbegrepen vanaf het Pro-abonnement, downloadt de inhoud op het toestel: de kiosk blijft tonen wat al gedownload is. Zonder die modus heeft de kiosk een verbinding nodig.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Zit de kiosk in de prijs?',
|
||||||
|
answer: 'De kioskmodus zit vanaf het Essentieel-abonnement in de prijs, aan €39/maand excl. btw, net als de web-app. De hardware — tablet of scherm — koopt u zelf en wordt niet door MyInfoMate gefactureerd.',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
ctaTitle: 'Wilt u een kiosk zien draaien met uw eigen inhoud?',
|
||||||
|
ctaButton: 'Gratis demo aanvragen',
|
||||||
|
},
|
||||||
|
de: {
|
||||||
|
back: 'Zurück zur Startseite',
|
||||||
|
badge: 'Kiosk-Modus',
|
||||||
|
h1Before: 'Ein Touch-Kiosk, der beantwortet, ',
|
||||||
|
h1Highlight: 'was am Empfang gefragt wird',
|
||||||
|
intro: 'Der Kiosk-Modus von MyInfoMate macht aus einem Tablet einen Informationspunkt: Plan Ihres Ortes oder Ihrer Stadt, aktueller Veranstaltungskalender, Besucherrundgänge. Die Inhalte stammen aus demselben Back-Office wie Ihre Mobile App.',
|
||||||
|
ctaPrimary: 'Demo anfragen',
|
||||||
|
ctaSecondary: 'Preise ansehen',
|
||||||
|
pointsTitle: 'Was ein Kiosk am Empfang verändert',
|
||||||
|
points: [
|
||||||
|
{
|
||||||
|
icon: 'support_agent',
|
||||||
|
title: 'Er fängt die wiederkehrenden Fragen ab',
|
||||||
|
text: 'Öffnungszeiten, Plan, Veranstaltungen am Wochenende, Wegbeschreibung: Der Kiosk antwortet, während Ihr Team sich um die Anliegen kümmert, die ein Gespräch verdienen.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'sync',
|
||||||
|
title: 'Ein Inhalt, zwei Kanäle',
|
||||||
|
text: 'Kiosk und Mobile App zeigen dieselben Inhalte, an einer Stelle gepflegt. Sie veröffentlichen einmal, alles folgt — ohne Doppelerfassung.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'accessibility_new',
|
||||||
|
title: 'Auch für alle, die nichts installieren',
|
||||||
|
text: 'Nicht jeder Besucher will eine App laden oder hat ein aktuelles Smartphone. Der Kiosk gibt denselben Zugang — ohne Konto, ohne Installation.',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
caseTitle: 'Visit Namur, Kioske im Einsatz seit 2024',
|
||||||
|
caseText: 'Das Tourismusbüro Namur hat XXL-Touch-Kioske aufgestellt: Stadtplan mit verorteten Sehenswürdigkeiten, ein vom Team gepflegter Veranstaltungskalender und Routenplanung. Der Auftrag wurde nach einer veröffentlichten Ausschreibung vergeben.',
|
||||||
|
caseLink: 'Den Fall Visit Namur lesen',
|
||||||
|
caseSlug: 'visit-namur',
|
||||||
|
faqTitle: 'Häufige Fragen zum Kiosk-Modus',
|
||||||
|
faq: [
|
||||||
|
{
|
||||||
|
question: 'Braucht es spezielle Hardware?',
|
||||||
|
answer: 'Die Kiosk-App läuft auf gängigen Android-Tablets — auf denen, die Sie schon haben, oder auf denen Ihrer Wahl. Für einen großen Empfangsbildschirm wie bei Visit Namur sprechen wir vor dem Einsatz über die Hardware: Das ist der einzige Punkt, der eine Entscheidung im Voraus verlangt.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Sind die Inhalte dieselben wie in der Mobile App?',
|
||||||
|
answer: 'Ja, genau darum geht es: Ein einziges Back-Office versorgt Kiosk, Mobile App und Web-App. Eine Änderung ist überall sichtbar, sobald sie veröffentlicht ist — ohne Doppelerfassung und ohne technischen Aufwand.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Was passiert, wenn die Verbindung ausfällt?',
|
||||||
|
answer: 'Der Offline-Modus, ab dem Pro-Plan enthalten, lädt die Inhalte auf das Gerät: Der Kiosk zeigt weiterhin, was bereits geladen ist. Ohne ihn braucht der Kiosk eine Verbindung.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Ist der Kiosk im Preis enthalten?',
|
||||||
|
answer: 'Der Kiosk-Modus ist ab dem Essential-Plan enthalten, für 39 €/Monat zzgl. MwSt., ebenso wie die Web-App. Die Hardware — Tablet oder Bildschirm — beschaffen Sie selbst; sie wird von MyInfoMate nicht berechnet.',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
ctaTitle: 'Möchten Sie einen Kiosk mit Ihren Inhalten sehen?',
|
||||||
|
ctaButton: 'Kostenlose Demo anfordern',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export function generateStaticParams() {
|
||||||
|
return LOCALES.map((lang) => ({ lang }));
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function generateMetadata({
|
||||||
|
params,
|
||||||
|
}: {
|
||||||
|
params: Promise<{ lang: string }>;
|
||||||
|
}): Promise<Metadata> {
|
||||||
|
const { lang } = await params;
|
||||||
|
if (!isLocale(lang)) return {};
|
||||||
|
const m = META[lang];
|
||||||
|
const languages = Object.fromEntries(LOCALES.map((l) => [LOCALE_HTML_LANG[l], `/${l}/${PATH}`]));
|
||||||
|
return {
|
||||||
|
title: m.title,
|
||||||
|
description: m.description,
|
||||||
|
openGraph: {
|
||||||
|
title: m.title,
|
||||||
|
description: m.description,
|
||||||
|
url: `${SITE_URL}/${lang}/${PATH}`,
|
||||||
|
siteName: 'MyInfoMate',
|
||||||
|
locale: LOCALE_OG[lang],
|
||||||
|
type: 'website',
|
||||||
|
},
|
||||||
|
alternates: {
|
||||||
|
canonical: `/${lang}/${PATH}`,
|
||||||
|
languages: { ...languages, 'x-default': `/${DEFAULT_LOCALE}/${PATH}` },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default async function BorneKioskPage({ params }: { params: Promise<{ lang: string }> }) {
|
||||||
|
const { lang } = await params;
|
||||||
|
if (!isLocale(lang)) notFound();
|
||||||
|
const text = TEXT[lang];
|
||||||
|
|
||||||
|
const faqSchema = {
|
||||||
|
'@context': 'https://schema.org',
|
||||||
|
'@type': 'FAQPage',
|
||||||
|
mainEntity: text.faq.map((item) => ({
|
||||||
|
'@type': 'Question',
|
||||||
|
name: item.question,
|
||||||
|
acceptedAnswer: { '@type': 'Answer', text: item.answer },
|
||||||
|
})),
|
||||||
|
};
|
||||||
|
|
||||||
|
const softwareSchema = {
|
||||||
|
'@context': 'https://schema.org',
|
||||||
|
'@type': 'SoftwareApplication',
|
||||||
|
name: 'MyInfoMate',
|
||||||
|
applicationCategory: 'BusinessApplication',
|
||||||
|
operatingSystem: 'Android, Web',
|
||||||
|
offers: softwareOffers,
|
||||||
|
sameAs: [MYINFOMATE_LINKEDIN],
|
||||||
|
description: META[lang].description,
|
||||||
|
url: `${SITE_URL}/${lang}/${PATH}`,
|
||||||
|
};
|
||||||
|
|
||||||
|
const breadcrumb = breadcrumbSchema([
|
||||||
|
{ name: 'MyInfoMate', path: `/${lang}` },
|
||||||
|
{ name: text.badge, path: `/${lang}/${PATH}` },
|
||||||
|
]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(breadcrumb) }} />
|
||||||
|
<script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(faqSchema) }} />
|
||||||
|
<script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(softwareSchema) }} />
|
||||||
|
<ContentPage lang={lang} text={text} />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -2,6 +2,8 @@ import type { Metadata } from 'next';
|
|||||||
import { notFound } from 'next/navigation';
|
import { notFound } from 'next/navigation';
|
||||||
import { LOCALES, LOCALE_HTML_LANG, LOCALE_OG, DEFAULT_LOCALE, isLocale } from '@/i18n';
|
import { LOCALES, LOCALE_HTML_LANG, LOCALE_OG, DEFAULT_LOCALE, isLocale } from '@/i18n';
|
||||||
import { getCasClientData, getAllCasClientSlugs } from '@/data/cas-clients';
|
import { getCasClientData, getAllCasClientSlugs } from '@/data/cas-clients';
|
||||||
|
import { breadcrumbSchema } from '@/data/structured-data';
|
||||||
|
import translations from '@/data/translations';
|
||||||
|
|
||||||
const SITE_URL = 'https://myinfomate.be';
|
const SITE_URL = 'https://myinfomate.be';
|
||||||
|
|
||||||
@ -64,8 +66,15 @@ export default async function CasClientPage({
|
|||||||
url: `${SITE_URL}/${lang}/cas-clients/${slug}`,
|
url: `${SITE_URL}/${lang}/cas-clients/${slug}`,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const breadcrumb = breadcrumbSchema([
|
||||||
|
{ name: 'MyInfoMate', path: `/${lang}` },
|
||||||
|
{ name: translations[lang].casClients.sectionLabel, path: `/${lang}/cas-clients` },
|
||||||
|
{ name: data.client, path: `/${lang}/cas-clients/${slug}` },
|
||||||
|
]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
<script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(breadcrumb) }} />
|
||||||
<script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(caseStudySchema) }} />
|
<script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(caseStudySchema) }} />
|
||||||
|
|
||||||
<main className="bg-slate-50 text-slate-900 min-h-screen font-display">
|
<main className="bg-slate-50 text-slate-900 min-h-screen font-display">
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import type { Metadata } from 'next';
|
|||||||
import { notFound } from 'next/navigation';
|
import { notFound } from 'next/navigation';
|
||||||
import { LOCALES, LOCALE_HTML_LANG, LOCALE_OG, DEFAULT_LOCALE, isLocale } from '@/i18n';
|
import { LOCALES, LOCALE_HTML_LANG, LOCALE_OG, DEFAULT_LOCALE, isLocale } from '@/i18n';
|
||||||
import { getAllCasClients } from '@/data/cas-clients';
|
import { getAllCasClients } from '@/data/cas-clients';
|
||||||
|
import { breadcrumbSchema } from '@/data/structured-data';
|
||||||
|
|
||||||
const SITE_URL = 'https://myinfomate.be';
|
const SITE_URL = 'https://myinfomate.be';
|
||||||
|
|
||||||
@ -105,8 +106,15 @@ export default async function CasClientsListPage({
|
|||||||
const back = BACK_BY_LOCALE[lang];
|
const back = BACK_BY_LOCALE[lang];
|
||||||
const sectorLabels = SECTOR_LABEL_BY_LOCALE[lang];
|
const sectorLabels = SECTOR_LABEL_BY_LOCALE[lang];
|
||||||
|
|
||||||
|
const breadcrumb = breadcrumbSchema([
|
||||||
|
{ name: 'MyInfoMate', path: `/${lang}` },
|
||||||
|
{ name: h.badge, path: `/${lang}/cas-clients` },
|
||||||
|
]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<main className="bg-slate-50 text-slate-900 min-h-screen font-display">
|
<main className="bg-slate-50 text-slate-900 min-h-screen font-display">
|
||||||
|
<script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(breadcrumb) }} />
|
||||||
|
|
||||||
{/* Nav */}
|
{/* Nav */}
|
||||||
<header className="fixed top-0 left-0 right-0 z-50 bg-white/80 backdrop-blur-md border-b border-slate-200">
|
<header className="fixed top-0 left-0 right-0 z-50 bg-white/80 backdrop-blur-md border-b border-slate-200">
|
||||||
<div className="max-w-7xl mx-auto px-6 h-16 flex items-center gap-4">
|
<div className="max-w-7xl mx-auto px-6 h-16 flex items-center gap-4">
|
||||||
|
|||||||
207
src/app/[lang]/comparatif/[slug]/page.tsx
Normal file
@ -0,0 +1,207 @@
|
|||||||
|
import type { Metadata } from 'next';
|
||||||
|
import Link from 'next/link';
|
||||||
|
import { notFound } from 'next/navigation';
|
||||||
|
import { isLocale } from '@/i18n';
|
||||||
|
import { getComparison, getAllComparisonSlugs } from '@/data/comparisons';
|
||||||
|
import { breadcrumbSchema } from '@/data/structured-data';
|
||||||
|
|
||||||
|
const SITE_URL = 'https://myinfomate.be';
|
||||||
|
const PATH = 'comparatif';
|
||||||
|
|
||||||
|
// Comparatifs en français uniquement.
|
||||||
|
export function generateStaticParams() {
|
||||||
|
return getAllComparisonSlugs().map((slug) => ({ lang: 'fr', slug }));
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function generateMetadata({
|
||||||
|
params,
|
||||||
|
}: {
|
||||||
|
params: Promise<{ lang: string; slug: string }>;
|
||||||
|
}): Promise<Metadata> {
|
||||||
|
const { lang, slug } = await params;
|
||||||
|
const comparison = getComparison(slug);
|
||||||
|
if (lang !== 'fr' || !comparison) return {};
|
||||||
|
return {
|
||||||
|
title: `${comparison.title} | MyInfoMate`,
|
||||||
|
description: comparison.description,
|
||||||
|
openGraph: {
|
||||||
|
title: comparison.title,
|
||||||
|
description: comparison.description,
|
||||||
|
url: `${SITE_URL}/fr/${PATH}/${slug}`,
|
||||||
|
siteName: 'MyInfoMate',
|
||||||
|
locale: 'fr_BE',
|
||||||
|
type: 'article',
|
||||||
|
},
|
||||||
|
alternates: { canonical: `/fr/${PATH}/${slug}` },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default async function ComparisonPage({
|
||||||
|
params,
|
||||||
|
}: {
|
||||||
|
params: Promise<{ lang: string; slug: string }>;
|
||||||
|
}) {
|
||||||
|
const { lang, slug } = await params;
|
||||||
|
if (!isLocale(lang) || lang !== 'fr') notFound();
|
||||||
|
const comparison = getComparison(slug);
|
||||||
|
if (!comparison) notFound();
|
||||||
|
|
||||||
|
const faqSchema = {
|
||||||
|
'@context': 'https://schema.org',
|
||||||
|
'@type': 'FAQPage',
|
||||||
|
mainEntity: comparison.faq.map((item) => ({
|
||||||
|
'@type': 'Question',
|
||||||
|
name: item.question,
|
||||||
|
acceptedAnswer: { '@type': 'Answer', text: item.answer },
|
||||||
|
})),
|
||||||
|
};
|
||||||
|
|
||||||
|
const breadcrumb = breadcrumbSchema([
|
||||||
|
{ name: 'MyInfoMate', path: '/fr' },
|
||||||
|
{ name: `MyInfoMate ou ${comparison.competitor}`, path: `/fr/${PATH}/${slug}` },
|
||||||
|
]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<main className="bg-slate-50 text-slate-900 min-h-screen font-display">
|
||||||
|
<script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(breadcrumb) }} />
|
||||||
|
<script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(faqSchema) }} />
|
||||||
|
|
||||||
|
<header className="fixed top-0 left-0 right-0 z-50 bg-white/80 backdrop-blur-md border-b border-slate-200">
|
||||||
|
<div className="max-w-7xl mx-auto px-6 h-16 flex items-center gap-4">
|
||||||
|
<Link href="/fr" className="flex items-center gap-2 text-sm font-bold text-slate-600 hover:text-primary transition-colors">
|
||||||
|
<span className="material-symbols-outlined text-base">arrow_back</span>
|
||||||
|
Retour à l'accueil
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div className="pt-16">
|
||||||
|
<section className="py-20 bg-white border-b border-slate-100">
|
||||||
|
<div className="max-w-3xl mx-auto px-6">
|
||||||
|
<div className="inline-flex items-center gap-2 px-4 py-2 rounded-full bg-primary/10 border border-primary/20 text-slate-700 text-xs font-bold uppercase tracking-wider mb-6">
|
||||||
|
<span className="w-2 h-2 rounded-full bg-primary"></span>
|
||||||
|
Comparatif
|
||||||
|
</div>
|
||||||
|
<h1 className="text-3xl lg:text-5xl font-extrabold text-slate-900 leading-tight mb-6">{comparison.title}</h1>
|
||||||
|
<p className="text-lg text-slate-600 leading-relaxed">{comparison.intro}</p>
|
||||||
|
<p className="text-xs text-slate-400 mt-6">
|
||||||
|
Tarifs de {comparison.competitor} relevés sur ses pages publiques le {comparison.checkedOn}. Ils peuvent
|
||||||
|
avoir changé depuis : les sources sont en bas de page.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section className="py-16">
|
||||||
|
<div className="max-w-4xl mx-auto px-6">
|
||||||
|
<h2 className="text-2xl lg:text-3xl font-extrabold text-slate-900 mb-4">Les prix, côte à côte</h2>
|
||||||
|
<p className="text-slate-600 mb-8">{comparison.priceIntro}</p>
|
||||||
|
<div className="overflow-x-auto bg-white rounded-3xl border border-slate-100">
|
||||||
|
<table className="w-full text-sm text-left border-collapse min-w-[640px]">
|
||||||
|
<thead>
|
||||||
|
<tr className="border-b border-slate-200 text-slate-500">
|
||||||
|
<th className="py-4 px-6 font-semibold"></th>
|
||||||
|
<th className="py-4 px-6 font-extrabold text-slate-900">MyInfoMate</th>
|
||||||
|
<th className="py-4 px-6 font-extrabold text-slate-900">{comparison.competitor}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody className="text-slate-600">
|
||||||
|
{comparison.rows.map((row) => (
|
||||||
|
<tr key={row.label} className="border-b border-slate-100 last:border-0 align-top">
|
||||||
|
<th scope="row" className="py-4 px-6 font-semibold text-slate-800 text-left">{row.label}</th>
|
||||||
|
<td className="py-4 px-6">{row.myinfomate}</td>
|
||||||
|
<td className="py-4 px-6">{row.competitor}</td>
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section className="py-16 bg-white border-y border-slate-100">
|
||||||
|
<div className="max-w-3xl mx-auto px-6 grid grid-cols-1 md:grid-cols-2 gap-10">
|
||||||
|
<div>
|
||||||
|
<h2 className="text-xl font-extrabold text-slate-900 mb-4">{comparison.fairTitle}</h2>
|
||||||
|
<ul className="space-y-4">
|
||||||
|
{comparison.fair.map((item) => (
|
||||||
|
<li key={item} className="flex items-start gap-3 text-slate-600 text-sm leading-relaxed">
|
||||||
|
<span className="material-symbols-outlined text-slate-400 shrink-0 text-base">check</span>
|
||||||
|
{item}
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h2 className="text-xl font-extrabold text-slate-900 mb-4">{comparison.differenceTitle}</h2>
|
||||||
|
<ul className="space-y-4">
|
||||||
|
{comparison.differences.map((item) => (
|
||||||
|
<li key={item} className="flex items-start gap-3 text-slate-600 text-sm leading-relaxed">
|
||||||
|
<span className="material-symbols-outlined text-primary shrink-0 text-base">check_circle</span>
|
||||||
|
{item}
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section className="py-16">
|
||||||
|
<div className="max-w-3xl mx-auto px-6">
|
||||||
|
<h2 className="text-2xl lg:text-3xl font-extrabold text-slate-900 mb-6">{comparison.verdictTitle}</h2>
|
||||||
|
{comparison.verdict.map((paragraph) => (
|
||||||
|
<p key={paragraph.slice(0, 40)} className="text-slate-600 leading-relaxed mb-4">{paragraph}</p>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section className="py-16 bg-white border-y border-slate-100">
|
||||||
|
<div className="max-w-3xl mx-auto px-6">
|
||||||
|
<h2 className="text-2xl lg:text-3xl font-extrabold text-slate-900 text-center mb-10">Questions fréquentes</h2>
|
||||||
|
<div className="space-y-4">
|
||||||
|
{comparison.faq.map((item) => (
|
||||||
|
<details key={item.question} className="group bg-slate-50 rounded-2xl border border-slate-100 p-6">
|
||||||
|
<summary className="flex items-center justify-between gap-4 cursor-pointer list-none">
|
||||||
|
<h3 className="font-extrabold text-slate-900">{item.question}</h3>
|
||||||
|
<span className="material-symbols-outlined text-slate-400 transition-transform group-open:rotate-180">expand_more</span>
|
||||||
|
</summary>
|
||||||
|
<p className="text-slate-600 leading-relaxed mt-4">{item.answer}</p>
|
||||||
|
</details>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section className="py-12">
|
||||||
|
<div className="max-w-3xl mx-auto px-6">
|
||||||
|
<h2 className="text-sm font-extrabold text-slate-400 uppercase tracking-widest mb-4">Sources</h2>
|
||||||
|
<ul className="space-y-2">
|
||||||
|
{comparison.sources.map((source) => (
|
||||||
|
<li key={source.url} className="text-sm text-slate-500">
|
||||||
|
<a href={source.url} target="_blank" rel="noopener noreferrer" className="text-cyan-600 hover:underline">
|
||||||
|
{source.label}
|
||||||
|
</a>
|
||||||
|
<span className="text-slate-400"> — consulté le {comparison.checkedOn}</span>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section className="py-16 bg-slate-900 text-center">
|
||||||
|
<div className="max-w-2xl mx-auto px-6">
|
||||||
|
<h2 className="text-2xl lg:text-3xl font-extrabold text-white mb-4">
|
||||||
|
Comparez sur vos propres contenus
|
||||||
|
</h2>
|
||||||
|
<Link
|
||||||
|
href="/fr#contact"
|
||||||
|
className="inline-flex items-center gap-2 mt-6 px-8 py-4 bg-primary text-slate-900 font-extrabold rounded-full shadow-xl shadow-primary/30 hover:brightness-110 transition-all"
|
||||||
|
>
|
||||||
|
Demander une démo gratuite
|
||||||
|
<span className="material-symbols-outlined">arrow_forward</span>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
}
|
||||||
385
src/app/[lang]/conditions-generales/page.tsx
Normal file
@ -0,0 +1,385 @@
|
|||||||
|
import type { Metadata } from "next";
|
||||||
|
import Link from "next/link";
|
||||||
|
import { notFound } from "next/navigation";
|
||||||
|
import { LOCALES, LOCALE_HTML_LANG, DEFAULT_LOCALE, isLocale, type Locale } from "@/i18n";
|
||||||
|
|
||||||
|
const PATH = "conditions-generales";
|
||||||
|
|
||||||
|
const META: Record<Locale, { title: string; description: string }> = {
|
||||||
|
fr: { title: "Conditions générales | MyInfoMate", description: "Conditions générales d'utilisation de la solution MyInfoMate, éditée par Unov (Namur, Belgique)." },
|
||||||
|
en: { title: "Terms and conditions | MyInfoMate", description: "Terms and conditions of the MyInfoMate solution, published by Unov (Namur, Belgium). French version only." },
|
||||||
|
nl: { title: "Algemene voorwaarden | MyInfoMate", description: "Algemene voorwaarden van de MyInfoMate-oplossing, uitgegeven door Unov (Namen, België). Enkel in het Frans." },
|
||||||
|
de: { title: "Allgemeine Geschäftsbedingungen | MyInfoMate", description: "AGB der MyInfoMate-Lösung, herausgegeben von Unov (Namur, Belgien). Nur auf Französisch verfügbar." },
|
||||||
|
};
|
||||||
|
|
||||||
|
const BACK: Record<Locale, string> = {
|
||||||
|
fr: "← Retour",
|
||||||
|
en: "← Back",
|
||||||
|
nl: "← Terug",
|
||||||
|
de: "← Zurück",
|
||||||
|
};
|
||||||
|
|
||||||
|
// Le contrat n'existe qu'en français : c'est la version qui fait foi.
|
||||||
|
const NOTICE: Record<Locale, string | null> = {
|
||||||
|
fr: null,
|
||||||
|
en: "These terms are available in French only. The French version is the binding one. If you need a translation before signing, write to contact@unov.be.",
|
||||||
|
nl: "Deze voorwaarden bestaan enkel in het Frans. De Franse versie is de bindende versie. Hebt u vóór ondertekening een vertaling nodig, schrijf dan naar contact@unov.be.",
|
||||||
|
de: "Diese Bedingungen liegen nur auf Französisch vor. Verbindlich ist die französische Fassung. Benötigen Sie vor der Unterzeichnung eine Übersetzung, schreiben Sie an contact@unov.be.",
|
||||||
|
};
|
||||||
|
|
||||||
|
export function generateStaticParams() {
|
||||||
|
return LOCALES.map((lang) => ({ lang }));
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function generateMetadata({ params }: { params: Promise<{ lang: string }> }): Promise<Metadata> {
|
||||||
|
const { lang } = await params;
|
||||||
|
if (!isLocale(lang)) return {};
|
||||||
|
const languages = Object.fromEntries(LOCALES.map((l) => [LOCALE_HTML_LANG[l], `/${l}/${PATH}`]));
|
||||||
|
return {
|
||||||
|
...META[lang],
|
||||||
|
alternates: {
|
||||||
|
canonical: `/${lang}/${PATH}`,
|
||||||
|
languages: { ...languages, "x-default": `/${DEFAULT_LOCALE}/${PATH}` },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Source : DOCS/cgu-myinfomate.md — toute modification doit y être répercutée.
|
||||||
|
export default async function ConditionsGenerales({ params }: { params: Promise<{ lang: string }> }) {
|
||||||
|
const { lang } = await params;
|
||||||
|
if (!isLocale(lang)) notFound();
|
||||||
|
const notice = NOTICE[lang];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<main className="min-h-screen bg-white">
|
||||||
|
<div className="max-w-3xl mx-auto px-6 py-16">
|
||||||
|
<Link href={`/${lang}`} className="text-sm text-slate-400 hover:text-slate-600 mb-8 inline-block">
|
||||||
|
{BACK[lang]}
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
<h1 className="text-3xl font-bold text-slate-900 mb-2">Conditions générales d'utilisation</h1>
|
||||||
|
<p className="text-sm text-slate-400 mb-6">Unov — Version 1.0 — Avril 2026</p>
|
||||||
|
|
||||||
|
{notice && (
|
||||||
|
<p className="text-sm text-slate-600 bg-slate-50 border border-slate-200 rounded-2xl px-5 py-4 mb-10">
|
||||||
|
{notice}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Le contrat reste en français, quelle que soit la langue de la page. */}
|
||||||
|
<div lang="fr">
|
||||||
|
|
||||||
|
<section className="mb-8">
|
||||||
|
<h2 className="text-lg font-semibold text-slate-800 mb-3">1. Parties et objet</h2>
|
||||||
|
<p className="text-slate-600 text-sm leading-relaxed mb-3">
|
||||||
|
Les présentes conditions générales d'utilisation (ci-après « CGU ») régissent la relation contractuelle
|
||||||
|
entre <strong>Unov</strong>, ci-après « le Prestataire », fournisseur de la solution MyInfoMate, et
|
||||||
|
<strong> le Client</strong>, toute personne morale ou physique souscrivant à un abonnement MyInfoMate.
|
||||||
|
</p>
|
||||||
|
<p className="text-slate-600 text-sm leading-relaxed">
|
||||||
|
MyInfoMate est un service SaaS comprenant une application mobile visiteurs (iOS et Android), une application
|
||||||
|
kiosk tablette, un back-office de gestion de contenu, un assistant IA conversationnel et un tableau de bord
|
||||||
|
de statistiques de visite — ces deux derniers selon le plan souscrit.
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section className="mb-8">
|
||||||
|
<h2 className="text-lg font-semibold text-slate-800 mb-3">2. Accès au service</h2>
|
||||||
|
<p className="text-slate-600 text-sm leading-relaxed mb-3">
|
||||||
|
<strong>2.1 Création du compte.</strong> L'accès à MyInfoMate est conditionné à la souscription d'un
|
||||||
|
abonnement. Le Prestataire crée l'instance du Client et lui fournit les accès au back-office dans un
|
||||||
|
délai convenu lors de la commande.
|
||||||
|
</p>
|
||||||
|
<p className="text-slate-600 text-sm leading-relaxed mb-3">
|
||||||
|
<strong>2.2 Identifiants.</strong> Le Client est responsable de la confidentialité de ses identifiants
|
||||||
|
d'accès. Toute utilisation du service avec ses identifiants est réputée effectuée par le Client.
|
||||||
|
</p>
|
||||||
|
<p className="text-slate-600 text-sm leading-relaxed">
|
||||||
|
<strong>2.3 Conditions d'utilisation.</strong> Le Client s'engage à utiliser MyInfoMate dans le
|
||||||
|
cadre légal applicable et uniquement pour les finalités décrites lors de la souscription.
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section className="mb-8">
|
||||||
|
<h2 className="text-lg font-semibold text-slate-800 mb-3">3. Applications mobiles et stores</h2>
|
||||||
|
<p className="text-slate-600 text-sm leading-relaxed mb-3">
|
||||||
|
<strong>3.1 Publication sous compte Unov.</strong> Les applications MyInfoMate (iOS et Android) sont publiées
|
||||||
|
sur l'App Store d'Apple et le Google Play Store sous le compte développeur d'Unov. Le Client
|
||||||
|
n'est propriétaire ni du compte développeur, ni de la fiche application dans les stores.
|
||||||
|
</p>
|
||||||
|
<p className="text-slate-600 text-sm leading-relaxed mb-3">
|
||||||
|
<strong>3.2 White label.</strong> L'application est personnalisée aux couleurs et à l'identité
|
||||||
|
visuelle du Client (logo, nom, palette de couleurs). Cette personnalisation ne confère pas au Client de
|
||||||
|
droits de propriété sur l'application elle-même.
|
||||||
|
</p>
|
||||||
|
<p className="text-slate-600 text-sm leading-relaxed mb-3">
|
||||||
|
<strong>3.3 Mises à jour.</strong> Le Prestataire assure les mises à jour techniques de l'application.
|
||||||
|
Le Client est responsable de la mise à jour du contenu via le back-office.
|
||||||
|
</p>
|
||||||
|
<p className="text-slate-600 text-sm leading-relaxed">
|
||||||
|
<strong>3.4 Résiliation et retrait des stores.</strong> En cas de résiliation du contrat, pour quelque raison
|
||||||
|
que ce soit, le Prestataire procédera au retrait de l'application des stores dans un délai de 30 jours
|
||||||
|
calendrier suivant la date effective de résiliation.
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section className="mb-8">
|
||||||
|
<h2 className="text-lg font-semibold text-slate-800 mb-3">4. Propriété intellectuelle</h2>
|
||||||
|
<p className="text-slate-600 text-sm leading-relaxed mb-3">
|
||||||
|
<strong>4.1 Propriété du Prestataire.</strong> La solution MyInfoMate, son code source, son architecture, ses
|
||||||
|
interfaces, ses algorithmes et tout élément développé par Unov restent la propriété exclusive du Prestataire.
|
||||||
|
La souscription confère au Client un droit d'usage non exclusif et non transférable pour la durée du
|
||||||
|
contrat.
|
||||||
|
</p>
|
||||||
|
<p className="text-slate-600 text-sm leading-relaxed mb-3">
|
||||||
|
<strong>4.2 Propriété du Client.</strong> Le contenu téléversé par le Client (textes, images, vidéos,
|
||||||
|
documents) reste sa propriété exclusive. Le Client garantit détenir les droits nécessaires sur l'ensemble
|
||||||
|
des contenus qu'il publie via MyInfoMate.
|
||||||
|
</p>
|
||||||
|
<p className="text-slate-600 text-sm leading-relaxed">
|
||||||
|
<strong>4.3 Licence de contenu.</strong> En publiant du contenu via MyInfoMate, le Client accorde au
|
||||||
|
Prestataire une licence limitée et non exclusive pour héberger, reproduire et afficher ce contenu dans le
|
||||||
|
cadre strict de la fourniture du service.
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section className="mb-8">
|
||||||
|
<h2 className="text-lg font-semibold text-slate-800 mb-3">5. Plans et tarification</h2>
|
||||||
|
<div className="overflow-x-auto mb-4">
|
||||||
|
<table className="w-full text-sm text-left border-collapse">
|
||||||
|
<thead>
|
||||||
|
<tr className="border-b border-slate-200 text-slate-500">
|
||||||
|
<th className="py-2 pr-4 font-semibold">Plan</th>
|
||||||
|
<th className="py-2 pr-4 font-semibold">Prix</th>
|
||||||
|
<th className="py-2 pr-4 font-semibold">Canaux</th>
|
||||||
|
<th className="py-2 pr-4 font-semibold">Stockage</th>
|
||||||
|
<th className="py-2 font-semibold">Assistant IA</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody className="text-slate-600">
|
||||||
|
<tr className="border-b border-slate-100">
|
||||||
|
<td className="py-2 pr-4 font-semibold text-slate-800">Essentiel</td>
|
||||||
|
<td className="py-2 pr-4">39 €/mois HTVA</td>
|
||||||
|
<td className="py-2 pr-4">Web + kiosk tablette</td>
|
||||||
|
<td className="py-2 pr-4">1 Go</td>
|
||||||
|
<td className="py-2">En option</td>
|
||||||
|
</tr>
|
||||||
|
<tr className="border-b border-slate-100">
|
||||||
|
<td className="py-2 pr-4 font-semibold text-slate-800">Pro</td>
|
||||||
|
<td className="py-2 pr-4">99 €/mois HTVA</td>
|
||||||
|
<td className="py-2 pr-4">Web + application mobile à la marque du Client</td>
|
||||||
|
<td className="py-2 pr-4">15 Go</td>
|
||||||
|
<td className="py-2">En option</td>
|
||||||
|
</tr>
|
||||||
|
<tr className="border-b border-slate-100">
|
||||||
|
<td className="py-2 pr-4 font-semibold text-slate-800">Premium</td>
|
||||||
|
<td className="py-2 pr-4">179 €/mois HTVA</td>
|
||||||
|
<td className="py-2 pr-4">Web + application mobile à la marque du Client</td>
|
||||||
|
<td className="py-2 pr-4">50 Go</td>
|
||||||
|
<td className="py-2">Inclus</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td className="py-2 pr-4 font-semibold text-slate-800">Enterprise</td>
|
||||||
|
<td className="py-2 pr-4">Sur devis</td>
|
||||||
|
<td className="py-2 pr-4">Multi-sites, besoins spécifiques</td>
|
||||||
|
<td className="py-2 pr-4">Sur mesure</td>
|
||||||
|
<td className="py-2">Sur mesure</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<p className="text-slate-600 text-sm leading-relaxed mb-3">
|
||||||
|
Le plan Essentiel est sans engagement. Les plans incluant une application mobile native impliquent des frais
|
||||||
|
de mise en place et un engagement de 12 mois (voir 5.2). Des engagements pluriannuels (2 ou 3 ans) avec
|
||||||
|
facturation annuelle et tarif préférentiel sont disponibles sur demande.
|
||||||
|
</p>
|
||||||
|
<p className="text-slate-600 text-sm leading-relaxed mb-3">
|
||||||
|
<strong>5.1 bis Quota de l'assistant IA.</strong> Lorsque l'assistant IA est actif, son usage est
|
||||||
|
encadré par un quota mensuel exprimé en jetons de traitement (« tokens »), dont le volume dépend du plan
|
||||||
|
souscrit. La consommation en cours et le plafond applicable sont consultables à tout moment dans le
|
||||||
|
back-office. Le quota se réinitialise au début de chaque période de facturation mensuelle. Une fois le quota
|
||||||
|
atteint, l'assistant cesse de répondre jusqu'à la réinitialisation ou jusqu'à la souscription
|
||||||
|
d'un volume complémentaire, sans que les autres fonctionnalités du service en soient affectées.
|
||||||
|
</p>
|
||||||
|
<p className="text-slate-600 text-sm leading-relaxed mb-3">
|
||||||
|
<strong>5.2 Frais de mise en place.</strong> Un forfait de mise en place est facturé une seule fois lors de
|
||||||
|
l'onboarding. Il couvre la création de l'instance, la configuration initiale, la personnalisation
|
||||||
|
visuelle de l'application et le déploiement sur les stores. Son montant est convenu lors de la commande.
|
||||||
|
</p>
|
||||||
|
<p className="text-slate-600 text-sm leading-relaxed mb-3">
|
||||||
|
<strong>5.3 Facturation.</strong> La facturation est mensuelle ou annuelle selon l'option choisie par le
|
||||||
|
Client. En cas de facturation annuelle, le montant est dû en totalité au début de la période.
|
||||||
|
</p>
|
||||||
|
<p className="text-slate-600 text-sm leading-relaxed mb-3">
|
||||||
|
<strong>5.4 Retard de paiement.</strong> Tout retard de paiement entraîne l'application d'intérêts
|
||||||
|
de retard conformément à la loi belge du 2 août 2002 concernant la lutte contre le retard de paiement dans
|
||||||
|
les transactions commerciales. Le Prestataire se réserve le droit de suspendre l'accès au service après
|
||||||
|
mise en demeure restée sans effet pendant 15 jours.
|
||||||
|
</p>
|
||||||
|
<p className="text-slate-600 text-sm leading-relaxed">
|
||||||
|
<strong>5.5 Évolution tarifaire.</strong> Le Prestataire se réserve le droit de modifier ses tarifs avec un
|
||||||
|
préavis de 60 jours. Le Client peut résilier sans frais si la hausse lui est défavorable et qu'il notifie
|
||||||
|
sa résiliation dans ce délai.
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section className="mb-8">
|
||||||
|
<h2 className="text-lg font-semibold text-slate-800 mb-3">6. Stockage et quotas</h2>
|
||||||
|
<p className="text-slate-600 text-sm leading-relaxed mb-3">
|
||||||
|
<strong>6.1 Quotas de stockage.</strong> Chaque plan inclut un quota de stockage pour les ressources
|
||||||
|
téléversées (images, PDF, documents) : 1 Go pour Essentiel, 15 Go pour Pro, 50 Go pour Premium, sur mesure
|
||||||
|
pour Enterprise.
|
||||||
|
</p>
|
||||||
|
<p className="text-slate-600 text-sm leading-relaxed mb-3">
|
||||||
|
<strong>6.2 Dépassement.</strong> En cas de dépassement, le Prestataire en informe le Client, qui dispose de
|
||||||
|
30 jours pour réduire son usage ou changer de plan. Sans action, le Prestataire pourra suspendre les
|
||||||
|
téléversements jusqu'à régularisation.
|
||||||
|
</p>
|
||||||
|
<p className="text-slate-600 text-sm leading-relaxed">
|
||||||
|
<strong>6.3 Hébergement des médias.</strong> Les ressources sont hébergées sur des services tiers. Le
|
||||||
|
Prestataire se réserve le droit de changer de fournisseur de stockage sans impact pour le Client.
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section className="mb-8">
|
||||||
|
<h2 className="text-lg font-semibold text-slate-800 mb-3">7. Service d'assistant IA</h2>
|
||||||
|
<p className="text-slate-600 text-sm leading-relaxed mb-3">
|
||||||
|
<strong>7.1 Disponibilité selon le plan.</strong> L'assistant IA conversationnel est inclus dans le plan
|
||||||
|
Premium. Il est disponible en option sur les autres plans, et sur mesure dans le plan Enterprise.
|
||||||
|
</p>
|
||||||
|
<p className="text-slate-600 text-sm leading-relaxed mb-3">
|
||||||
|
<strong>7.2 Quotas.</strong> L'usage de l'assistant est encadré par le quota mensuel décrit au
|
||||||
|
point 5.1 bis. Le solde non utilisé n'est pas reporté.
|
||||||
|
</p>
|
||||||
|
<p className="text-slate-600 text-sm leading-relaxed mb-3">
|
||||||
|
<strong>7.3 Fournisseur IA.</strong> Le service est fourni via un fournisseur tiers. Le Prestataire se
|
||||||
|
réserve le droit d'en changer sans impact fonctionnel pour le Client.
|
||||||
|
</p>
|
||||||
|
<p className="text-slate-600 text-sm leading-relaxed">
|
||||||
|
<strong>7.4 Responsabilité sur les réponses.</strong> Le Prestataire ne garantit pas l'exactitude des
|
||||||
|
réponses générées par l'assistant. Il appartient au Client de s'assurer que les contenus qu'il
|
||||||
|
publie sont exacts et à jour. Le Prestataire ne saurait être tenu responsable d'une réponse incorrecte
|
||||||
|
fondée sur un contenu erroné fourni par le Client.
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section className="mb-8">
|
||||||
|
<h2 className="text-lg font-semibold text-slate-800 mb-3">8. Données personnelles et RGPD</h2>
|
||||||
|
<p className="text-slate-600 text-sm leading-relaxed mb-3">
|
||||||
|
<strong>8.1 Données collectées.</strong> D'une part, des <strong>données de visite anonymes</strong> :
|
||||||
|
sections consultées, durée de visite, langue utilisée, type d'appareil, scans de codes QR — aucune
|
||||||
|
donnée permettant d'identifier un visiteur. D'autre part, lorsque le Client a activé cette
|
||||||
|
fonctionnalité, les <strong>questions posées au guide IA</strong> : le texte de la question, la réponse du
|
||||||
|
guide, la langue, le canal utilisé et un identifiant de session généré aléatoirement permettant de rattacher
|
||||||
|
les tours d'une même conversation. Aucun identifiant nominatif, aucun compte et aucune adresse IP ne
|
||||||
|
sont associés à ces enregistrements.
|
||||||
|
</p>
|
||||||
|
<p className="text-slate-600 text-sm leading-relaxed mb-3">
|
||||||
|
Le champ de question est une saisie libre : un visiteur peut y écrire spontanément des informations le
|
||||||
|
concernant, y compris des données sensibles au sens de l'article 9 du RGPD. Le Prestataire ne sollicite
|
||||||
|
ni n'exploite ces informations, et les durées de conservation du point 8.4 s'y appliquent.
|
||||||
|
</p>
|
||||||
|
<p className="text-slate-600 text-sm leading-relaxed mb-3">
|
||||||
|
<strong>8.2 Responsabilité du traitement.</strong> Le Client est responsable de traitement au sens du RGPD
|
||||||
|
pour les données relatives à ses visiteurs. Le Prestataire agit en qualité de sous-traitant.
|
||||||
|
</p>
|
||||||
|
<p className="text-slate-600 text-sm leading-relaxed mb-3">
|
||||||
|
<strong>8.3 Information des visiteurs.</strong> Le Client s'engage à informer ses visiteurs des
|
||||||
|
traitements décrits au point 8.1, via une politique de confidentialité accessible depuis l'application.
|
||||||
|
Cette obligation couvre explicitement les questions posées au guide IA : leur enregistrement, leur durée de
|
||||||
|
conservation et le recours à un fournisseur d'intelligence artificielle tiers. Le Prestataire met à
|
||||||
|
disposition du Client un texte d'information type, que celui-ci reste libre d'adapter et demeure
|
||||||
|
seul responsable de publier.
|
||||||
|
</p>
|
||||||
|
<p className="text-slate-600 text-sm leading-relaxed mb-3">
|
||||||
|
<strong>8.4 Conservation.</strong> Les statistiques de visite sont conservées 13 mois, pour tous les plans.
|
||||||
|
Le texte intégral des questions posées au guide IA est conservé 90 jours, puis supprimé automatiquement ; les
|
||||||
|
regroupements par thème qui en sont issus sont conservés au-delà, sous forme agrégée et sans texte de
|
||||||
|
question. À la résiliation du contrat, les données du Client sont supprimées dans un délai de 90 jours.
|
||||||
|
</p>
|
||||||
|
<p className="text-slate-600 text-sm leading-relaxed mb-3">
|
||||||
|
<strong>8.5 Localisation des données.</strong> Les données sont hébergées au sein de l'Union européenne.
|
||||||
|
Le traitement par le fournisseur d'intelligence artificielle mentionné au point 8.6 peut impliquer un
|
||||||
|
transfert hors Union européenne, encadré par les garanties contractuelles de ce fournisseur.
|
||||||
|
</p>
|
||||||
|
<p className="text-slate-600 text-sm leading-relaxed mb-3">
|
||||||
|
<strong>8.6 Sous-traitants ultérieurs.</strong> Le Prestataire recourt aux sous-traitants suivants :
|
||||||
|
<strong> Google (Gemini)</strong> pour la génération des réponses du guide IA et l'indexation sémantique
|
||||||
|
des contenus ; <strong>Google Cloud / Firebase</strong> pour l'hébergement des fichiers médias ;
|
||||||
|
<strong> Stripe</strong> pour le traitement des paiements ; <strong>Resend</strong> pour l'acheminement
|
||||||
|
des courriels transactionnels. Le Client est réputé autoriser ces sous-traitants du fait de la souscription.
|
||||||
|
Le Prestataire informera le Client de tout ajout ou remplacement, dans un délai lui permettant de formuler
|
||||||
|
une objection.
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section className="mb-8">
|
||||||
|
<h2 className="text-lg font-semibold text-slate-800 mb-3">9. Disponibilité et niveau de service</h2>
|
||||||
|
<p className="text-slate-600 text-sm leading-relaxed mb-3">
|
||||||
|
<strong>9.1 Objectif de disponibilité.</strong> Le Prestataire s'engage à maintenir un taux de
|
||||||
|
disponibilité de 99 % par mois calendaire, hors maintenances planifiées.
|
||||||
|
</p>
|
||||||
|
<p className="text-slate-600 text-sm leading-relaxed mb-3">
|
||||||
|
<strong>9.2 Maintenances planifiées.</strong> Le Prestataire informe le Client avec un préavis de 48 heures
|
||||||
|
pour toute maintenance susceptible d'impacter la disponibilité du service.
|
||||||
|
</p>
|
||||||
|
<p className="text-slate-600 text-sm leading-relaxed">
|
||||||
|
<strong>9.3 Limitation de responsabilité.</strong> En cas d'indisponibilité, la responsabilité du
|
||||||
|
Prestataire est limitée à un avoir sur la prochaine facture, calculé au prorata de la durée
|
||||||
|
d'indisponibilité. Le Prestataire ne saurait être tenu responsable des pertes indirectes subies par le
|
||||||
|
Client.
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section className="mb-8">
|
||||||
|
<h2 className="text-lg font-semibold text-slate-800 mb-3">10. Résiliation</h2>
|
||||||
|
<p className="text-slate-600 text-sm leading-relaxed mb-3">
|
||||||
|
<strong>10.1 Par le Client.</strong> Le Client peut résilier son abonnement à tout moment avec un préavis de
|
||||||
|
30 jours. En cas d'abonnement annuel, aucun remboursement n'est effectué pour la période restante,
|
||||||
|
sauf disposition contraire convenue par écrit.
|
||||||
|
</p>
|
||||||
|
<p className="text-slate-600 text-sm leading-relaxed mb-3">
|
||||||
|
<strong>10.2 Par le Prestataire.</strong> Le Prestataire peut résilier le contrat en cas de non-paiement
|
||||||
|
après mise en demeure restée sans effet, d'utilisation du service contraire aux présentes CGU ou à la
|
||||||
|
loi, ou, pour toute autre raison, avec un préavis de 60 jours.
|
||||||
|
</p>
|
||||||
|
<p className="text-slate-600 text-sm leading-relaxed">
|
||||||
|
<strong>10.3 Effets.</strong> À la date effective de résiliation, l'accès au back-office est désactivé
|
||||||
|
et l'application est retirée des stores dans un délai de 30 jours. Le Client peut demander
|
||||||
|
l'export de son contenu dans un délai de 30 jours avant suppression définitive.
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section className="mb-8">
|
||||||
|
<h2 className="text-lg font-semibold text-slate-800 mb-3">11. Dispositions générales</h2>
|
||||||
|
<p className="text-slate-600 text-sm leading-relaxed mb-3">
|
||||||
|
<strong>11.1 Droit applicable.</strong> Les présentes CGU sont soumises au droit belge.
|
||||||
|
</p>
|
||||||
|
<p className="text-slate-600 text-sm leading-relaxed mb-3">
|
||||||
|
<strong>11.2 Juridiction compétente.</strong> En cas de litige, les parties s'engagent à rechercher une
|
||||||
|
solution amiable. À défaut, les tribunaux de l'arrondissement judiciaire de Namur sont seuls compétents.
|
||||||
|
</p>
|
||||||
|
<p className="text-slate-600 text-sm leading-relaxed mb-3">
|
||||||
|
<strong>11.3 Modification des CGU.</strong> Le Prestataire se réserve le droit de modifier les présentes CGU
|
||||||
|
avec un préavis de 30 jours. La poursuite de l'utilisation du service après ce délai vaut acceptation
|
||||||
|
des nouvelles CGU.
|
||||||
|
</p>
|
||||||
|
<p className="text-slate-600 text-sm leading-relaxed">
|
||||||
|
<strong>11.4 Divisibilité.</strong> Si une clause des présentes CGU est déclarée nulle ou inapplicable, les
|
||||||
|
autres clauses restent en vigueur.
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<p className="text-slate-500 text-sm leading-relaxed">
|
||||||
|
Unov — Rue René Copette 3, 5020 Namur — <a href="mailto:contact@unov.be" className="text-cyan-500 hover:underline">contact@unov.be</a> — TVA BE 0776.895.467
|
||||||
|
</p>
|
||||||
|
<p className="text-slate-400 text-xs mt-4">
|
||||||
|
Voir aussi la <Link href={`/${lang}/confidentialite`} className="text-cyan-500 hover:underline">politique de confidentialité</Link> et les <Link href={`/${lang}/mentions-legales`} className="text-cyan-500 hover:underline">mentions légales</Link>.
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
}
|
||||||
204
src/app/[lang]/confidentialite/page.tsx
Normal file
@ -0,0 +1,204 @@
|
|||||||
|
import type { Metadata } from 'next';
|
||||||
|
import Link from 'next/link';
|
||||||
|
import { notFound } from 'next/navigation';
|
||||||
|
import { LOCALES, LOCALE_HTML_LANG, DEFAULT_LOCALE, isLocale, type Locale } from '@/i18n';
|
||||||
|
|
||||||
|
const PATH = 'confidentialite';
|
||||||
|
|
||||||
|
type LegalText = {
|
||||||
|
meta: { title: string; description: string };
|
||||||
|
back: string;
|
||||||
|
h1: string;
|
||||||
|
intro: string;
|
||||||
|
sections: { title: string; html: string }[];
|
||||||
|
};
|
||||||
|
|
||||||
|
const TEXT: Record<Locale, LegalText> = {
|
||||||
|
fr: {
|
||||||
|
meta: { title: 'Politique de confidentialité | MyInfoMate', description: 'Politique de confidentialité et traitement des données personnelles de MyInfoMate.' },
|
||||||
|
back: '← Retour',
|
||||||
|
h1: 'Politique de confidentialité',
|
||||||
|
intro: "Cette politique concerne le site myinfomate.be. Le traitement des données des visiteurs dans les applications déployées chez nos clients est décrit au point 8 de nos conditions générales.",
|
||||||
|
sections: [
|
||||||
|
{
|
||||||
|
title: 'Responsable du traitement',
|
||||||
|
html: 'Thomas Fransolet — UNOV<br />Rue René Copette 3, 5020 Namur, Belgique<br />Email : <a href="mailto:contact@unov.be" class="text-cyan-500 hover:underline">contact@unov.be</a>',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Données collectées',
|
||||||
|
html: "Le formulaire de contact collecte les données suivantes : prénom, nom, adresse email et le message saisi. Le formulaire d'inscription collecte en outre les données nécessaires à la création de votre espace et à la facturation : nom de l'organisation, coordonnées, adresse de facturation et numéro de TVA éventuel.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Finalité et base légale',
|
||||||
|
html: "Les données du formulaire de contact sont traitées uniquement pour répondre à votre prise de contact ; la base légale est l'intérêt légitime (art. 6.1.f du RGPD). Les données d'inscription sont traitées pour exécuter le contrat que vous souscrivez (art. 6.1.b).",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Conservation des données',
|
||||||
|
html: "Les messages envoyés via le formulaire de contact ne sont pas stockés sur nos serveurs : ils sont transmis par email via le service <strong>Formspree</strong> et ne sont pas conservés au-delà de la réception. Les données liées à un abonnement sont conservées pendant la durée du contrat, puis selon les délais légaux de conservation comptable.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Sous-traitants',
|
||||||
|
html: 'L\'envoi du formulaire utilise <strong>Formspree, Inc.</strong> (États-Unis), dont le transfert est encadré par les clauses contractuelles types de la Commission européenne — voir la <a href="https://formspree.io/legal/privacy-policy" target="_blank" rel="noopener noreferrer" class="text-cyan-500 hover:underline">politique de confidentialité de Formspree</a>. Pour un abonnement, nous recourons également à <strong>Stripe</strong> (paiements) et <strong>Resend</strong> (courriels transactionnels).',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Vos droits',
|
||||||
|
html: 'Conformément au RGPD, vous disposez d\'un droit d\'accès, de rectification, d\'effacement, de limitation, d\'opposition et de portabilité de vos données. Pour les exercer, écrivez à <a href="mailto:contact@unov.be" class="text-cyan-500 hover:underline">contact@unov.be</a>.<br /><br />Vous pouvez également introduire une réclamation auprès de l\'Autorité de protection des données belge : <a href="https://www.autoriteprotectiondonnees.be" target="_blank" rel="noopener noreferrer" class="text-cyan-500 hover:underline">autoriteprotectiondonnees.be</a>.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Cookies',
|
||||||
|
html: "Ce site n'utilise pas de cookies de traçage ou publicitaires. Aucun outil d'analyse comportementale n'est actif.",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
en: {
|
||||||
|
meta: { title: 'Privacy policy | MyInfoMate', description: 'Privacy policy and personal data processing for MyInfoMate.' },
|
||||||
|
back: '← Back',
|
||||||
|
h1: 'Privacy policy',
|
||||||
|
intro: 'This policy covers the myinfomate.be website. The processing of visitor data inside the apps deployed at our customers is described in section 8 of our terms and conditions.',
|
||||||
|
sections: [
|
||||||
|
{
|
||||||
|
title: 'Data controller',
|
||||||
|
html: 'Thomas Fransolet — UNOV<br />Rue René Copette 3, 5020 Namur, Belgium<br />Email: <a href="mailto:contact@unov.be" class="text-cyan-500 hover:underline">contact@unov.be</a>',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Data collected',
|
||||||
|
html: 'The contact form collects the following data: first name, last name, email address and the message you write. The sign-up form additionally collects what is needed to create your space and to invoice you: organisation name, contact details, billing address and VAT number where applicable.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Purpose and legal basis',
|
||||||
|
html: 'Contact form data is processed solely to answer your enquiry; the legal basis is legitimate interest (art. 6.1.f GDPR). Sign-up data is processed to perform the contract you enter into (art. 6.1.b).',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Data retention',
|
||||||
|
html: 'Messages sent through the contact form are not stored on our servers: they are forwarded by email through <strong>Formspree</strong> and not kept beyond receipt. Subscription data is kept for the duration of the contract, then according to statutory accounting retention periods.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Processors',
|
||||||
|
html: 'The form uses <strong>Formspree, Inc.</strong> (United States); the transfer is covered by the European Commission\'s standard contractual clauses — see <a href="https://formspree.io/legal/privacy-policy" target="_blank" rel="noopener noreferrer" class="text-cyan-500 hover:underline">Formspree\'s privacy policy</a>. For a subscription we also use <strong>Stripe</strong> (payments) and <strong>Resend</strong> (transactional emails).',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Your rights',
|
||||||
|
html: 'Under the GDPR you have the right to access, rectify, erase, restrict, object to and port your data. To exercise them, write to <a href="mailto:contact@unov.be" class="text-cyan-500 hover:underline">contact@unov.be</a>.<br /><br />You may also lodge a complaint with the Belgian Data Protection Authority: <a href="https://www.autoriteprotectiondonnees.be" target="_blank" rel="noopener noreferrer" class="text-cyan-500 hover:underline">autoriteprotectiondonnees.be</a>.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Cookies',
|
||||||
|
html: 'This site uses no tracking or advertising cookies. No behavioural analytics tool is active.',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
nl: {
|
||||||
|
meta: { title: 'Privacybeleid | MyInfoMate', description: 'Privacybeleid en verwerking van persoonsgegevens van MyInfoMate.' },
|
||||||
|
back: '← Terug',
|
||||||
|
h1: 'Privacybeleid',
|
||||||
|
intro: 'Dit beleid geldt voor de website myinfomate.be. De verwerking van bezoekersgegevens in de apps bij onze klanten staat beschreven in punt 8 van onze algemene voorwaarden.',
|
||||||
|
sections: [
|
||||||
|
{
|
||||||
|
title: 'Verwerkingsverantwoordelijke',
|
||||||
|
html: 'Thomas Fransolet — UNOV<br />Rue René Copette 3, 5020 Namen, België<br />E-mail: <a href="mailto:contact@unov.be" class="text-cyan-500 hover:underline">contact@unov.be</a>',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Verzamelde gegevens',
|
||||||
|
html: 'Het contactformulier verzamelt: voornaam, naam, e-mailadres en uw bericht. Het inschrijvingsformulier verzamelt bijkomend wat nodig is om uw ruimte aan te maken en te factureren: naam van de organisatie, contactgegevens, facturatieadres en eventueel btw-nummer.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Doel en rechtsgrond',
|
||||||
|
html: 'Gegevens uit het contactformulier worden enkel verwerkt om uw vraag te beantwoorden; de rechtsgrond is het gerechtvaardigd belang (art. 6.1.f AVG). Inschrijvingsgegevens worden verwerkt om de overeenkomst uit te voeren die u aangaat (art. 6.1.b).',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Bewaartermijn',
|
||||||
|
html: 'Berichten via het contactformulier worden niet op onze servers bewaard: ze worden per e-mail doorgestuurd via <strong>Formspree</strong> en niet langer dan de ontvangst bewaard. Abonnementsgegevens worden bewaard tijdens de duur van de overeenkomst en daarna volgens de wettelijke boekhoudkundige bewaartermijnen.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Verwerkers',
|
||||||
|
html: 'Het formulier gebruikt <strong>Formspree, Inc.</strong> (Verenigde Staten); de doorgifte is gedekt door de standaardcontractbepalingen van de Europese Commissie — zie het <a href="https://formspree.io/legal/privacy-policy" target="_blank" rel="noopener noreferrer" class="text-cyan-500 hover:underline">privacybeleid van Formspree</a>. Voor een abonnement doen we ook een beroep op <strong>Stripe</strong> (betalingen) en <strong>Resend</strong> (transactionele e-mails).',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Uw rechten',
|
||||||
|
html: 'Volgens de AVG hebt u recht op inzage, rectificatie, verwijdering, beperking, bezwaar en overdraagbaarheid van uw gegevens. Schrijf daarvoor naar <a href="mailto:contact@unov.be" class="text-cyan-500 hover:underline">contact@unov.be</a>.<br /><br />U kunt ook klacht indienen bij de Belgische Gegevensbeschermingsautoriteit: <a href="https://www.gegevensbeschermingsautoriteit.be" target="_blank" rel="noopener noreferrer" class="text-cyan-500 hover:underline">gegevensbeschermingsautoriteit.be</a>.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Cookies',
|
||||||
|
html: 'Deze site gebruikt geen tracking- of advertentiecookies. Er is geen tool voor gedragsanalyse actief.',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
de: {
|
||||||
|
meta: { title: 'Datenschutzerklärung | MyInfoMate', description: 'Datenschutzerklärung und Verarbeitung personenbezogener Daten von MyInfoMate.' },
|
||||||
|
back: '← Zurück',
|
||||||
|
h1: 'Datenschutzerklärung',
|
||||||
|
intro: 'Diese Erklärung betrifft die Website myinfomate.be. Die Verarbeitung von Besucherdaten in den bei unseren Kunden eingesetzten Apps ist in Punkt 8 unserer AGB beschrieben.',
|
||||||
|
sections: [
|
||||||
|
{
|
||||||
|
title: 'Verantwortlicher',
|
||||||
|
html: 'Thomas Fransolet — UNOV<br />Rue René Copette 3, 5020 Namur, Belgien<br />E-Mail: <a href="mailto:contact@unov.be" class="text-cyan-500 hover:underline">contact@unov.be</a>',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Erhobene Daten',
|
||||||
|
html: 'Das Kontaktformular erhebt: Vorname, Name, E-Mail-Adresse und Ihre Nachricht. Das Anmeldeformular erhebt zusätzlich, was zur Einrichtung Ihres Bereichs und zur Abrechnung nötig ist: Name der Organisation, Kontaktdaten, Rechnungsadresse und gegebenenfalls USt-IdNr.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Zweck und Rechtsgrundlage',
|
||||||
|
html: 'Daten aus dem Kontaktformular werden ausschließlich zur Beantwortung Ihrer Anfrage verarbeitet; Rechtsgrundlage ist das berechtigte Interesse (Art. 6.1.f DSGVO). Anmeldedaten werden zur Erfüllung des von Ihnen geschlossenen Vertrags verarbeitet (Art. 6.1.b).',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Speicherdauer',
|
||||||
|
html: 'Über das Kontaktformular gesendete Nachrichten werden nicht auf unseren Servern gespeichert: Sie werden per E-Mail über <strong>Formspree</strong> weitergeleitet und nicht über den Empfang hinaus aufbewahrt. Abonnementdaten werden für die Vertragsdauer und danach gemäß den gesetzlichen Aufbewahrungsfristen des Handelsrechts gespeichert.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Auftragsverarbeiter',
|
||||||
|
html: 'Das Formular nutzt <strong>Formspree, Inc.</strong> (USA); die Übermittlung ist durch die Standardvertragsklauseln der Europäischen Kommission abgedeckt — siehe die <a href="https://formspree.io/legal/privacy-policy" target="_blank" rel="noopener noreferrer" class="text-cyan-500 hover:underline">Datenschutzerklärung von Formspree</a>. Für ein Abonnement setzen wir zudem <strong>Stripe</strong> (Zahlungen) und <strong>Resend</strong> (Transaktions-E-Mails) ein.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Ihre Rechte',
|
||||||
|
html: 'Nach der DSGVO haben Sie Rechte auf Auskunft, Berichtigung, Löschung, Einschränkung, Widerspruch und Datenübertragbarkeit. Schreiben Sie dazu an <a href="mailto:contact@unov.be" class="text-cyan-500 hover:underline">contact@unov.be</a>.<br /><br />Sie können sich auch bei der belgischen Datenschutzbehörde beschweren: <a href="https://www.autoriteprotectiondonnees.be" target="_blank" rel="noopener noreferrer" class="text-cyan-500 hover:underline">autoriteprotectiondonnees.be</a>.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Cookies',
|
||||||
|
html: 'Diese Website verwendet keine Tracking- oder Werbe-Cookies. Es ist kein Werkzeug zur Verhaltensanalyse aktiv.',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export function generateStaticParams() {
|
||||||
|
return LOCALES.map((lang) => ({ lang }));
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function generateMetadata({ params }: { params: Promise<{ lang: string }> }): Promise<Metadata> {
|
||||||
|
const { lang } = await params;
|
||||||
|
if (!isLocale(lang)) return {};
|
||||||
|
const languages = Object.fromEntries(LOCALES.map((l) => [LOCALE_HTML_LANG[l], `/${l}/${PATH}`]));
|
||||||
|
return {
|
||||||
|
...TEXT[lang].meta,
|
||||||
|
alternates: {
|
||||||
|
canonical: `/${lang}/${PATH}`,
|
||||||
|
languages: { ...languages, 'x-default': `/${DEFAULT_LOCALE}/${PATH}` },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default async function Confidentialite({ params }: { params: Promise<{ lang: string }> }) {
|
||||||
|
const { lang } = await params;
|
||||||
|
if (!isLocale(lang)) notFound();
|
||||||
|
const text = TEXT[lang];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<main className="min-h-screen bg-white">
|
||||||
|
<div className="max-w-3xl mx-auto px-6 py-16">
|
||||||
|
<Link href={`/${lang}`} className="text-sm text-slate-400 hover:text-slate-600 mb-8 inline-block">
|
||||||
|
{text.back}
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
<h1 className="text-3xl font-bold text-slate-900 mb-4">{text.h1}</h1>
|
||||||
|
<p className="text-slate-500 text-sm leading-relaxed mb-10">{text.intro}</p>
|
||||||
|
|
||||||
|
{text.sections.map((section) => (
|
||||||
|
<section key={section.title} className="mb-8">
|
||||||
|
<h2 className="text-lg font-semibold text-slate-800 mb-3">{section.title}</h2>
|
||||||
|
<p className="text-slate-600 text-sm leading-relaxed" dangerouslySetInnerHTML={{ __html: section.html }} />
|
||||||
|
</section>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
}
|
||||||
33
src/app/[lang]/layout.tsx
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import type { Metadata } from "next";
|
||||||
|
import "../globals.css";
|
||||||
|
import { plusJakartaSans } from "../font";
|
||||||
|
import { DEFAULT_LOCALE, LOCALES, LOCALE_HTML_LANG, isLocale } from "@/i18n";
|
||||||
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
metadataBase: new URL("https://myinfomate.be"),
|
||||||
|
icons: { icon: "/myinfomate-logo.png" },
|
||||||
|
};
|
||||||
|
|
||||||
|
export function generateStaticParams() {
|
||||||
|
return LOCALES.map((lang) => ({ lang }));
|
||||||
|
}
|
||||||
|
|
||||||
|
export default async function LangLayout({
|
||||||
|
children,
|
||||||
|
params,
|
||||||
|
}: Readonly<{ children: React.ReactNode; params: Promise<{ lang: string }> }>) {
|
||||||
|
const { lang } = await params;
|
||||||
|
const locale = isLocale(lang) ? lang : DEFAULT_LOCALE;
|
||||||
|
return (
|
||||||
|
<html lang={LOCALE_HTML_LANG[locale]} className={plusJakartaSans.variable}>
|
||||||
|
<head>
|
||||||
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||||
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossOrigin="anonymous" />
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@24,400,0,0&display=swap" rel="stylesheet" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
{children}
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
);
|
||||||
|
}
|
||||||
327
src/app/[lang]/marches-publics/page.tsx
Normal file
@ -0,0 +1,327 @@
|
|||||||
|
import type { Metadata } from 'next';
|
||||||
|
import { notFound } from 'next/navigation';
|
||||||
|
import { LOCALES, LOCALE_HTML_LANG, LOCALE_OG, DEFAULT_LOCALE, isLocale, type Locale } from '@/i18n';
|
||||||
|
import { MYINFOMATE_LINKEDIN, breadcrumbSchema, softwareOffers } from '@/data/structured-data';
|
||||||
|
import ContentPage, { type ContentPageText } from '@/components/ContentPage';
|
||||||
|
|
||||||
|
const SITE_URL = 'https://myinfomate.be';
|
||||||
|
const PATH = 'marches-publics';
|
||||||
|
|
||||||
|
const META: Record<Locale, { title: string; description: string }> = {
|
||||||
|
fr: {
|
||||||
|
title: 'MyInfoMate et les marchés publics | Acheter en commune, musée, province',
|
||||||
|
description: "Prix publics, référence attribuée sur cahier des charges publié, description technique pour votre dossier : comment une commune ou un musée public achète MyInfoMate.",
|
||||||
|
},
|
||||||
|
en: {
|
||||||
|
title: 'MyInfoMate and Public Procurement | Buying as a public body',
|
||||||
|
description: 'Public prices, a reference awarded through a published call for tenders, a technical description for your file: how a municipality or a public museum buys MyInfoMate.',
|
||||||
|
},
|
||||||
|
nl: {
|
||||||
|
title: 'MyInfoMate en overheidsopdrachten | Aankopen als openbaar bestuur',
|
||||||
|
description: 'Publieke prijzen, een referentie gegund na een gepubliceerd bestek, een technische beschrijving voor uw dossier: hoe een gemeente of openbaar museum MyInfoMate aankoopt.',
|
||||||
|
},
|
||||||
|
de: {
|
||||||
|
title: 'MyInfoMate und öffentliche Aufträge | Beschaffung für Kommunen',
|
||||||
|
description: 'Öffentliche Preise, eine nach veröffentlichter Ausschreibung vergebene Referenz, eine technische Beschreibung für Ihre Akte: So beschafft eine Gemeinde oder ein öffentliches Museum MyInfoMate.',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const TEXT: Record<Locale, ContentPageText> = {
|
||||||
|
fr: {
|
||||||
|
back: "Retour à l'accueil",
|
||||||
|
badge: 'Marchés publics',
|
||||||
|
h1Before: 'Acheter MyInfoMate ',
|
||||||
|
h1Highlight: 'quand on est un acheteur public',
|
||||||
|
intro: "Commune, province, musée communal, office du tourisme, intercommunale : la question n'est pas seulement « est-ce que la solution convient ? », mais « est-ce qu'on peut l'acheter proprement ? ». Voici de quoi préparer votre dossier.",
|
||||||
|
ctaPrimary: 'Demander un devis',
|
||||||
|
ctaSecondary: 'Voir les tarifs publics',
|
||||||
|
pointsTitle: 'Ce que nous apportons à votre dossier',
|
||||||
|
points: [
|
||||||
|
{
|
||||||
|
icon: 'gavel',
|
||||||
|
title: 'Une référence attribuée sur cahier des charges',
|
||||||
|
text: "L'office du tourisme de Namur a retenu MyInfoMate à l'issue d'un cahier des charges publié. Ce n'est pas un argument commercial : c'est une procédure que vos collègues connaissent, menée à son terme.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'sell',
|
||||||
|
title: 'Des prix publics, donc un budget défendable',
|
||||||
|
text: "39, 99 et 179 €/mois hors TVA, affichés sur le site. Vous pouvez chiffrer votre projet avant même de nous rencontrer, et justifier le montant estimé dans votre note au collège ou à votre direction.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'description',
|
||||||
|
title: 'Les pièces techniques, écrites pour être annexées',
|
||||||
|
text: "Devis détaillé, description des fonctionnalités, modes de déploiement, hébergement et traitement des données : nous vous fournissons de quoi documenter votre dossier, sans que vous ayez à traduire un argumentaire commercial.",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
caseTitle: 'Visit Namur, le précédent le plus parlant',
|
||||||
|
caseText: "Un office du tourisme public, un cahier des charges publié, des bornes tactiles en service depuis 2024 : carte de la ville, agenda des événements tenu par l'équipe, itinéraires. C'est la référence à citer si votre service marchés vous demande qui a déjà fait ça.",
|
||||||
|
caseLink: 'Lire le cas Visit Namur',
|
||||||
|
caseSlug: 'visit-namur',
|
||||||
|
faqTitle: 'Questions fréquentes des acheteurs publics',
|
||||||
|
faq: [
|
||||||
|
{
|
||||||
|
question: 'Faut-il forcément lancer une procédure formelle ?',
|
||||||
|
answer: "Pas nécessairement. En Belgique, les marchés de faible montant se commandent sur simple facture ou bon de commande, sans mise en concurrence formelle ; au-dessus, une consultation de plusieurs opérateurs suffit souvent. Le seuil applicable dépend du droit en vigueur au moment de votre achat : c'est à vérifier avec votre service marchés, nous ne nous substituons pas à lui.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Quels documents pouvez-vous fournir pour notre dossier ?',
|
||||||
|
answer: "Dites-nous ce que votre dossier exige et nous rassemblons les pièces : devis détaillé, description technique, informations sur l'hébergement et le traitement des données, coordonnées d'entreprise et de TVA. Si votre marché impose un contrat de traitement des données (DPA), nous l'établissons avec vous avant la signature.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Où sont hébergées les données, et qui est responsable de traitement ?',
|
||||||
|
answer: "Les données sont hébergées dans l'Union européenne. Votre institution est responsable de traitement au sens du RGPD, MyInfoMate agit comme sous-traitant. Les statistiques de visite sont anonymes ; si l'assistant IA est activé, les questions des visiteurs sont conservées 90 jours puis supprimées. Le détail figure au point 8 de nos conditions générales.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Répondez-vous aux critères d\'accessibilité ?',
|
||||||
|
answer: "Soyons précis, parce que c'est un critère qui peut éliminer une offre : l'audio et le multilingue aident réellement, et l'application respecte les réglages d'accessibilité de l'appareil. Mais nous ne sommes pas certifiés Access-i et aucun audit d'accessibilité formel n'a été réalisé à ce jour. Si votre cahier des charges l'exige, dites-le-nous avant de le publier.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Le budget peut-il être étalé sur plusieurs années ?',
|
||||||
|
answer: "Oui. Nous proposons des engagements de 2 ou 3 ans avec facturation annuelle et tarif préférentiel, ce qui correspond mieux à un subside ou à un budget pluriannuel qu'un abonnement mensuel.",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
ctaTitle: 'Un dossier à monter ? Écrivez-nous.',
|
||||||
|
ctaButton: 'Demander un devis détaillé',
|
||||||
|
},
|
||||||
|
en: {
|
||||||
|
back: 'Back to home',
|
||||||
|
badge: 'Public procurement',
|
||||||
|
h1Before: 'Buying MyInfoMate ',
|
||||||
|
h1Highlight: 'as a public body',
|
||||||
|
intro: 'Municipality, province, municipal museum, tourism office: the question is not only "does the solution fit?" but "can we buy it properly?". Here is what you need to prepare your file.',
|
||||||
|
ctaPrimary: 'Request a quotation',
|
||||||
|
ctaSecondary: 'See public pricing',
|
||||||
|
pointsTitle: 'What we bring to your file',
|
||||||
|
points: [
|
||||||
|
{
|
||||||
|
icon: 'gavel',
|
||||||
|
title: 'A reference awarded through a published tender',
|
||||||
|
text: 'The Namur tourism office selected MyInfoMate following a published call for tenders. That is not a sales line: it is a procedure your colleagues know, carried through to the end.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'sell',
|
||||||
|
title: 'Public prices, so a defensible budget',
|
||||||
|
text: '€39, €99 and €179 per month excluding VAT, published on the site. You can size your project before meeting us, and justify the estimate in your note to the council or to your management.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'description',
|
||||||
|
title: 'Technical documents written to be annexed',
|
||||||
|
text: 'Detailed quotation, description of features, deployment modes, hosting and data processing: we give you what documents your file, without you having to translate a sales pitch.',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
caseTitle: 'Visit Namur, the most telling precedent',
|
||||||
|
caseText: 'A public tourism office, a published call for tenders, touch kiosks in service since 2024: city map, events agenda kept by the team, itineraries. That is the reference to quote if your procurement department asks who has done this before.',
|
||||||
|
caseLink: 'Read the Visit Namur case',
|
||||||
|
caseSlug: 'visit-namur',
|
||||||
|
faqTitle: 'Public buyers FAQ',
|
||||||
|
faq: [
|
||||||
|
{
|
||||||
|
question: 'Do we have to run a formal procedure?',
|
||||||
|
answer: 'Not necessarily. In Belgium, low-value contracts can be ordered on a simple invoice or purchase order, with no formal competition; above that, consulting several operators is often enough. The applicable threshold depends on the law in force when you buy: check it with your procurement department — we do not stand in for it.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'What documents can you provide for our file?',
|
||||||
|
answer: 'Tell us what your file requires and we gather the pieces: detailed quotation, technical description, information on hosting and data processing, company and VAT details. If your contract requires a data processing agreement (DPA), we draw it up with you before signature.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Where is the data hosted, and who is the controller?',
|
||||||
|
answer: 'Data is hosted in the European Union. Your institution is the data controller under the GDPR and MyInfoMate acts as processor. Visit statistics are anonymous; if the AI assistant is enabled, visitor questions are kept for 90 days and then deleted. The details are in section 8 of our terms and conditions.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Do you meet accessibility criteria?',
|
||||||
|
answer: 'Let us be precise, because this criterion can rule an offer out: audio and multilingual content genuinely help, and the app respects the device accessibility settings. But we are not Access-i certified and no formal accessibility audit has been carried out to date. If your specification requires it, tell us before publishing it.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Can the budget be spread over several years?',
|
||||||
|
answer: 'Yes. We offer 2- or 3-year commitments with annual billing and a preferential rate, which suits a grant or a multi-year budget better than a monthly subscription.',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
ctaTitle: 'Preparing a file? Write to us.',
|
||||||
|
ctaButton: 'Request a detailed quotation',
|
||||||
|
},
|
||||||
|
nl: {
|
||||||
|
back: 'Terug naar home',
|
||||||
|
badge: 'Overheidsopdrachten',
|
||||||
|
h1Before: 'MyInfoMate aankopen ',
|
||||||
|
h1Highlight: 'als openbaar bestuur',
|
||||||
|
intro: 'Gemeente, provincie, gemeentelijk museum, toerismekantoor: de vraag is niet alleen "past de oplossing?", maar ook "kunnen we ze correct aankopen?". Hier vindt u wat u nodig hebt voor uw dossier.',
|
||||||
|
ctaPrimary: 'Offerte aanvragen',
|
||||||
|
ctaSecondary: 'Publieke tarieven bekijken',
|
||||||
|
pointsTitle: 'Wat wij aan uw dossier toevoegen',
|
||||||
|
points: [
|
||||||
|
{
|
||||||
|
icon: 'gavel',
|
||||||
|
title: 'Een referentie gegund na een gepubliceerd bestek',
|
||||||
|
text: 'Het toerismekantoor van Namen koos MyInfoMate na een gepubliceerd bestek. Dat is geen verkooppraatje: het is een procedure die uw collega\'s kennen, tot het einde doorlopen.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'sell',
|
||||||
|
title: 'Publieke prijzen, dus een verdedigbaar budget',
|
||||||
|
text: '€39, €99 en €179 per maand excl. btw, op de site vermeld. U kunt uw project ramen nog vóór u ons ontmoet, en het bedrag verantwoorden in uw nota aan het college of aan uw directie.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'description',
|
||||||
|
title: 'Technische stukken, geschreven om bij te voegen',
|
||||||
|
text: 'Gedetailleerde offerte, beschrijving van de functionaliteiten, uitrolwijzen, hosting en gegevensverwerking: wij leveren wat uw dossier documenteert, zonder dat u een verkoopstekst moet vertalen.',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
caseTitle: 'Visit Namen, het meest sprekende precedent',
|
||||||
|
caseText: 'Een openbaar toerismekantoor, een gepubliceerd bestek, touchkiosken in dienst sinds 2024: stadsplan, evenementenagenda bijgehouden door het team, routes. Dat is de referentie om te citeren als uw dienst overheidsopdrachten vraagt wie dit al deed.',
|
||||||
|
caseLink: 'Lees de case Visit Namen',
|
||||||
|
caseSlug: 'visit-namur',
|
||||||
|
faqTitle: 'Veelgestelde vragen van openbare aankopers',
|
||||||
|
faq: [
|
||||||
|
{
|
||||||
|
question: 'Moeten we per se een formele procedure voeren?',
|
||||||
|
answer: 'Niet noodzakelijk. In België kunnen opdrachten van beperkte waarde besteld worden op eenvoudige factuur of bestelbon, zonder formele mededinging; daarboven volstaat vaak een raadpleging van meerdere operatoren. De toepasselijke drempel hangt af van de geldende regelgeving op het moment van uw aankoop: check dat met uw dienst overheidsopdrachten — wij treden niet in hun plaats.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Welke documenten kunt u voor ons dossier leveren?',
|
||||||
|
answer: 'Zeg ons wat uw dossier vereist en wij verzamelen de stukken: gedetailleerde offerte, technische beschrijving, informatie over hosting en gegevensverwerking, onderneming- en btw-gegevens. Vereist uw opdracht een verwerkersovereenkomst (DPA), dan stellen we die samen met u op vóór de ondertekening.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Waar worden de gegevens gehost en wie is verwerkingsverantwoordelijke?',
|
||||||
|
answer: 'De gegevens worden in de Europese Unie gehost. Uw instelling is verwerkingsverantwoordelijke volgens de GDPR, MyInfoMate treedt op als verwerker. De bezoekstatistieken zijn anoniem; is de AI-assistent actief, dan worden bezoekersvragen 90 dagen bewaard en daarna verwijderd. De details staan in punt 8 van onze algemene voorwaarden.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Voldoet u aan toegankelijkheidscriteria?',
|
||||||
|
answer: 'Laten we precies zijn, want dat criterium kan een offerte uitsluiten: audio en meertaligheid helpen echt, en de app respecteert de toegankelijkheidsinstellingen van het toestel. Maar we zijn niet Access-i-gecertificeerd en er is tot vandaag geen formele toegankelijkheidsaudit uitgevoerd. Vereist uw bestek dat, zeg het ons vóór u publiceert.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Kan het budget over meerdere jaren gespreid worden?',
|
||||||
|
answer: 'Ja. We bieden verbintenissen van 2 of 3 jaar met jaarlijkse facturatie en een voordeliger tarief, wat beter past bij een subsidie of een meerjarig budget dan een maandabonnement.',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
ctaTitle: 'Een dossier voor te bereiden? Schrijf ons.',
|
||||||
|
ctaButton: 'Gedetailleerde offerte aanvragen',
|
||||||
|
},
|
||||||
|
de: {
|
||||||
|
back: 'Zurück zur Startseite',
|
||||||
|
badge: 'Öffentliche Aufträge',
|
||||||
|
h1Before: 'MyInfoMate beschaffen ',
|
||||||
|
h1Highlight: 'als öffentlicher Auftraggeber',
|
||||||
|
intro: 'Gemeinde, Provinz, kommunales Museum, Tourismusbüro: Die Frage ist nicht nur „passt die Lösung?“, sondern „können wir sie sauber beschaffen?“. Hier finden Sie, was Sie für Ihre Akte brauchen.',
|
||||||
|
ctaPrimary: 'Angebot anfragen',
|
||||||
|
ctaSecondary: 'Öffentliche Preise ansehen',
|
||||||
|
pointsTitle: 'Was wir zu Ihrer Akte beitragen',
|
||||||
|
points: [
|
||||||
|
{
|
||||||
|
icon: 'gavel',
|
||||||
|
title: 'Eine nach veröffentlichter Ausschreibung vergebene Referenz',
|
||||||
|
text: 'Das Tourismusbüro Namur hat MyInfoMate nach einer veröffentlichten Ausschreibung ausgewählt. Das ist kein Verkaufsargument, sondern ein Verfahren, das Ihre Kollegen kennen — bis zum Ende geführt.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'sell',
|
||||||
|
title: 'Öffentliche Preise, also ein vertretbares Budget',
|
||||||
|
text: '39, 99 und 179 € pro Monat zzgl. MwSt., auf der Website veröffentlicht. Sie können Ihr Projekt kalkulieren, bevor Sie uns treffen, und den Betrag in Ihrer Vorlage begründen.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'description',
|
||||||
|
title: 'Technische Unterlagen, zum Beilegen geschrieben',
|
||||||
|
text: 'Detailliertes Angebot, Beschreibung der Funktionen, Einsatzarten, Hosting und Datenverarbeitung: Wir liefern, was Ihre Akte belegt — ohne dass Sie einen Werbetext übersetzen müssen.',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
caseTitle: 'Visit Namur, der aussagekräftigste Präzedenzfall',
|
||||||
|
caseText: 'Ein öffentliches Tourismusbüro, eine veröffentlichte Ausschreibung, Touch-Kioske im Einsatz seit 2024: Stadtplan, vom Team gepflegter Veranstaltungskalender, Routen. Das ist die Referenz, wenn Ihre Vergabestelle fragt, wer so etwas schon gemacht hat.',
|
||||||
|
caseLink: 'Den Fall Visit Namur lesen',
|
||||||
|
caseSlug: 'visit-namur',
|
||||||
|
faqTitle: 'Häufige Fragen öffentlicher Auftraggeber',
|
||||||
|
faq: [
|
||||||
|
{
|
||||||
|
question: 'Muss zwingend ein förmliches Verfahren laufen?',
|
||||||
|
answer: 'Nicht unbedingt. In Belgien können Aufträge geringen Wertes auf einfache Rechnung oder Bestellung vergeben werden, ohne förmlichen Wettbewerb; darüber genügt oft die Konsultation mehrerer Anbieter. Der geltende Schwellenwert hängt vom Recht zum Zeitpunkt der Beschaffung ab: Klären Sie ihn mit Ihrer Vergabestelle — wir ersetzen sie nicht.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Welche Unterlagen können Sie für unsere Akte liefern?',
|
||||||
|
answer: 'Sagen Sie uns, was Ihre Akte verlangt, und wir stellen die Unterlagen zusammen: detailliertes Angebot, technische Beschreibung, Angaben zu Hosting und Datenverarbeitung, Unternehmens- und USt-Daten. Verlangt Ihr Auftrag einen Auftragsverarbeitungsvertrag (AVV), erstellen wir ihn vor der Unterschrift gemeinsam mit Ihnen.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Wo werden die Daten gehostet, und wer ist Verantwortlicher?',
|
||||||
|
answer: 'Die Daten werden in der Europäischen Union gehostet. Ihre Einrichtung ist Verantwortlicher im Sinne der DSGVO, MyInfoMate handelt als Auftragsverarbeiter. Die Besuchsstatistiken sind anonym; ist der KI-Assistent aktiv, werden Besucherfragen 90 Tage gespeichert und danach gelöscht. Details stehen in Punkt 8 unserer AGB.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Erfüllen Sie Barrierefreiheitskriterien?',
|
||||||
|
answer: 'Seien wir genau, denn dieses Kriterium kann ein Angebot ausschließen: Audio und Mehrsprachigkeit helfen wirklich, und die App übernimmt die Barrierefreiheitseinstellungen des Geräts. Aber wir sind nicht Access-i-zertifiziert, und bis heute wurde kein formelles Barrierefreiheits-Audit durchgeführt. Verlangt Ihr Leistungsverzeichnis das, sagen Sie es uns vor der Veröffentlichung.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Lässt sich das Budget über mehrere Jahre strecken?',
|
||||||
|
answer: 'Ja. Wir bieten Laufzeiten von 2 oder 3 Jahren mit jährlicher Abrechnung und Vorzugspreis — das passt besser zu einer Förderung oder einem mehrjährigen Budget als ein Monatsabo.',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
ctaTitle: 'Eine Akte vorzubereiten? Schreiben Sie uns.',
|
||||||
|
ctaButton: 'Detailliertes Angebot anfragen',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export function generateStaticParams() {
|
||||||
|
return LOCALES.map((lang) => ({ lang }));
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function generateMetadata({
|
||||||
|
params,
|
||||||
|
}: {
|
||||||
|
params: Promise<{ lang: string }>;
|
||||||
|
}): Promise<Metadata> {
|
||||||
|
const { lang } = await params;
|
||||||
|
if (!isLocale(lang)) return {};
|
||||||
|
const m = META[lang];
|
||||||
|
const languages = Object.fromEntries(LOCALES.map((l) => [LOCALE_HTML_LANG[l], `/${l}/${PATH}`]));
|
||||||
|
return {
|
||||||
|
title: m.title,
|
||||||
|
description: m.description,
|
||||||
|
openGraph: {
|
||||||
|
title: m.title,
|
||||||
|
description: m.description,
|
||||||
|
url: `${SITE_URL}/${lang}/${PATH}`,
|
||||||
|
siteName: 'MyInfoMate',
|
||||||
|
locale: LOCALE_OG[lang],
|
||||||
|
type: 'website',
|
||||||
|
},
|
||||||
|
alternates: {
|
||||||
|
canonical: `/${lang}/${PATH}`,
|
||||||
|
languages: { ...languages, 'x-default': `/${DEFAULT_LOCALE}/${PATH}` },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default async function MarchesPublicsPage({ params }: { params: Promise<{ lang: string }> }) {
|
||||||
|
const { lang } = await params;
|
||||||
|
if (!isLocale(lang)) notFound();
|
||||||
|
const text = TEXT[lang];
|
||||||
|
|
||||||
|
const faqSchema = {
|
||||||
|
'@context': 'https://schema.org',
|
||||||
|
'@type': 'FAQPage',
|
||||||
|
mainEntity: text.faq.map((item) => ({
|
||||||
|
'@type': 'Question',
|
||||||
|
name: item.question,
|
||||||
|
acceptedAnswer: { '@type': 'Answer', text: item.answer },
|
||||||
|
})),
|
||||||
|
};
|
||||||
|
|
||||||
|
const softwareSchema = {
|
||||||
|
'@context': 'https://schema.org',
|
||||||
|
'@type': 'SoftwareApplication',
|
||||||
|
name: 'MyInfoMate',
|
||||||
|
applicationCategory: 'BusinessApplication',
|
||||||
|
operatingSystem: 'iOS, Android, Web',
|
||||||
|
offers: softwareOffers,
|
||||||
|
sameAs: [MYINFOMATE_LINKEDIN],
|
||||||
|
description: META[lang].description,
|
||||||
|
url: `${SITE_URL}/${lang}/${PATH}`,
|
||||||
|
};
|
||||||
|
|
||||||
|
const breadcrumb = breadcrumbSchema([
|
||||||
|
{ name: 'MyInfoMate', path: `/${lang}` },
|
||||||
|
{ name: text.badge, path: `/${lang}/${PATH}` },
|
||||||
|
]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(breadcrumb) }} />
|
||||||
|
<script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(faqSchema) }} />
|
||||||
|
<script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(softwareSchema) }} />
|
||||||
|
<ContentPage lang={lang} text={text} />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
166
src/app/[lang]/mentions-legales/page.tsx
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
import type { Metadata } from 'next';
|
||||||
|
import Link from 'next/link';
|
||||||
|
import { notFound } from 'next/navigation';
|
||||||
|
import { LOCALES, LOCALE_HTML_LANG, DEFAULT_LOCALE, isLocale, type Locale } from '@/i18n';
|
||||||
|
|
||||||
|
const PATH = 'mentions-legales';
|
||||||
|
|
||||||
|
type LegalText = {
|
||||||
|
meta: { title: string; description: string };
|
||||||
|
back: string;
|
||||||
|
h1: string;
|
||||||
|
sections: { title: string; html: string }[];
|
||||||
|
};
|
||||||
|
|
||||||
|
const TEXT: Record<Locale, LegalText> = {
|
||||||
|
fr: {
|
||||||
|
meta: { title: 'Mentions légales | MyInfoMate', description: 'Mentions légales du site MyInfoMate, édité par Unov (Namur, Belgique).' },
|
||||||
|
back: '← Retour',
|
||||||
|
h1: 'Mentions légales',
|
||||||
|
sections: [
|
||||||
|
{
|
||||||
|
title: 'Éditeur du site',
|
||||||
|
html: 'Le présent site est édité par :<br /><strong>Thomas Fransolet</strong>, personne physique exerçant une activité sous l\'enseigne <strong>UNOV</strong><br />Numéro d\'entreprise BCE : 0776.895.467<br />Numéro de TVA : BE 0776.895.467<br />Rue René Copette 3, 5020 Namur, Belgique<br />Email : <a href="mailto:contact@unov.be" class="text-cyan-500 hover:underline">contact@unov.be</a><br />Téléphone : +32 498 07 95 35',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Hébergement',
|
||||||
|
html: 'Ce site est hébergé par :<br /><strong>OVH SAS</strong><br />2 rue Kellermann, 59100 Roubaix, France<br /><a href="https://www.ovh.com" target="_blank" rel="noopener noreferrer" class="text-cyan-500 hover:underline">www.ovh.com</a>',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Propriété intellectuelle',
|
||||||
|
html: "L'ensemble des contenus présents sur ce site (textes, images, logos, graphismes) sont la propriété exclusive de Thomas Fransolet / UNOV, sauf mention contraire. Toute reproduction, distribution ou utilisation sans autorisation préalable est interdite.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Responsabilité',
|
||||||
|
html: "UNOV s'efforce de maintenir les informations publiées sur ce site à jour et exactes. Nous déclinons toute responsabilité en cas d'erreurs, d'omissions ou de résultats obtenus par un usage inapproprié de ces informations.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Droit applicable',
|
||||||
|
html: 'Le présent site est soumis au droit belge. Tout litige relatif à son utilisation relève de la compétence exclusive des tribunaux de Namur, Belgique.',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
en: {
|
||||||
|
meta: { title: 'Legal notice | MyInfoMate', description: 'Legal notice for the MyInfoMate website, published by Unov (Namur, Belgium).' },
|
||||||
|
back: '← Back',
|
||||||
|
h1: 'Legal notice',
|
||||||
|
sections: [
|
||||||
|
{
|
||||||
|
title: 'Publisher',
|
||||||
|
html: 'This website is published by:<br /><strong>Thomas Fransolet</strong>, a natural person trading under the name <strong>UNOV</strong><br />Belgian company number (BCE): 0776.895.467<br />VAT number: BE 0776.895.467<br />Rue René Copette 3, 5020 Namur, Belgium<br />Email: <a href="mailto:contact@unov.be" class="text-cyan-500 hover:underline">contact@unov.be</a><br />Phone: +32 498 07 95 35',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Hosting',
|
||||||
|
html: 'This website is hosted by:<br /><strong>OVH SAS</strong><br />2 rue Kellermann, 59100 Roubaix, France<br /><a href="https://www.ovh.com" target="_blank" rel="noopener noreferrer" class="text-cyan-500 hover:underline">www.ovh.com</a>',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Intellectual property',
|
||||||
|
html: 'All content on this website (texts, images, logos, graphics) is the exclusive property of Thomas Fransolet / UNOV unless stated otherwise. Any reproduction, distribution or use without prior authorisation is prohibited.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Liability',
|
||||||
|
html: 'UNOV strives to keep the information published on this site accurate and up to date. We accept no liability for errors, omissions, or outcomes resulting from inappropriate use of this information.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Applicable law',
|
||||||
|
html: 'This website is governed by Belgian law. Any dispute relating to its use falls under the exclusive jurisdiction of the courts of Namur, Belgium.',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
nl: {
|
||||||
|
meta: { title: 'Wettelijke vermeldingen | MyInfoMate', description: 'Wettelijke vermeldingen van de website MyInfoMate, uitgegeven door Unov (Namen, België).' },
|
||||||
|
back: '← Terug',
|
||||||
|
h1: 'Wettelijke vermeldingen',
|
||||||
|
sections: [
|
||||||
|
{
|
||||||
|
title: 'Uitgever van de website',
|
||||||
|
html: 'Deze website wordt uitgegeven door:<br /><strong>Thomas Fransolet</strong>, natuurlijke persoon handelend onder de naam <strong>UNOV</strong><br />Ondernemingsnummer (KBO): 0776.895.467<br />Btw-nummer: BE 0776.895.467<br />Rue René Copette 3, 5020 Namen, België<br />E-mail: <a href="mailto:contact@unov.be" class="text-cyan-500 hover:underline">contact@unov.be</a><br />Telefoon: +32 498 07 95 35',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Hosting',
|
||||||
|
html: 'Deze website wordt gehost door:<br /><strong>OVH SAS</strong><br />2 rue Kellermann, 59100 Roubaix, Frankrijk<br /><a href="https://www.ovh.com" target="_blank" rel="noopener noreferrer" class="text-cyan-500 hover:underline">www.ovh.com</a>',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Intellectuele eigendom',
|
||||||
|
html: 'Alle inhoud op deze website (teksten, beelden, logo\'s, grafische elementen) is de exclusieve eigendom van Thomas Fransolet / UNOV, tenzij anders vermeld. Elke reproductie, verspreiding of gebruik zonder voorafgaande toestemming is verboden.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Aansprakelijkheid',
|
||||||
|
html: 'UNOV streeft ernaar de informatie op deze site correct en actueel te houden. Wij aanvaarden geen aansprakelijkheid voor fouten, weglatingen of gevolgen van een oneigenlijk gebruik van deze informatie.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Toepasselijk recht',
|
||||||
|
html: 'Deze website is onderworpen aan het Belgische recht. Elk geschil over het gebruik ervan valt onder de uitsluitende bevoegdheid van de rechtbanken van Namen, België.',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
de: {
|
||||||
|
meta: { title: 'Impressum | MyInfoMate', description: 'Impressum der Website MyInfoMate, herausgegeben von Unov (Namur, Belgien).' },
|
||||||
|
back: '← Zurück',
|
||||||
|
h1: 'Impressum',
|
||||||
|
sections: [
|
||||||
|
{
|
||||||
|
title: 'Herausgeber der Website',
|
||||||
|
html: 'Diese Website wird herausgegeben von:<br /><strong>Thomas Fransolet</strong>, natürliche Person, tätig unter der Bezeichnung <strong>UNOV</strong><br />Unternehmensnummer (ZDU): 0776.895.467<br />USt-IdNr.: BE 0776.895.467<br />Rue René Copette 3, 5020 Namur, Belgien<br />E-Mail: <a href="mailto:contact@unov.be" class="text-cyan-500 hover:underline">contact@unov.be</a><br />Telefon: +32 498 07 95 35',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Hosting',
|
||||||
|
html: 'Diese Website wird gehostet von:<br /><strong>OVH SAS</strong><br />2 rue Kellermann, 59100 Roubaix, Frankreich<br /><a href="https://www.ovh.com" target="_blank" rel="noopener noreferrer" class="text-cyan-500 hover:underline">www.ovh.com</a>',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Geistiges Eigentum',
|
||||||
|
html: 'Alle Inhalte dieser Website (Texte, Bilder, Logos, Grafiken) sind ausschließliches Eigentum von Thomas Fransolet / UNOV, sofern nicht anders angegeben. Jede Vervielfältigung, Verbreitung oder Nutzung ohne vorherige Genehmigung ist untersagt.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Haftung',
|
||||||
|
html: 'UNOV ist bestrebt, die auf dieser Website veröffentlichten Informationen aktuell und richtig zu halten. Für Fehler, Auslassungen oder Folgen einer unsachgemäßen Nutzung dieser Informationen übernehmen wir keine Haftung.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Anwendbares Recht',
|
||||||
|
html: 'Diese Website unterliegt belgischem Recht. Für Streitigkeiten über ihre Nutzung sind ausschließlich die Gerichte von Namur, Belgien, zuständig.',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export function generateStaticParams() {
|
||||||
|
return LOCALES.map((lang) => ({ lang }));
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function generateMetadata({ params }: { params: Promise<{ lang: string }> }): Promise<Metadata> {
|
||||||
|
const { lang } = await params;
|
||||||
|
if (!isLocale(lang)) return {};
|
||||||
|
const languages = Object.fromEntries(LOCALES.map((l) => [LOCALE_HTML_LANG[l], `/${l}/${PATH}`]));
|
||||||
|
return {
|
||||||
|
...TEXT[lang].meta,
|
||||||
|
alternates: {
|
||||||
|
canonical: `/${lang}/${PATH}`,
|
||||||
|
languages: { ...languages, 'x-default': `/${DEFAULT_LOCALE}/${PATH}` },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default async function MentionsLegales({ params }: { params: Promise<{ lang: string }> }) {
|
||||||
|
const { lang } = await params;
|
||||||
|
if (!isLocale(lang)) notFound();
|
||||||
|
const text = TEXT[lang];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<main className="min-h-screen bg-white">
|
||||||
|
<div className="max-w-3xl mx-auto px-6 py-16">
|
||||||
|
<Link href={`/${lang}`} className="text-sm text-slate-400 hover:text-slate-600 mb-8 inline-block">
|
||||||
|
{text.back}
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
<h1 className="text-3xl font-bold text-slate-900 mb-10">{text.h1}</h1>
|
||||||
|
|
||||||
|
{text.sections.map((section) => (
|
||||||
|
<section key={section.title} className="mb-8">
|
||||||
|
<h2 className="text-lg font-semibold text-slate-800 mb-3">{section.title}</h2>
|
||||||
|
<p className="text-slate-600 text-sm leading-relaxed" dangerouslySetInnerHTML={{ __html: section.html }} />
|
||||||
|
</section>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
}
|
||||||
16
src/app/[lang]/not-found.tsx
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import Link from "next/link";
|
||||||
|
|
||||||
|
export default function NotFound() {
|
||||||
|
return (
|
||||||
|
<main className="min-h-screen bg-white flex items-center justify-center px-6">
|
||||||
|
<div className="text-center">
|
||||||
|
<p className="text-6xl font-extrabold text-slate-900 mb-4">404</p>
|
||||||
|
<h1 className="text-xl font-bold text-slate-700 mb-2">Page introuvable</h1>
|
||||||
|
<p className="text-slate-500 mb-8">Page not found · Pagina niet gevonden · Seite nicht gefunden</p>
|
||||||
|
<Link href="/" className="inline-block bg-primary text-slate-900 font-extrabold text-sm px-6 py-3 rounded-full">
|
||||||
|
MyInfoMate
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -1,6 +1,8 @@
|
|||||||
import type { Metadata } from 'next';
|
import type { Metadata } from 'next';
|
||||||
import { notFound } from 'next/navigation';
|
import { notFound } from 'next/navigation';
|
||||||
import { LOCALES, LOCALE_HTML_LANG, LOCALE_OG, DEFAULT_LOCALE, isLocale, type Locale } from '@/i18n';
|
import { LOCALES, LOCALE_HTML_LANG, LOCALE_OG, DEFAULT_LOCALE, isLocale, type Locale } from '@/i18n';
|
||||||
|
import { MYINFOMATE_LINKEDIN, softwareOffers } from '@/data/structured-data';
|
||||||
|
import translations from '@/data/translations';
|
||||||
import HomeClient from './HomeClient';
|
import HomeClient from './HomeClient';
|
||||||
|
|
||||||
const SITE_URL = 'https://myinfomate.be';
|
const SITE_URL = 'https://myinfomate.be';
|
||||||
@ -71,12 +73,26 @@ export default async function HomePage({ params }: { params: Promise<{ lang: str
|
|||||||
'@context': 'https://schema.org',
|
'@context': 'https://schema.org',
|
||||||
'@type': 'Organization',
|
'@type': 'Organization',
|
||||||
name: 'Unov',
|
name: 'Unov',
|
||||||
url: SITE_URL,
|
url: 'https://unov.be',
|
||||||
logo: `${SITE_URL}/myinfomate-logo.png`,
|
logo: `${SITE_URL}/myinfomate-logo.png`,
|
||||||
|
vatID: 'BE0776895467',
|
||||||
|
taxID: '0776.895.467',
|
||||||
|
address: {
|
||||||
|
'@type': 'PostalAddress',
|
||||||
|
streetAddress: 'Rue René Copette 3',
|
||||||
|
postalCode: '5020',
|
||||||
|
addressLocality: 'Namur',
|
||||||
|
addressRegion: 'Wallonie',
|
||||||
|
addressCountry: 'BE',
|
||||||
|
},
|
||||||
|
areaServed: ['BE', 'FR', 'LU'],
|
||||||
|
sameAs: ['https://www.linkedin.com/company/77631946/'],
|
||||||
contactPoint: {
|
contactPoint: {
|
||||||
'@type': 'ContactPoint',
|
'@type': 'ContactPoint',
|
||||||
email: 'contact@unov.be',
|
email: 'contact@unov.be',
|
||||||
|
telephone: '+32498079535',
|
||||||
contactType: 'customer support',
|
contactType: 'customer support',
|
||||||
|
availableLanguage: ['French', 'English', 'Dutch', 'German'],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -97,23 +113,25 @@ export default async function HomePage({ params }: { params: Promise<{ lang: str
|
|||||||
name: 'MyInfoMate',
|
name: 'MyInfoMate',
|
||||||
applicationCategory: 'BusinessApplication',
|
applicationCategory: 'BusinessApplication',
|
||||||
operatingSystem: 'iOS, Android, Web',
|
operatingSystem: 'iOS, Android, Web',
|
||||||
offers: {
|
offers: softwareOffers,
|
||||||
'@type': 'Offer',
|
sameAs: [MYINFOMATE_LINKEDIN],
|
||||||
price: '39',
|
|
||||||
priceCurrency: 'EUR',
|
|
||||||
priceSpecification: {
|
|
||||||
'@type': 'UnitPriceSpecification',
|
|
||||||
price: '39',
|
|
||||||
priceCurrency: 'EUR',
|
|
||||||
unitText: 'MONTH',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
description: META_BY_LOCALE[lang as Locale].description,
|
description: META_BY_LOCALE[lang as Locale].description,
|
||||||
url: `${SITE_URL}/${lang}`,
|
url: `${SITE_URL}/${lang}`,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const faqSchema = {
|
||||||
|
'@context': 'https://schema.org',
|
||||||
|
'@type': 'FAQPage',
|
||||||
|
mainEntity: translations[lang].homeFaq.items.map((item) => ({
|
||||||
|
'@type': 'Question',
|
||||||
|
name: item.question,
|
||||||
|
acceptedAnswer: { '@type': 'Answer', text: item.answer },
|
||||||
|
})),
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
<script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(faqSchema) }} />
|
||||||
<script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(organizationSchema) }} />
|
<script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(organizationSchema) }} />
|
||||||
<script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(websiteSchema) }} />
|
<script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(websiteSchema) }} />
|
||||||
<script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(softwareSchema) }} />
|
<script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(softwareSchema) }} />
|
||||||
|
|||||||
157
src/app/[lang]/ressources/[slug]/page.tsx
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
import type { Metadata } from 'next';
|
||||||
|
import Link from 'next/link';
|
||||||
|
import { notFound } from 'next/navigation';
|
||||||
|
import { isLocale } from '@/i18n';
|
||||||
|
import { getArticle, getAllArticleSlugs, getAllArticles } from '@/data/articles';
|
||||||
|
import { breadcrumbSchema } from '@/data/structured-data';
|
||||||
|
|
||||||
|
const SITE_URL = 'https://myinfomate.be';
|
||||||
|
const PATH = 'ressources';
|
||||||
|
|
||||||
|
export function generateStaticParams() {
|
||||||
|
return getAllArticleSlugs().map((slug) => ({ lang: 'fr', slug }));
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function generateMetadata({
|
||||||
|
params,
|
||||||
|
}: {
|
||||||
|
params: Promise<{ lang: string; slug: string }>;
|
||||||
|
}): Promise<Metadata> {
|
||||||
|
const { lang, slug } = await params;
|
||||||
|
const article = getArticle(slug);
|
||||||
|
if (lang !== 'fr' || !article) return {};
|
||||||
|
return {
|
||||||
|
title: `${article.title} | MyInfoMate`,
|
||||||
|
description: article.description,
|
||||||
|
openGraph: {
|
||||||
|
title: article.title,
|
||||||
|
description: article.description,
|
||||||
|
url: `${SITE_URL}/fr/${PATH}/${slug}`,
|
||||||
|
siteName: 'MyInfoMate',
|
||||||
|
locale: 'fr_BE',
|
||||||
|
type: 'article',
|
||||||
|
publishedTime: article.published,
|
||||||
|
},
|
||||||
|
alternates: { canonical: `/fr/${PATH}/${slug}` },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default async function ArticlePage({
|
||||||
|
params,
|
||||||
|
}: {
|
||||||
|
params: Promise<{ lang: string; slug: string }>;
|
||||||
|
}) {
|
||||||
|
const { lang, slug } = await params;
|
||||||
|
if (!isLocale(lang) || lang !== 'fr') notFound();
|
||||||
|
const article = getArticle(slug);
|
||||||
|
if (!article) notFound();
|
||||||
|
|
||||||
|
const others = getAllArticles().filter((item) => item.slug !== slug);
|
||||||
|
|
||||||
|
const articleSchema = {
|
||||||
|
'@context': 'https://schema.org',
|
||||||
|
'@type': 'BlogPosting',
|
||||||
|
headline: article.title,
|
||||||
|
description: article.description,
|
||||||
|
datePublished: article.published,
|
||||||
|
dateModified: article.published,
|
||||||
|
inLanguage: 'fr-BE',
|
||||||
|
author: { '@type': 'Organization', name: 'Unov', url: 'https://unov.be' },
|
||||||
|
publisher: { '@type': 'Organization', name: 'MyInfoMate', url: SITE_URL },
|
||||||
|
mainEntityOfPage: `${SITE_URL}/fr/${PATH}/${slug}`,
|
||||||
|
url: `${SITE_URL}/fr/${PATH}/${slug}`,
|
||||||
|
};
|
||||||
|
|
||||||
|
const breadcrumb = breadcrumbSchema([
|
||||||
|
{ name: 'MyInfoMate', path: '/fr' },
|
||||||
|
{ name: 'Ressources', path: `/fr/${PATH}` },
|
||||||
|
{ name: article.title, path: `/fr/${PATH}/${slug}` },
|
||||||
|
]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<main className="bg-white text-slate-900 min-h-screen font-display">
|
||||||
|
<script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(breadcrumb) }} />
|
||||||
|
<script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(articleSchema) }} />
|
||||||
|
|
||||||
|
<header className="fixed top-0 left-0 right-0 z-50 bg-white/80 backdrop-blur-md border-b border-slate-200">
|
||||||
|
<div className="max-w-7xl mx-auto px-6 h-16 flex items-center gap-4">
|
||||||
|
<Link href={`/fr/${PATH}`} className="flex items-center gap-2 text-sm font-bold text-slate-600 hover:text-primary transition-colors">
|
||||||
|
<span className="material-symbols-outlined text-base">arrow_back</span>
|
||||||
|
Toutes les ressources
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<article className="pt-16">
|
||||||
|
<div className="max-w-3xl mx-auto px-6 py-16">
|
||||||
|
<div className="flex items-center gap-3 mb-6 text-xs text-slate-400 font-semibold">
|
||||||
|
<time dateTime={article.published}>
|
||||||
|
{new Date(article.published).toLocaleDateString('fr-BE', { day: 'numeric', month: 'long', year: 'numeric' })}
|
||||||
|
</time>
|
||||||
|
<span>·</span>
|
||||||
|
<span>{article.readingMinutes} min de lecture</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h1 className="text-3xl lg:text-5xl font-extrabold text-slate-900 leading-tight mb-8">{article.title}</h1>
|
||||||
|
<p className="text-lg text-slate-600 leading-relaxed mb-12">{article.intro}</p>
|
||||||
|
|
||||||
|
{article.sections.map((section) => (
|
||||||
|
<section key={section.title} className="mb-10">
|
||||||
|
<h2 className="text-2xl font-extrabold text-slate-900 mb-4">{section.title}</h2>
|
||||||
|
{section.paragraphs.map((paragraph) => (
|
||||||
|
<p key={paragraph.slice(0, 40)} className="text-slate-600 leading-relaxed mb-4">
|
||||||
|
{paragraph}
|
||||||
|
</p>
|
||||||
|
))}
|
||||||
|
{section.list && (
|
||||||
|
<ul className="space-y-3 mt-6">
|
||||||
|
{section.list.map((item) => (
|
||||||
|
<li key={item} className="flex items-start gap-3 text-slate-700">
|
||||||
|
<span className="material-symbols-outlined text-primary shrink-0">check_circle</span>
|
||||||
|
{item}
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
)}
|
||||||
|
</section>
|
||||||
|
))}
|
||||||
|
|
||||||
|
<p className="text-slate-600 leading-relaxed bg-slate-50 border border-slate-100 rounded-2xl p-6">
|
||||||
|
{article.closing}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div className="mt-12 flex flex-col sm:flex-row gap-4">
|
||||||
|
<Link
|
||||||
|
href="/fr#contact"
|
||||||
|
className="inline-flex items-center justify-center gap-2 px-8 py-4 bg-primary text-slate-900 font-extrabold rounded-full shadow-lg shadow-primary/20 hover:brightness-110 transition-all"
|
||||||
|
>
|
||||||
|
Demander une démo gratuite
|
||||||
|
<span className="material-symbols-outlined">arrow_forward</span>
|
||||||
|
</Link>
|
||||||
|
<Link
|
||||||
|
href="/fr/tarifs"
|
||||||
|
className="inline-flex items-center justify-center gap-2 px-8 py-4 bg-white border-2 border-slate-200 text-slate-700 font-bold rounded-full hover:border-primary hover:text-primary transition-all"
|
||||||
|
>
|
||||||
|
Voir les tarifs
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{others.length > 0 && (
|
||||||
|
<aside className="mt-16 pt-10 border-t border-slate-100">
|
||||||
|
<h2 className="text-sm font-extrabold text-slate-400 uppercase tracking-widest mb-6">À lire aussi</h2>
|
||||||
|
<ul className="space-y-4">
|
||||||
|
{others.map((other) => (
|
||||||
|
<li key={other.slug}>
|
||||||
|
<Link href={`/fr/${PATH}/${other.slug}`} className="text-lg font-bold text-slate-900 hover:text-primary transition-colors">
|
||||||
|
{other.title}
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</aside>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
}
|
||||||
101
src/app/[lang]/ressources/page.tsx
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
import type { Metadata } from 'next';
|
||||||
|
import Link from 'next/link';
|
||||||
|
import { notFound } from 'next/navigation';
|
||||||
|
import { isLocale } from '@/i18n';
|
||||||
|
import { getAllArticles } from '@/data/articles';
|
||||||
|
import { breadcrumbSchema } from '@/data/structured-data';
|
||||||
|
|
||||||
|
const PATH = 'ressources';
|
||||||
|
|
||||||
|
// Blog en français uniquement pour l'instant.
|
||||||
|
export function generateStaticParams() {
|
||||||
|
return [{ lang: 'fr' }];
|
||||||
|
}
|
||||||
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
title: 'Ressources — médiation numérique et expérience visiteur | MyInfoMate',
|
||||||
|
description: "Articles pratiques pour les musées, offices de tourisme et sites patrimoniaux : audioguide ou application, borne ou smartphone, mode hors ligne, RGPD.",
|
||||||
|
alternates: { canonical: '/fr/ressources' },
|
||||||
|
};
|
||||||
|
|
||||||
|
export default async function RessourcesPage({ params }: { params: Promise<{ lang: string }> }) {
|
||||||
|
const { lang } = await params;
|
||||||
|
if (!isLocale(lang) || lang !== 'fr') notFound();
|
||||||
|
|
||||||
|
const articles = getAllArticles();
|
||||||
|
const breadcrumb = breadcrumbSchema([
|
||||||
|
{ name: 'MyInfoMate', path: '/fr' },
|
||||||
|
{ name: 'Ressources', path: `/fr/${PATH}` },
|
||||||
|
]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<main className="bg-slate-50 text-slate-900 min-h-screen font-display">
|
||||||
|
<script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(breadcrumb) }} />
|
||||||
|
|
||||||
|
<header className="fixed top-0 left-0 right-0 z-50 bg-white/80 backdrop-blur-md border-b border-slate-200">
|
||||||
|
<div className="max-w-7xl mx-auto px-6 h-16 flex items-center gap-4">
|
||||||
|
<Link href="/fr" className="flex items-center gap-2 text-sm font-bold text-slate-600 hover:text-primary transition-colors">
|
||||||
|
<span className="material-symbols-outlined text-base">arrow_back</span>
|
||||||
|
Retour à l'accueil
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div className="pt-16">
|
||||||
|
<section className="py-20 lg:py-24 bg-white border-b border-slate-100">
|
||||||
|
<div className="max-w-4xl mx-auto px-6 text-center">
|
||||||
|
<div className="inline-flex items-center gap-2 px-4 py-2 rounded-full bg-primary/10 border border-primary/20 text-slate-700 text-xs font-bold uppercase tracking-wider mb-6">
|
||||||
|
<span className="w-2 h-2 rounded-full bg-primary"></span>
|
||||||
|
Ressources
|
||||||
|
</div>
|
||||||
|
<h1 className="text-4xl lg:text-6xl font-extrabold text-slate-900 leading-[1.1] mb-6">
|
||||||
|
Comprendre avant de choisir
|
||||||
|
</h1>
|
||||||
|
<p className="text-lg text-slate-500 max-w-2xl mx-auto">
|
||||||
|
Des articles écrits pour les équipes de musées, d'offices de tourisme et de sites patrimoniaux qui
|
||||||
|
doivent trancher des questions concrètes — sans jargon, et sans faire semblant que la réponse est toujours
|
||||||
|
la nôtre.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section className="py-20">
|
||||||
|
<div className="max-w-3xl mx-auto px-6 flex flex-col gap-8">
|
||||||
|
{articles.map((article) => (
|
||||||
|
<Link
|
||||||
|
key={article.slug}
|
||||||
|
href={`/fr/${PATH}/${article.slug}`}
|
||||||
|
className="group bg-white rounded-3xl border border-slate-100 p-8 hover:border-primary/30 hover:shadow-xl hover:shadow-primary/5 transition-all"
|
||||||
|
>
|
||||||
|
<div className="flex items-center gap-3 mb-4 text-xs text-slate-400 font-semibold">
|
||||||
|
<time dateTime={article.published}>
|
||||||
|
{new Date(article.published).toLocaleDateString('fr-BE', { day: 'numeric', month: 'long', year: 'numeric' })}
|
||||||
|
</time>
|
||||||
|
<span>·</span>
|
||||||
|
<span>{article.readingMinutes} min de lecture</span>
|
||||||
|
</div>
|
||||||
|
<h2 className="text-2xl font-extrabold text-slate-900 mb-3 group-hover:text-primary transition-colors">
|
||||||
|
{article.title}
|
||||||
|
</h2>
|
||||||
|
<p className="text-slate-500 leading-relaxed">{article.description}</p>
|
||||||
|
</Link>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section className="py-16 bg-slate-900 text-center">
|
||||||
|
<div className="max-w-2xl mx-auto px-6">
|
||||||
|
<h2 className="text-2xl lg:text-3xl font-extrabold text-white mb-4">Une question sur votre projet ?</h2>
|
||||||
|
<Link
|
||||||
|
href="/fr#contact"
|
||||||
|
className="inline-flex items-center gap-2 mt-6 px-8 py-4 bg-primary text-slate-900 font-extrabold rounded-full shadow-xl shadow-primary/30 hover:brightness-110 transition-all"
|
||||||
|
>
|
||||||
|
Demander une démo gratuite
|
||||||
|
<span className="material-symbols-outlined">arrow_forward</span>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -1,6 +1,7 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useEffect, useRef, useState } from 'react';
|
import { useEffect, useRef, useState } from 'react';
|
||||||
|
import Link from 'next/link';
|
||||||
import translations, { Language } from '@/data/translations';
|
import translations, { Language } from '@/data/translations';
|
||||||
|
|
||||||
const API_BASE = process.env.NEXT_PUBLIC_MANAGER_SERVICE_URL ?? '';
|
const API_BASE = process.env.NEXT_PUBLIC_MANAGER_SERVICE_URL ?? '';
|
||||||
@ -412,9 +413,9 @@ export default function SignupClient({ lang }: { lang: Language }) {
|
|||||||
className="w-5 h-5 mt-0.5 flex-none accent-primary rounded cursor-pointer" />
|
className="w-5 h-5 mt-0.5 flex-none accent-primary rounded cursor-pointer" />
|
||||||
<span>
|
<span>
|
||||||
{t.consentPrefix}{' '}
|
{t.consentPrefix}{' '}
|
||||||
<a href={`/${lang}#`} className="text-primary font-bold hover:underline">{t.consentTerms}</a>{' '}
|
<Link href={`/${lang}/conditions-generales`} className="text-primary font-bold hover:underline">{t.consentTerms}</Link>{' '}
|
||||||
{t.consentAnd}{' '}
|
{t.consentAnd}{' '}
|
||||||
<a href="/confidentialite" className="text-primary font-bold hover:underline">{t.consentPrivacy}</a>{' '}
|
<Link href={`/${lang}/confidentialite`} className="text-primary font-bold hover:underline">{t.consentPrivacy}</Link>{' '}
|
||||||
{t.consentSuffix}
|
{t.consentSuffix}
|
||||||
</span>
|
</span>
|
||||||
</label>
|
</label>
|
||||||
|
|||||||
345
src/app/[lang]/tarifs/page.tsx
Normal file
@ -0,0 +1,345 @@
|
|||||||
|
import type { Metadata } from 'next';
|
||||||
|
import Link from 'next/link';
|
||||||
|
import { notFound } from 'next/navigation';
|
||||||
|
import { LOCALES, LOCALE_HTML_LANG, LOCALE_OG, DEFAULT_LOCALE, isLocale, type Locale } from '@/i18n';
|
||||||
|
import { MYINFOMATE_LINKEDIN, breadcrumbSchema, softwareOffers } from '@/data/structured-data';
|
||||||
|
import PricingPlans from '@/components/PricingPlans';
|
||||||
|
|
||||||
|
const SITE_URL = 'https://myinfomate.be';
|
||||||
|
|
||||||
|
type PageText = {
|
||||||
|
meta: { title: string; description: string };
|
||||||
|
back: string;
|
||||||
|
badge: string;
|
||||||
|
h1: string;
|
||||||
|
subtitle: string;
|
||||||
|
faqTitle: string;
|
||||||
|
faq: { question: string; answer: string }[];
|
||||||
|
publicNote: string;
|
||||||
|
publicLink: string;
|
||||||
|
ctaTitle: string;
|
||||||
|
ctaButton: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const TEXT_BY_LOCALE: Record<Locale, PageText> = {
|
||||||
|
fr: {
|
||||||
|
meta: {
|
||||||
|
title: 'Tarifs MyInfoMate — Application guide de visite dès 39 €/mois',
|
||||||
|
description: 'Prix publics de MyInfoMate : Essentiel 39 €, Pro 99 €, Premium 179 € par mois HTVA. Application web, app mobile à votre marque, mode hors ligne, assistant IA.',
|
||||||
|
},
|
||||||
|
back: "Retour à l'accueil",
|
||||||
|
badge: 'Tarifs',
|
||||||
|
h1: 'Tarifs MyInfoMate : un plan pour chaque lieu',
|
||||||
|
subtitle: 'Application web, application mobile à votre marque, assistant IA : choisissez ce dont votre lieu a besoin. Prix mensuels hors TVA, affichés publiquement pour que vous puissiez budgéter avant même de nous appeler.',
|
||||||
|
faqTitle: 'Questions fréquentes sur les tarifs',
|
||||||
|
faq: [
|
||||||
|
{
|
||||||
|
question: 'Combien coûte une application guide de visite MyInfoMate ?',
|
||||||
|
answer: "MyInfoMate propose trois plans publics, en prix mensuels hors TVA : Essentiel à 39 €/mois (application web visiteur et mode borne), Pro à 99 €/mois (ajoute votre propre application mobile sur l'App Store et Google Play, le mode hors ligne et les notifications push) et Premium à 179 €/mois (ajoute l'assistant IA visiteur et la traduction automatique). Les organisations multi-sites ou aux besoins spécifiques bénéficient d'un devis Enterprise.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Que comprennent tous les plans ?',
|
||||||
|
answer: "Tous les plans comprennent le back-office pour gérer vos contenus sans code, toutes les sections de contenu (cartes, audio, vidéo, quiz, agenda, articles…), l'interface visiteur web et le mode borne tablette. Ce qui change d'un plan à l'autre : l'application mobile native, le mode hors ligne, l'assistant IA, le stockage et le niveau de statistiques.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Y a-t-il un engagement ?',
|
||||||
|
answer: "Le plan Essentiel est sans engagement et résiliable à tout moment. Les plans Pro et Premium, qui incluent la publication d'une application mobile à votre nom sur les stores, comportent un engagement de 12 mois et des frais de mise en place uniques. Ces frais couvrent la configuration et la publication sur l'App Store et Google Play ; ils sont chiffrés dans le devis, avant toute signature.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Puis-je essayer MyInfoMate gratuitement ?',
|
||||||
|
answer: "Oui : le plan Essentiel s'essaie gratuitement pendant 14 jours, sans carte bancaire. Vous créez votre espace, construisez votre première visite et la partagez par QR code. Pour les plans Pro et Premium, nous organisons une démonstration sur vos propres contenus.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: "Quel plan inclut l'assistant IA ?",
|
||||||
|
answer: "L'assistant IA visiteur est inclus dans le plan Premium, avec environ 2 000 questions de visiteurs par mois. Au-delà, le plan Enterprise permet de fixer un quota sur mesure.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Les prix sont-ils hors TVA ?',
|
||||||
|
answer: "Oui, tous les prix sont indiqués hors TVA. La TVA belge de 21 % s'applique ; une organisation établie dans un autre pays de l'Union européenne et disposant d'un numéro de TVA valide est facturée sans TVA (autoliquidation intracommunautaire).",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Proposez-vous des contrats pluriannuels ?',
|
||||||
|
answer: "Oui. Nous proposons des engagements de 2 ou 3 ans, avec facturation annuelle et un tarif préférentiel — pratique lorsque le projet est financé par un subside ou un budget pluriannuel.",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
publicNote: "Vous achetez pour une commune, une province, un musée public ou un office du tourisme ?",
|
||||||
|
publicLink: "Voir la page marchés publics",
|
||||||
|
ctaTitle: 'Un doute sur le plan qui vous convient ?',
|
||||||
|
ctaButton: 'Demander une démo gratuite',
|
||||||
|
},
|
||||||
|
en: {
|
||||||
|
meta: {
|
||||||
|
title: 'MyInfoMate Pricing — Visitor Guide App from €39/month',
|
||||||
|
description: 'Public MyInfoMate pricing: Essential €39, Pro €99, Premium €179 per month excl. VAT. Web app, your own branded mobile app, offline mode, AI assistant.',
|
||||||
|
},
|
||||||
|
back: 'Back to home',
|
||||||
|
badge: 'Pricing',
|
||||||
|
h1: 'MyInfoMate pricing: a plan for every venue',
|
||||||
|
subtitle: 'Web app, your own branded mobile app, AI assistant: pick what your venue needs. Monthly prices excluding VAT, published openly so you can budget before you even call us.',
|
||||||
|
faqTitle: 'Pricing FAQ',
|
||||||
|
faq: [
|
||||||
|
{
|
||||||
|
question: 'How much does a MyInfoMate visitor guide app cost?',
|
||||||
|
answer: 'MyInfoMate offers three public plans, monthly prices excluding VAT: Essential at €39/month (visitor web app and kiosk mode), Pro at €99/month (adds your own mobile app on the App Store and Google Play, offline mode and push notifications) and Premium at €179/month (adds the AI visitor assistant and automatic translation). Multi-site organisations or specific needs get an Enterprise quote.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'What do all plans include?',
|
||||||
|
answer: 'Every plan includes the back-office to manage your content without code, all content sections (maps, audio, video, quizzes, agenda, articles…), the visitor web interface and tablet kiosk mode. What changes between plans: the native mobile app, offline mode, the AI assistant, storage and the level of statistics.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Is there a commitment?',
|
||||||
|
answer: 'The Essential plan has no commitment and can be cancelled at any time. The Pro and Premium plans, which include publishing a mobile app under your name on the stores, come with a 12-month commitment and a one-off setup fee. That fee covers configuration and publishing on the App Store and Google Play; it is quoted before you sign anything.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Can I try MyInfoMate for free?',
|
||||||
|
answer: 'Yes: the Essential plan comes with a 14-day free trial, no credit card required. You create your space, build your first tour and share it with a QR code. For Pro and Premium, we run a demo on your own content.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Which plan includes the AI assistant?',
|
||||||
|
answer: 'The AI visitor assistant is included in the Premium plan, with around 2,000 visitor questions per month. Beyond that, the Enterprise plan allows a custom quota.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Are prices excluding VAT?',
|
||||||
|
answer: 'Yes, all prices are shown excluding VAT. Belgian VAT at 21% applies; an organisation based in another EU country with a valid VAT number is invoiced without VAT (intra-community reverse charge).',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Do you offer multi-year contracts?',
|
||||||
|
answer: 'Yes. We offer 2- or 3-year commitments with annual billing and a preferential rate — convenient when the project is funded by a grant or a multi-year budget.',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
publicNote: "Buying for a municipality, a province, a public museum or a tourism office?",
|
||||||
|
publicLink: "See the public procurement page",
|
||||||
|
ctaTitle: 'Not sure which plan fits?',
|
||||||
|
ctaButton: 'Request a free demo',
|
||||||
|
},
|
||||||
|
nl: {
|
||||||
|
meta: {
|
||||||
|
title: 'MyInfoMate Tarieven — Bezoekersgids-app vanaf €39/maand',
|
||||||
|
description: 'Publieke tarieven van MyInfoMate: Essentieel €39, Pro €99, Premium €179 per maand excl. btw. Web-app, eigen mobiele app, offline modus, AI-assistent.',
|
||||||
|
},
|
||||||
|
back: 'Terug naar home',
|
||||||
|
badge: 'Tarieven',
|
||||||
|
h1: 'MyInfoMate-tarieven: een abonnement voor elke locatie',
|
||||||
|
subtitle: 'Web-app, uw eigen mobiele app, AI-assistent: kies wat uw locatie nodig heeft. Maandprijzen exclusief btw, publiek vermeld zodat u kunt budgetteren nog voor u ons belt.',
|
||||||
|
faqTitle: 'Veelgestelde vragen over de tarieven',
|
||||||
|
faq: [
|
||||||
|
{
|
||||||
|
question: 'Hoeveel kost een MyInfoMate-bezoekersgids-app?',
|
||||||
|
answer: 'MyInfoMate biedt drie publieke abonnementen, maandprijzen exclusief btw: Essentieel aan €39/maand (web-app voor bezoekers en kioskmodus), Pro aan €99/maand (voegt uw eigen mobiele app in de App Store en Google Play toe, offline modus en pushmeldingen) en Premium aan €179/maand (voegt de AI-bezoekersassistent en automatische vertaling toe). Organisaties met meerdere sites of specifieke noden krijgen een Enterprise-offerte.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Wat zit er in elk abonnement?',
|
||||||
|
answer: 'Elk abonnement omvat de back-office om uw inhoud zonder code te beheren, alle inhoudssecties (kaarten, audio, video, quiz, agenda, artikels…), de webinterface voor bezoekers en de tabletkioskmodus. Wat verschilt tussen de abonnementen: de native mobiele app, de offline modus, de AI-assistent, de opslag en het niveau van statistieken.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Is er een verbintenis?',
|
||||||
|
answer: 'Het Essentieel-abonnement is zonder verbintenis en op elk moment opzegbaar. De Pro- en Premium-abonnementen, die de publicatie van een mobiele app op uw naam in de stores omvatten, hebben een verbintenis van 12 maanden en eenmalige opstartkosten. Die kosten dekken de configuratie en de publicatie in de App Store en Google Play; ze staan in de offerte, voor u iets ondertekent.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Kan ik MyInfoMate gratis uitproberen?',
|
||||||
|
answer: 'Ja: het Essentieel-abonnement kunt u 14 dagen gratis uitproberen, zonder kredietkaart. U maakt uw ruimte aan, bouwt uw eerste bezoek en deelt het via een QR-code. Voor Pro en Premium geven we een demo met uw eigen inhoud.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Welk abonnement bevat de AI-assistent?',
|
||||||
|
answer: 'De AI-bezoekersassistent zit in het Premium-abonnement, met ongeveer 2.000 bezoekersvragen per maand. Daarboven laat het Enterprise-abonnement een quotum op maat toe.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Zijn de prijzen exclusief btw?',
|
||||||
|
answer: 'Ja, alle prijzen zijn exclusief btw. De Belgische btw van 21% is van toepassing; een organisatie gevestigd in een ander EU-land met een geldig btw-nummer wordt zonder btw gefactureerd (intracommunautaire verlegging).',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Bieden jullie meerjarige contracten aan?',
|
||||||
|
answer: 'Ja. We bieden verbintenissen van 2 of 3 jaar aan, met jaarlijkse facturatie en een voordeliger tarief — handig wanneer het project gefinancierd wordt met een subsidie of een meerjarig budget.',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
publicNote: "Koopt u aan voor een gemeente, een provincie, een openbaar museum of een toerismekantoor?",
|
||||||
|
publicLink: "Bekijk de pagina overheidsopdrachten",
|
||||||
|
ctaTitle: 'Twijfelt u welk abonnement past?',
|
||||||
|
ctaButton: 'Gratis demo aanvragen',
|
||||||
|
},
|
||||||
|
de: {
|
||||||
|
meta: {
|
||||||
|
title: 'MyInfoMate Preise — Besucherguide-App ab 39 €/Monat',
|
||||||
|
description: 'Öffentliche MyInfoMate-Preise: Essential 39 €, Pro 99 €, Premium 179 € pro Monat zzgl. MwSt. Web-App, eigene Mobile App, Offline-Modus, KI-Assistent.',
|
||||||
|
},
|
||||||
|
back: 'Zurück zur Startseite',
|
||||||
|
badge: 'Preise',
|
||||||
|
h1: 'MyInfoMate-Preise: ein Plan für jeden Ort',
|
||||||
|
subtitle: 'Web-App, Ihre eigene Mobile App, KI-Assistent: Wählen Sie, was Ihr Ort braucht. Monatspreise zzgl. MwSt., öffentlich angegeben, damit Sie planen können, bevor Sie uns anrufen.',
|
||||||
|
faqTitle: 'Häufige Fragen zu den Preisen',
|
||||||
|
faq: [
|
||||||
|
{
|
||||||
|
question: 'Was kostet eine MyInfoMate-Besucherguide-App?',
|
||||||
|
answer: 'MyInfoMate bietet drei öffentliche Pläne, Monatspreise zzgl. MwSt.: Essential für 39 €/Monat (Besucher-Web-App und Kiosk-Modus), Pro für 99 €/Monat (dazu Ihre eigene Mobile App im App Store und bei Google Play, Offline-Modus und Push-Benachrichtigungen) und Premium für 179 €/Monat (dazu der KI-Besucherassistent und die automatische Übersetzung). Organisationen mit mehreren Standorten oder besonderen Anforderungen erhalten ein Enterprise-Angebot.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Was ist in allen Plänen enthalten?',
|
||||||
|
answer: 'Jeder Plan umfasst das Back-Office zur Verwaltung Ihrer Inhalte ohne Code, alle Inhaltsbereiche (Karten, Audio, Video, Quiz, Agenda, Artikel…), die Web-Oberfläche für Besucher und den Tablet-Kiosk-Modus. Was sich zwischen den Plänen ändert: die native Mobile App, der Offline-Modus, der KI-Assistent, der Speicherplatz und der Umfang der Statistiken.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Gibt es eine Mindestlaufzeit?',
|
||||||
|
answer: 'Der Essential-Plan hat keine Mindestlaufzeit und ist jederzeit kündbar. Die Pläne Pro und Premium, die die Veröffentlichung einer Mobile App unter Ihrem Namen in den Stores umfassen, beinhalten eine Laufzeit von 12 Monaten und eine einmalige Einrichtungsgebühr. Diese Gebühr deckt die Konfiguration und die Veröffentlichung im App Store und bei Google Play ab; sie wird im Angebot ausgewiesen, bevor Sie etwas unterschreiben.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Kann ich MyInfoMate kostenlos testen?',
|
||||||
|
answer: 'Ja: Den Essential-Plan können Sie 14 Tage kostenlos testen, ohne Kreditkarte. Sie legen Ihren Bereich an, erstellen Ihre erste Tour und teilen sie per QR-Code. Für Pro und Premium zeigen wir Ihnen eine Demo mit Ihren eigenen Inhalten.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Welcher Plan enthält den KI-Assistenten?',
|
||||||
|
answer: 'Der KI-Besucherassistent ist im Premium-Plan enthalten, mit rund 2.000 Besucherfragen pro Monat. Darüber hinaus ermöglicht der Enterprise-Plan ein individuelles Kontingent.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Verstehen sich die Preise zzgl. MwSt.?',
|
||||||
|
answer: 'Ja, alle Preise verstehen sich zzgl. MwSt. Es gilt die belgische MwSt. von 21 %; eine Organisation mit Sitz in einem anderen EU-Land und gültiger USt-IdNr. wird ohne MwSt. abgerechnet (innergemeinschaftliches Reverse-Charge-Verfahren).',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Bieten Sie mehrjährige Verträge an?',
|
||||||
|
answer: 'Ja. Wir bieten Laufzeiten von 2 oder 3 Jahren mit jährlicher Abrechnung und Vorzugspreis an — praktisch, wenn das Projekt über eine Förderung oder ein mehrjähriges Budget finanziert wird.',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
publicNote: "Beschaffen Sie für eine Gemeinde, eine Provinz, ein öffentliches Museum oder ein Tourismusbüro?",
|
||||||
|
publicLink: "Zur Seite öffentliche Aufträge",
|
||||||
|
ctaTitle: 'Unsicher, welcher Plan passt?',
|
||||||
|
ctaButton: 'Kostenlose Demo anfordern',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export function generateStaticParams() {
|
||||||
|
return LOCALES.map((lang) => ({ lang }));
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function generateMetadata({
|
||||||
|
params,
|
||||||
|
}: {
|
||||||
|
params: Promise<{ lang: string }>;
|
||||||
|
}): Promise<Metadata> {
|
||||||
|
const { lang } = await params;
|
||||||
|
if (!isLocale(lang)) return {};
|
||||||
|
const m = TEXT_BY_LOCALE[lang].meta;
|
||||||
|
const languages = Object.fromEntries(LOCALES.map((l) => [LOCALE_HTML_LANG[l], `/${l}/tarifs`]));
|
||||||
|
return {
|
||||||
|
title: m.title,
|
||||||
|
description: m.description,
|
||||||
|
openGraph: {
|
||||||
|
title: m.title,
|
||||||
|
description: m.description,
|
||||||
|
url: `${SITE_URL}/${lang}/tarifs`,
|
||||||
|
siteName: 'MyInfoMate',
|
||||||
|
locale: LOCALE_OG[lang],
|
||||||
|
type: 'website',
|
||||||
|
},
|
||||||
|
alternates: {
|
||||||
|
canonical: `/${lang}/tarifs`,
|
||||||
|
languages: { ...languages, 'x-default': `/${DEFAULT_LOCALE}/tarifs` },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default async function TarifsPage({ params }: { params: Promise<{ lang: string }> }) {
|
||||||
|
const { lang } = await params;
|
||||||
|
if (!isLocale(lang)) notFound();
|
||||||
|
const text = TEXT_BY_LOCALE[lang];
|
||||||
|
|
||||||
|
const faqSchema = {
|
||||||
|
'@context': 'https://schema.org',
|
||||||
|
'@type': 'FAQPage',
|
||||||
|
mainEntity: text.faq.map((item) => ({
|
||||||
|
'@type': 'Question',
|
||||||
|
name: item.question,
|
||||||
|
acceptedAnswer: { '@type': 'Answer', text: item.answer },
|
||||||
|
})),
|
||||||
|
};
|
||||||
|
|
||||||
|
const softwareSchema = {
|
||||||
|
'@context': 'https://schema.org',
|
||||||
|
'@type': 'SoftwareApplication',
|
||||||
|
name: 'MyInfoMate',
|
||||||
|
applicationCategory: 'BusinessApplication',
|
||||||
|
operatingSystem: 'iOS, Android, Web',
|
||||||
|
offers: softwareOffers,
|
||||||
|
sameAs: [MYINFOMATE_LINKEDIN],
|
||||||
|
description: text.meta.description,
|
||||||
|
url: `${SITE_URL}/${lang}/tarifs`,
|
||||||
|
};
|
||||||
|
|
||||||
|
const breadcrumb = breadcrumbSchema([
|
||||||
|
{ name: 'MyInfoMate', path: `/${lang}` },
|
||||||
|
{ name: text.badge, path: `/${lang}/tarifs` },
|
||||||
|
]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<main className="bg-slate-50 text-slate-900 min-h-screen font-display">
|
||||||
|
<script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(breadcrumb) }} />
|
||||||
|
<script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(faqSchema) }} />
|
||||||
|
<script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(softwareSchema) }} />
|
||||||
|
|
||||||
|
<header className="fixed top-0 left-0 right-0 z-50 bg-white/80 backdrop-blur-md border-b border-slate-200">
|
||||||
|
<div className="max-w-7xl mx-auto px-6 h-16 flex items-center gap-4">
|
||||||
|
<a href={`/${lang}`} className="flex items-center gap-2 text-sm font-bold text-slate-600 hover:text-primary transition-colors">
|
||||||
|
<span className="material-symbols-outlined text-base">arrow_back</span>
|
||||||
|
{text.back}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div className="pt-16">
|
||||||
|
<section className="py-20 lg:py-24 bg-white border-b border-slate-100">
|
||||||
|
<div className="max-w-4xl mx-auto px-6 text-center">
|
||||||
|
<div className="inline-flex items-center gap-2 px-4 py-2 rounded-full bg-primary/10 border border-primary/20 text-slate-700 text-xs font-bold uppercase tracking-wider mb-6">
|
||||||
|
<span className="w-2 h-2 rounded-full bg-primary"></span>
|
||||||
|
{text.badge}
|
||||||
|
</div>
|
||||||
|
<h1 className="text-4xl lg:text-6xl font-extrabold text-slate-900 leading-[1.1] mb-6">{text.h1}</h1>
|
||||||
|
<p className="text-lg text-slate-500 max-w-2xl mx-auto">{text.subtitle}</p>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section className="py-20" id="pricing">
|
||||||
|
<div className="max-w-7xl mx-auto px-6">
|
||||||
|
<PricingPlans lang={lang} contactHref={`/${lang}#contact`} />
|
||||||
|
<div className="mt-8 flex flex-col sm:flex-row items-center justify-between gap-4 bg-white rounded-2xl border border-slate-200 px-8 py-6">
|
||||||
|
<p className="text-slate-600 text-sm">{text.publicNote}</p>
|
||||||
|
<Link
|
||||||
|
href={`/${lang}/marches-publics`}
|
||||||
|
className="shrink-0 inline-flex items-center gap-1 text-primary font-bold text-sm hover:gap-2 transition-all"
|
||||||
|
>
|
||||||
|
{text.publicLink}
|
||||||
|
<span className="material-symbols-outlined text-base">arrow_forward</span>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section className="py-20 bg-white">
|
||||||
|
<div className="max-w-3xl mx-auto px-6">
|
||||||
|
<h2 className="text-3xl lg:text-4xl font-extrabold text-slate-900 text-center mb-12">{text.faqTitle}</h2>
|
||||||
|
<div className="space-y-4">
|
||||||
|
{text.faq.map((item) => (
|
||||||
|
<details key={item.question} className="group bg-slate-50 rounded-2xl border border-slate-100 p-6">
|
||||||
|
<summary className="flex items-center justify-between gap-4 cursor-pointer list-none">
|
||||||
|
<h3 className="font-extrabold text-slate-900">{item.question}</h3>
|
||||||
|
<span className="material-symbols-outlined text-slate-400 transition-transform group-open:rotate-180">expand_more</span>
|
||||||
|
</summary>
|
||||||
|
<p className="text-slate-600 leading-relaxed mt-4">{item.answer}</p>
|
||||||
|
</details>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section className="py-16 bg-slate-900 text-center">
|
||||||
|
<div className="max-w-2xl mx-auto px-6">
|
||||||
|
<h2 className="text-2xl lg:text-3xl font-extrabold text-white mb-4">{text.ctaTitle}</h2>
|
||||||
|
<a
|
||||||
|
href={`/${lang}#contact`}
|
||||||
|
className="inline-flex items-center gap-2 mt-6 px-8 py-4 bg-primary text-slate-900 font-extrabold rounded-full shadow-xl shadow-primary/30 hover:brightness-110 transition-all"
|
||||||
|
>
|
||||||
|
{text.ctaButton}
|
||||||
|
<span className="material-symbols-outlined">arrow_forward</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
}
|
||||||
311
src/app/[lang]/visite-hors-ligne/page.tsx
Normal file
@ -0,0 +1,311 @@
|
|||||||
|
import type { Metadata } from 'next';
|
||||||
|
import { notFound } from 'next/navigation';
|
||||||
|
import { LOCALES, LOCALE_HTML_LANG, LOCALE_OG, DEFAULT_LOCALE, isLocale, type Locale } from '@/i18n';
|
||||||
|
import { MYINFOMATE_LINKEDIN, breadcrumbSchema, softwareOffers } from '@/data/structured-data';
|
||||||
|
import ContentPage, { type ContentPageText } from '@/components/ContentPage';
|
||||||
|
|
||||||
|
const SITE_URL = 'https://myinfomate.be';
|
||||||
|
const PATH = 'visite-hors-ligne';
|
||||||
|
|
||||||
|
const META: Record<Locale, { title: string; description: string }> = {
|
||||||
|
fr: {
|
||||||
|
title: 'Visite guidée hors ligne, sans réseau | MyInfoMate',
|
||||||
|
description: "Audioguide et parcours qui fonctionnent sans 4G ni Wi-Fi : contenus téléchargés à l'entrée, balises BLE et codes QR. Éprouvé dans un fort souterrain.",
|
||||||
|
},
|
||||||
|
en: {
|
||||||
|
title: 'Offline Guided Visit, No Network Needed | MyInfoMate',
|
||||||
|
description: 'Audio guide and trails that work with no 4G or Wi-Fi: content downloaded at the entrance, BLE beacons and QR codes. Proven in an underground fort.',
|
||||||
|
},
|
||||||
|
nl: {
|
||||||
|
title: 'Offline bezoek, zonder netwerk | MyInfoMate',
|
||||||
|
description: 'Audiogids en parcours die werken zonder 4G of wifi: inhoud gedownload aan de ingang, BLE-bakens en QR-codes. Bewezen in een ondergronds fort.',
|
||||||
|
},
|
||||||
|
de: {
|
||||||
|
title: 'Offline-Besuch, ganz ohne Netz | MyInfoMate',
|
||||||
|
description: 'Audioguide und Rundgänge ohne 4G und WLAN: Inhalte am Eingang geladen, BLE-Beacons und QR-Codes. Erprobt in einem unterirdischen Fort.',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const TEXT: Record<Locale, ContentPageText> = {
|
||||||
|
fr: {
|
||||||
|
back: "Retour à l'accueil",
|
||||||
|
badge: 'Mode hors ligne',
|
||||||
|
h1Before: 'Une visite qui continue ',
|
||||||
|
h1Highlight: 'là où le réseau s\'arrête',
|
||||||
|
intro: "Caves, forts, carrières, sentiers en forêt, bâtiments classés aux murs épais : beaucoup de lieux ne captent pas. Le mode hors ligne de MyInfoMate télécharge la visite à l'entrée, puis fonctionne sans 4G ni Wi-Fi.",
|
||||||
|
ctaPrimary: 'Demander une démo',
|
||||||
|
ctaSecondary: 'Voir les tarifs',
|
||||||
|
pointsTitle: 'Comment la visite tient sans réseau',
|
||||||
|
points: [
|
||||||
|
{
|
||||||
|
icon: 'download_for_offline',
|
||||||
|
title: 'Tout est téléchargé à l\'entrée',
|
||||||
|
text: "Textes, images, audios et icônes du parcours sont embarqués sur le téléphone pendant qu'il y a encore du réseau. Une visite incomplète ne s'annonce jamais comme prête.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'sensors',
|
||||||
|
title: 'Des balises pour se repérer sans GPS',
|
||||||
|
text: "Sous terre, le GPS ne passe pas non plus. Des balises BLE placées dans les espaces détectent l'approche du visiteur et déclenchent le bon contenu.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'qr_code_2',
|
||||||
|
title: 'Des codes QR comme filet',
|
||||||
|
text: "Un code QR à chaque point d'intérêt ouvre directement la bonne fiche. C'est l'accès de secours, celui qui marche toujours, même si le visiteur arrive par un autre chemin.",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
caseTitle: 'Le Fort de Saint-Héribert, 100 % hors ligne',
|
||||||
|
caseText: "Un fort souterrain où aucun Wi-Fi n'est possible dans les galeries. L'application iOS et Android y fonctionne entièrement hors ligne depuis 2023 : contenus téléchargés à l'entrée, balises iBeacon dans les galeries, codes QR et audioguide.",
|
||||||
|
caseLink: 'Lire le cas Fort de Saint-Héribert',
|
||||||
|
caseSlug: 'fort-de-saint-heribert',
|
||||||
|
faqTitle: 'Questions fréquentes sur la visite hors ligne',
|
||||||
|
faq: [
|
||||||
|
{
|
||||||
|
question: 'Le visiteur doit-il télécharger quelque chose avant de venir ?',
|
||||||
|
answer: "Non, il peut le faire sur place : le téléchargement se lance à l'entrée du site, là où il y a encore du réseau ou un Wi-Fi d'accueil. Prévoir une bonne connexion à cet endroit précis est le seul vrai prérequis d'un déploiement hors ligne.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Qu\'est-ce qui fonctionne, et qu\'est-ce qui ne fonctionne pas, sans réseau ?',
|
||||||
|
answer: "Les contenus téléchargés — textes, images, audios, parcours, quiz — fonctionnent sans connexion. Ce qui a besoin du réseau : l'assistant IA, les mises à jour de contenu publiées entre-temps et l'envoi des statistiques, qui repartent à la prochaine connexion.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Faut-il installer des balises ?',
|
||||||
|
answer: "Ce n'est pas obligatoire. Les codes QR suffisent pour déclencher les contenus, et la géolocalisation suffit en extérieur. Les balises BLE apportent le déclenchement automatique là où le GPS ne passe pas, typiquement en intérieur ou sous terre.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'À partir de quel plan le mode hors ligne est-il inclus ?',
|
||||||
|
answer: "Dès le plan Pro, à 99 €/mois hors TVA, avec l'application mobile à votre marque et les balises BLE. Le mode hors ligne suppose une application installée : il ne s'applique pas à l'application web du plan Essentiel.",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
ctaTitle: 'Votre site ne capte pas ? Parlons-en.',
|
||||||
|
ctaButton: 'Demander une démo gratuite',
|
||||||
|
},
|
||||||
|
en: {
|
||||||
|
back: 'Back to home',
|
||||||
|
badge: 'Offline mode',
|
||||||
|
h1Before: 'A visit that carries on ',
|
||||||
|
h1Highlight: 'where the network stops',
|
||||||
|
intro: 'Cellars, forts, quarries, forest trails, listed buildings with thick walls: many venues have no coverage. MyInfoMate offline mode downloads the visit at the entrance, then works with no 4G and no Wi-Fi.',
|
||||||
|
ctaPrimary: 'Request a demo',
|
||||||
|
ctaSecondary: 'See pricing',
|
||||||
|
pointsTitle: 'How the visit holds up without a network',
|
||||||
|
points: [
|
||||||
|
{
|
||||||
|
icon: 'download_for_offline',
|
||||||
|
title: 'Everything is downloaded at the entrance',
|
||||||
|
text: 'Texts, images, audio and trail icons are stored on the phone while there is still coverage. An incomplete visit is never announced as ready.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'sensors',
|
||||||
|
title: 'Beacons to find your way without GPS',
|
||||||
|
text: 'Underground, GPS is gone too. BLE beacons placed in the spaces detect the visitor coming closer and trigger the right content.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'qr_code_2',
|
||||||
|
title: 'QR codes as a safety net',
|
||||||
|
text: 'A QR code at each point of interest opens the right entry directly. It is the fallback that always works, even when a visitor arrives from another direction.',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
caseTitle: 'Fort de Saint-Héribert, 100% offline',
|
||||||
|
caseText: 'An underground fort where Wi-Fi is simply impossible in the galleries. The iOS and Android app has run fully offline there since 2023: content downloaded at the entrance, iBeacon beacons in the galleries, QR codes and an audio guide.',
|
||||||
|
caseLink: 'Read the Fort de Saint-Héribert case',
|
||||||
|
caseSlug: 'fort-de-saint-heribert',
|
||||||
|
faqTitle: 'Offline visit FAQ',
|
||||||
|
faq: [
|
||||||
|
{
|
||||||
|
question: 'Does the visitor have to download anything before arriving?',
|
||||||
|
answer: 'No, it can be done on site: the download starts at the entrance, where there is still coverage or a welcome Wi-Fi. Making sure that one spot has a decent connection is the only real prerequisite of an offline deployment.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'What works offline, and what does not?',
|
||||||
|
answer: 'Downloaded content — texts, images, audio, trails, quizzes — works with no connection. What needs the network: the AI assistant, content updates published in the meantime, and sending statistics, which go out at the next connection.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Do we have to install beacons?',
|
||||||
|
answer: 'Not necessarily. QR codes are enough to trigger content, and geolocation is enough outdoors. BLE beacons add automatic triggering where GPS does not reach, typically indoors or underground.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'From which plan is offline mode included?',
|
||||||
|
answer: 'From the Pro plan, at €99/month excluding VAT, together with your branded mobile app and BLE beacons. Offline mode requires an installed app: it does not apply to the web app of the Essential plan.',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
ctaTitle: 'No coverage at your site? Let\'s talk.',
|
||||||
|
ctaButton: 'Request a free demo',
|
||||||
|
},
|
||||||
|
nl: {
|
||||||
|
back: 'Terug naar home',
|
||||||
|
badge: 'Offline modus',
|
||||||
|
h1Before: 'Een bezoek dat doorgaat ',
|
||||||
|
h1Highlight: 'waar het netwerk stopt',
|
||||||
|
intro: 'Kelders, forten, groeven, bospaden, beschermde gebouwen met dikke muren: veel locaties hebben geen bereik. De offline modus van MyInfoMate downloadt het bezoek aan de ingang en werkt daarna zonder 4G of wifi.',
|
||||||
|
ctaPrimary: 'Demo aanvragen',
|
||||||
|
ctaSecondary: 'Tarieven bekijken',
|
||||||
|
pointsTitle: 'Hoe het bezoek standhoudt zonder netwerk',
|
||||||
|
points: [
|
||||||
|
{
|
||||||
|
icon: 'download_for_offline',
|
||||||
|
title: 'Alles wordt aan de ingang gedownload',
|
||||||
|
text: 'Teksten, beelden, audio en icoontjes van het parcours komen op de telefoon zolang er nog bereik is. Een onvolledig bezoek wordt nooit als klaar aangekondigd.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'sensors',
|
||||||
|
title: 'Bakens om je weg te vinden zonder gps',
|
||||||
|
text: 'Ondergronds valt ook gps weg. BLE-bakens in de ruimtes merken de bezoeker op en tonen automatisch de juiste inhoud.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'qr_code_2',
|
||||||
|
title: 'QR-codes als vangnet',
|
||||||
|
text: 'Een QR-code bij elk punt opent meteen de juiste fiche. Dat is de terugvaloptie die altijd werkt, ook als de bezoeker van de andere kant komt.',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
caseTitle: 'Fort de Saint-Héribert, 100 % offline',
|
||||||
|
caseText: 'Een ondergronds fort waar wifi in de galerijen gewoon onmogelijk is. De iOS- en Android-app draait er sinds 2023 volledig offline: inhoud gedownload aan de ingang, iBeacon-bakens in de galerijen, QR-codes en audiogids.',
|
||||||
|
caseLink: 'Lees de case Fort de Saint-Héribert',
|
||||||
|
caseSlug: 'fort-de-saint-heribert',
|
||||||
|
faqTitle: 'Veelgestelde vragen over het offline bezoek',
|
||||||
|
faq: [
|
||||||
|
{
|
||||||
|
question: 'Moet de bezoeker vooraf iets downloaden?',
|
||||||
|
answer: 'Nee, het kan ter plaatse: de download start aan de ingang, waar er nog bereik of onthaalwifi is. Zorgen dat net die plek een degelijke verbinding heeft, is de enige echte voorwaarde voor een offline uitrol.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Wat werkt offline en wat niet?',
|
||||||
|
answer: 'Gedownloade inhoud — teksten, beelden, audio, parcours, quizzen — werkt zonder verbinding. Wat het netwerk nodig heeft: de AI-assistent, ondertussen gepubliceerde inhoudswijzigingen en het versturen van statistieken, die bij de volgende verbinding vertrekken.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Moeten er bakens geplaatst worden?',
|
||||||
|
answer: 'Niet noodzakelijk. QR-codes volstaan om inhoud te tonen, en buiten volstaat geolocatie. BLE-bakens voegen automatische activering toe waar gps niet raakt, typisch binnen of ondergronds.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Vanaf welk abonnement zit de offline modus erin?',
|
||||||
|
answer: 'Vanaf het Pro-abonnement, aan €99/maand excl. btw, samen met uw eigen mobiele app en de BLE-bakens. De offline modus veronderstelt een geïnstalleerde app: hij geldt niet voor de web-app van het Essentieel-abonnement.',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
ctaTitle: 'Geen bereik op uw site? Laten we praten.',
|
||||||
|
ctaButton: 'Gratis demo aanvragen',
|
||||||
|
},
|
||||||
|
de: {
|
||||||
|
back: 'Zurück zur Startseite',
|
||||||
|
badge: 'Offline-Modus',
|
||||||
|
h1Before: 'Ein Besuch, der weitergeht, ',
|
||||||
|
h1Highlight: 'wo das Netz aufhört',
|
||||||
|
intro: 'Keller, Forts, Steinbrüche, Waldwege, denkmalgeschützte Gebäude mit dicken Mauern: Viele Orte haben keinen Empfang. Der Offline-Modus von MyInfoMate lädt den Besuch am Eingang herunter und funktioniert danach ohne 4G und WLAN.',
|
||||||
|
ctaPrimary: 'Demo anfragen',
|
||||||
|
ctaSecondary: 'Preise ansehen',
|
||||||
|
pointsTitle: 'Wie der Besuch ohne Netz funktioniert',
|
||||||
|
points: [
|
||||||
|
{
|
||||||
|
icon: 'download_for_offline',
|
||||||
|
title: 'Alles wird am Eingang geladen',
|
||||||
|
text: 'Texte, Bilder, Audios und Rundgangssymbole landen auf dem Telefon, solange es noch Empfang gibt. Ein unvollständiger Besuch wird nie als fertig gemeldet.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'sensors',
|
||||||
|
title: 'Beacons zur Orientierung ohne GPS',
|
||||||
|
text: 'Unter Tage fällt auch GPS aus. BLE-Beacons in den Räumen erkennen den Besucher und lösen den passenden Inhalt aus.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'qr_code_2',
|
||||||
|
title: 'QR-Codes als Sicherheitsnetz',
|
||||||
|
text: 'Ein QR-Code an jedem Punkt öffnet direkt den richtigen Eintrag. Das ist die Rückfallebene, die immer funktioniert — auch wenn jemand von der anderen Seite kommt.',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
caseTitle: 'Fort de Saint-Héribert, 100 % offline',
|
||||||
|
caseText: 'Ein unterirdisches Fort, in dessen Galerien WLAN schlicht unmöglich ist. Die iOS- und Android-App läuft dort seit 2023 vollständig offline: Inhalte am Eingang geladen, iBeacon-Beacons in den Galerien, QR-Codes und Audioguide.',
|
||||||
|
caseLink: 'Den Fall Fort de Saint-Héribert lesen',
|
||||||
|
caseSlug: 'fort-de-saint-heribert',
|
||||||
|
faqTitle: 'Häufige Fragen zum Offline-Besuch',
|
||||||
|
faq: [
|
||||||
|
{
|
||||||
|
question: 'Muss der Besucher vor der Ankunft etwas herunterladen?',
|
||||||
|
answer: 'Nein, das geht vor Ort: Der Download startet am Eingang, wo es noch Empfang oder ein Empfangs-WLAN gibt. Genau dort für eine ordentliche Verbindung zu sorgen, ist die einzige echte Voraussetzung eines Offline-Einsatzes.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Was funktioniert offline und was nicht?',
|
||||||
|
answer: 'Heruntergeladene Inhalte — Texte, Bilder, Audios, Rundgänge, Quiz — funktionieren ohne Verbindung. Das Netz brauchen: der KI-Assistent, zwischenzeitlich veröffentlichte Inhaltsänderungen und das Senden der Statistiken, die bei der nächsten Verbindung übertragen werden.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Müssen Beacons installiert werden?',
|
||||||
|
answer: 'Nicht zwingend. QR-Codes genügen, um Inhalte auszulösen, im Freien genügt die Ortung. BLE-Beacons ergänzen die automatische Auslösung dort, wo GPS nicht hinreicht — typischerweise drinnen oder unter Tage.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Ab welchem Plan ist der Offline-Modus enthalten?',
|
||||||
|
answer: 'Ab dem Pro-Plan, für 99 €/Monat zzgl. MwSt., zusammen mit Ihrer eigenen Mobile App und den BLE-Beacons. Der Offline-Modus setzt eine installierte App voraus: Für die Web-App des Essential-Plans gilt er nicht.',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
ctaTitle: 'Kein Empfang an Ihrem Ort? Sprechen wir darüber.',
|
||||||
|
ctaButton: 'Kostenlose Demo anfordern',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export function generateStaticParams() {
|
||||||
|
return LOCALES.map((lang) => ({ lang }));
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function generateMetadata({
|
||||||
|
params,
|
||||||
|
}: {
|
||||||
|
params: Promise<{ lang: string }>;
|
||||||
|
}): Promise<Metadata> {
|
||||||
|
const { lang } = await params;
|
||||||
|
if (!isLocale(lang)) return {};
|
||||||
|
const m = META[lang];
|
||||||
|
const languages = Object.fromEntries(LOCALES.map((l) => [LOCALE_HTML_LANG[l], `/${l}/${PATH}`]));
|
||||||
|
return {
|
||||||
|
title: m.title,
|
||||||
|
description: m.description,
|
||||||
|
openGraph: {
|
||||||
|
title: m.title,
|
||||||
|
description: m.description,
|
||||||
|
url: `${SITE_URL}/${lang}/${PATH}`,
|
||||||
|
siteName: 'MyInfoMate',
|
||||||
|
locale: LOCALE_OG[lang],
|
||||||
|
type: 'website',
|
||||||
|
},
|
||||||
|
alternates: {
|
||||||
|
canonical: `/${lang}/${PATH}`,
|
||||||
|
languages: { ...languages, 'x-default': `/${DEFAULT_LOCALE}/${PATH}` },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default async function VisiteHorsLignePage({ params }: { params: Promise<{ lang: string }> }) {
|
||||||
|
const { lang } = await params;
|
||||||
|
if (!isLocale(lang)) notFound();
|
||||||
|
const text = TEXT[lang];
|
||||||
|
|
||||||
|
const faqSchema = {
|
||||||
|
'@context': 'https://schema.org',
|
||||||
|
'@type': 'FAQPage',
|
||||||
|
mainEntity: text.faq.map((item) => ({
|
||||||
|
'@type': 'Question',
|
||||||
|
name: item.question,
|
||||||
|
acceptedAnswer: { '@type': 'Answer', text: item.answer },
|
||||||
|
})),
|
||||||
|
};
|
||||||
|
|
||||||
|
const softwareSchema = {
|
||||||
|
'@context': 'https://schema.org',
|
||||||
|
'@type': 'SoftwareApplication',
|
||||||
|
name: 'MyInfoMate',
|
||||||
|
applicationCategory: 'BusinessApplication',
|
||||||
|
operatingSystem: 'iOS, Android',
|
||||||
|
offers: softwareOffers,
|
||||||
|
sameAs: [MYINFOMATE_LINKEDIN],
|
||||||
|
description: META[lang].description,
|
||||||
|
url: `${SITE_URL}/${lang}/${PATH}`,
|
||||||
|
};
|
||||||
|
|
||||||
|
const breadcrumb = breadcrumbSchema([
|
||||||
|
{ name: 'MyInfoMate', path: `/${lang}` },
|
||||||
|
{ name: text.badge, path: `/${lang}/${PATH}` },
|
||||||
|
]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(breadcrumb) }} />
|
||||||
|
<script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(faqSchema) }} />
|
||||||
|
<script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(softwareSchema) }} />
|
||||||
|
<ContentPage lang={lang} text={text} />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -1,74 +0,0 @@
|
|||||||
import type { Metadata } from "next";
|
|
||||||
import Link from "next/link";
|
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
|
||||||
title: "Politique de confidentialité | MyInfoMate",
|
|
||||||
description: "Politique de confidentialité et traitement des données personnelles de MyInfoMate.",
|
|
||||||
alternates: { canonical: "/confidentialite" },
|
|
||||||
};
|
|
||||||
|
|
||||||
export default function Confidentialite() {
|
|
||||||
return (
|
|
||||||
<main className="min-h-screen bg-white">
|
|
||||||
<div className="max-w-3xl mx-auto px-6 py-16">
|
|
||||||
<Link href="/" className="text-sm text-slate-400 hover:text-slate-600 mb-8 inline-block">
|
|
||||||
← Retour
|
|
||||||
</Link>
|
|
||||||
|
|
||||||
<h1 className="text-3xl font-bold text-slate-900 mb-10">Politique de confidentialité</h1>
|
|
||||||
|
|
||||||
<section className="mb-8">
|
|
||||||
<h2 className="text-lg font-semibold text-slate-800 mb-3">Responsable du traitement</h2>
|
|
||||||
<p className="text-slate-600 text-sm leading-relaxed">
|
|
||||||
Thomas Fransolet — UNOV<br />
|
|
||||||
Rue René Copette 3, 5020 Namur, Belgique<br />
|
|
||||||
Email : <a href="mailto:contact@unov.be" className="text-cyan-500 hover:underline">contact@unov.be</a>
|
|
||||||
</p>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section className="mb-8">
|
|
||||||
<h2 className="text-lg font-semibold text-slate-800 mb-3">Données collectées</h2>
|
|
||||||
<p className="text-slate-600 text-sm leading-relaxed">
|
|
||||||
Le formulaire de contact collecte les données suivantes : prénom, nom, adresse email, et le message saisi. Ces données sont transmises à UNOV à des fins de réponse à votre demande.
|
|
||||||
</p>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section className="mb-8">
|
|
||||||
<h2 className="text-lg font-semibold text-slate-800 mb-3">Finalité et base légale</h2>
|
|
||||||
<p className="text-slate-600 text-sm leading-relaxed">
|
|
||||||
Les données collectées sont traitées uniquement pour répondre à votre prise de contact. La base légale est l'intérêt légitime (art. 6.1.f du RGPD).
|
|
||||||
</p>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section className="mb-8">
|
|
||||||
<h2 className="text-lg font-semibold text-slate-800 mb-3">Conservation des données</h2>
|
|
||||||
<p className="text-slate-600 text-sm leading-relaxed">
|
|
||||||
Les données ne sont pas stockées sur nos serveurs. Elles sont transmises par email via le service <strong>Formspree</strong> (formspree.io) et ne sont pas conservées au-delà de la réception du message.
|
|
||||||
</p>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section className="mb-8">
|
|
||||||
<h2 className="text-lg font-semibold text-slate-800 mb-3">Sous-traitant</h2>
|
|
||||||
<p className="text-slate-600 text-sm leading-relaxed">
|
|
||||||
L'envoi du formulaire utilise le service <strong>Formspree, Inc.</strong> (États-Unis), qui agit en qualité de sous-traitant. Le transfert est encadré par les clauses contractuelles types de la Commission européenne. Pour plus d'informations : <a href="https://formspree.io/legal/privacy-policy" target="_blank" rel="noopener noreferrer" className="text-cyan-500 hover:underline">politique de confidentialité de Formspree</a>.
|
|
||||||
</p>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section className="mb-8">
|
|
||||||
<h2 className="text-lg font-semibold text-slate-800 mb-3">Vos droits</h2>
|
|
||||||
<p className="text-slate-600 text-sm leading-relaxed">
|
|
||||||
Conformément au RGPD, vous disposez d'un droit d'accès, de rectification, d'effacement, de limitation, d'opposition et de portabilité de vos données. Pour exercer ces droits, contactez-nous à <a href="mailto:contact@unov.be" className="text-cyan-500 hover:underline">contact@unov.be</a>.<br /><br />
|
|
||||||
Vous avez également le droit d'introduire une réclamation auprès de l'Autorité de protection des données (APD) belge : <a href="https://www.autoriteprotectiondonnees.be" target="_blank" rel="noopener noreferrer" className="text-cyan-500 hover:underline">autoriteprotectiondonnees.be</a>.
|
|
||||||
</p>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section>
|
|
||||||
<h2 className="text-lg font-semibold text-slate-800 mb-3">Cookies</h2>
|
|
||||||
<p className="text-slate-600 text-sm leading-relaxed">
|
|
||||||
Ce site n'utilise pas de cookies de traçage ou publicitaires. Aucun outil d'analyse comportementale n'est actif.
|
|
||||||
</p>
|
|
||||||
</section>
|
|
||||||
</div>
|
|
||||||
</main>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
8
src/app/font.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import { Plus_Jakarta_Sans } from "next/font/google";
|
||||||
|
|
||||||
|
export const plusJakartaSans = Plus_Jakarta_Sans({
|
||||||
|
subsets: ["latin"],
|
||||||
|
weight: ["400", "500", "600", "700", "800"],
|
||||||
|
variable: "--font-plus-jakarta",
|
||||||
|
display: "swap",
|
||||||
|
});
|
||||||
@ -1,91 +0,0 @@
|
|||||||
import type { Metadata } from "next";
|
|
||||||
import { headers } from "next/headers";
|
|
||||||
import { Plus_Jakarta_Sans } from "next/font/google";
|
|
||||||
import "./globals.css";
|
|
||||||
import { DEFAULT_LOCALE, LOCALES, LOCALE_HTML_LANG, LOCALE_OG, isLocale, type Locale } from "@/i18n";
|
|
||||||
|
|
||||||
const plusJakartaSans = Plus_Jakarta_Sans({
|
|
||||||
subsets: ["latin"],
|
|
||||||
weight: ["400", "500", "600", "700", "800"],
|
|
||||||
variable: "--font-plus-jakarta",
|
|
||||||
display: "swap",
|
|
||||||
});
|
|
||||||
|
|
||||||
const SITE_URL = "https://myinfomate.be";
|
|
||||||
|
|
||||||
const META_BY_LOCALE: Record<Locale, { title: string; description: string }> = {
|
|
||||||
fr: {
|
|
||||||
title: "MyInfoMate — Application guide visiteur pour musées & lieux",
|
|
||||||
description: "Créez votre app guide visiteur sans code. Cartes interactives, audioguide, quiz, escape game et assistant IA pour musées, parcs et offices de tourisme. Dès €39/mois.",
|
|
||||||
},
|
|
||||||
en: {
|
|
||||||
title: "MyInfoMate — Digital Visitor App for Museums & Venues",
|
|
||||||
description: "Build your visitor guide app with no code. Interactive maps, audio guides, quizzes, escape game and AI assistant for museums, parks and tourism offices. From €39/month.",
|
|
||||||
},
|
|
||||||
nl: {
|
|
||||||
title: "MyInfoMate — Digitale bezoekersgids voor musea & locaties",
|
|
||||||
description: "Maak uw bezoekersgids-app zonder code. Interactieve kaarten, audiogids, quiz, escape game en AI-assistent voor musea, parken en toerismekantoren. Vanaf €39/maand.",
|
|
||||||
},
|
|
||||||
de: {
|
|
||||||
title: "MyInfoMate — Digitaler Besucherguide für Museen & Orte",
|
|
||||||
description: "Erstellen Sie Ihre Besucher-App ohne Code. Interaktive Karten, Audioguide, Quiz, Escape Game und KI-Assistent für Museen, Parks und Tourismusbüros. Ab €39/Monat.",
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
async function resolveLocale(): Promise<Locale> {
|
|
||||||
const h = await headers();
|
|
||||||
const pathname = h.get("x-pathname") ?? "/";
|
|
||||||
const seg = pathname.split("/").filter(Boolean)[0];
|
|
||||||
return seg && isLocale(seg) ? seg : DEFAULT_LOCALE;
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function generateMetadata(): Promise<Metadata> {
|
|
||||||
const locale = await resolveLocale();
|
|
||||||
const m = META_BY_LOCALE[locale];
|
|
||||||
const languages = Object.fromEntries(
|
|
||||||
LOCALES.map((l) => [LOCALE_HTML_LANG[l], `/${l}`])
|
|
||||||
);
|
|
||||||
return {
|
|
||||||
metadataBase: new URL(SITE_URL),
|
|
||||||
title: m.title,
|
|
||||||
description: m.description,
|
|
||||||
icons: { icon: "/myinfomate-logo.png" },
|
|
||||||
openGraph: {
|
|
||||||
title: m.title,
|
|
||||||
description: m.description,
|
|
||||||
url: `${SITE_URL}/${locale}`,
|
|
||||||
siteName: "MyInfoMate",
|
|
||||||
locale: LOCALE_OG[locale],
|
|
||||||
alternateLocale: LOCALES.filter((l) => l !== locale).map((l) => LOCALE_OG[l]),
|
|
||||||
type: "website",
|
|
||||||
images: [{ url: "/myinfomate-logo.png" }],
|
|
||||||
},
|
|
||||||
twitter: {
|
|
||||||
card: "summary_large_image",
|
|
||||||
title: m.title,
|
|
||||||
description: m.description,
|
|
||||||
},
|
|
||||||
alternates: {
|
|
||||||
canonical: `/${locale}`,
|
|
||||||
languages: { ...languages, "x-default": `/${DEFAULT_LOCALE}` },
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export default async function RootLayout({
|
|
||||||
children,
|
|
||||||
}: Readonly<{ children: React.ReactNode }>) {
|
|
||||||
const locale = await resolveLocale();
|
|
||||||
return (
|
|
||||||
<html lang={LOCALE_HTML_LANG[locale]} className={plusJakartaSans.variable}>
|
|
||||||
<head>
|
|
||||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossOrigin="anonymous" />
|
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@24,400,0,0&display=swap" rel="stylesheet" />
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
{children}
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@ -1,65 +0,0 @@
|
|||||||
import type { Metadata } from "next";
|
|
||||||
import Link from "next/link";
|
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
|
||||||
title: "Mentions légales | MyInfoMate",
|
|
||||||
description: "Mentions légales du site MyInfoMate.",
|
|
||||||
alternates: { canonical: "/mentions-legales" },
|
|
||||||
};
|
|
||||||
|
|
||||||
export default function MentionsLegales() {
|
|
||||||
return (
|
|
||||||
<main className="min-h-screen bg-white">
|
|
||||||
<div className="max-w-3xl mx-auto px-6 py-16">
|
|
||||||
<Link href="/" className="text-sm text-slate-400 hover:text-slate-600 mb-8 inline-block">
|
|
||||||
← Retour
|
|
||||||
</Link>
|
|
||||||
|
|
||||||
<h1 className="text-3xl font-bold text-slate-900 mb-10">Mentions légales</h1>
|
|
||||||
|
|
||||||
<section className="mb-8">
|
|
||||||
<h2 className="text-lg font-semibold text-slate-800 mb-3">Éditeur du site</h2>
|
|
||||||
<p className="text-slate-600 text-sm leading-relaxed">
|
|
||||||
Le présent site est édité par :<br />
|
|
||||||
<strong>Thomas Fransolet</strong>, personne physique exerçant une activité sous l'enseigne <strong>UNOV</strong><br />
|
|
||||||
Numéro d'entreprise BCE : 0776.895.467<br />
|
|
||||||
Rue René Copette 3, 5020 Namur, Belgique<br />
|
|
||||||
Email : <a href="mailto:contact@unov.be" className="text-cyan-500 hover:underline">contact@unov.be</a><br />
|
|
||||||
Téléphone : +32 498 07 95 35
|
|
||||||
</p>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section className="mb-8">
|
|
||||||
<h2 className="text-lg font-semibold text-slate-800 mb-3">Hébergement</h2>
|
|
||||||
<p className="text-slate-600 text-sm leading-relaxed">
|
|
||||||
Ce site est hébergé par :<br />
|
|
||||||
<strong>OVH SAS</strong><br />
|
|
||||||
2 rue Kellermann, 59100 Roubaix, France<br />
|
|
||||||
<a href="https://www.ovh.com" target="_blank" rel="noopener noreferrer" className="text-cyan-500 hover:underline">www.ovh.com</a>
|
|
||||||
</p>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section className="mb-8">
|
|
||||||
<h2 className="text-lg font-semibold text-slate-800 mb-3">Propriété intellectuelle</h2>
|
|
||||||
<p className="text-slate-600 text-sm leading-relaxed">
|
|
||||||
L'ensemble des contenus présents sur ce site (textes, images, logos, graphismes) sont la propriété exclusive de Thomas Fransolet / UNOV, sauf mention contraire. Toute reproduction, distribution ou utilisation sans autorisation préalable est interdite.
|
|
||||||
</p>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section className="mb-8">
|
|
||||||
<h2 className="text-lg font-semibold text-slate-800 mb-3">Responsabilité</h2>
|
|
||||||
<p className="text-slate-600 text-sm leading-relaxed">
|
|
||||||
UNOV s'efforce de maintenir les informations publiées sur ce site à jour et exactes. Nous déclinons toute responsabilité en cas d'erreurs, d'omissions ou de résultats obtenus par un usage inapproprié de ces informations.
|
|
||||||
</p>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section>
|
|
||||||
<h2 className="text-lg font-semibold text-slate-800 mb-3">Droit applicable</h2>
|
|
||||||
<p className="text-slate-600 text-sm leading-relaxed">
|
|
||||||
Le présent site est soumis au droit belge. Tout litige relatif à son utilisation relève de la compétence exclusive des tribunaux de Namur, Belgique.
|
|
||||||
</p>
|
|
||||||
</section>
|
|
||||||
</div>
|
|
||||||
</main>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@ -2,9 +2,24 @@ import { MetadataRoute } from "next";
|
|||||||
import { LOCALES, LOCALE_HTML_LANG, DEFAULT_LOCALE } from "@/i18n";
|
import { LOCALES, LOCALE_HTML_LANG, DEFAULT_LOCALE } from "@/i18n";
|
||||||
import { getAllSegmentSlugs } from "@/data/segments";
|
import { getAllSegmentSlugs } from "@/data/segments";
|
||||||
import { getAllCasClientSlugs } from "@/data/cas-clients";
|
import { getAllCasClientSlugs } from "@/data/cas-clients";
|
||||||
|
import { getAllArticles } from "@/data/articles";
|
||||||
|
import { getAllComparisonSlugs } from "@/data/comparisons";
|
||||||
|
|
||||||
const SITE_URL = "https://myinfomate.be";
|
const SITE_URL = "https://myinfomate.be";
|
||||||
|
|
||||||
|
// Date de dernière modification réelle du contenu, par famille de pages.
|
||||||
|
// À mettre à jour en même temps que le contenu : une date de build sur toutes les URLs
|
||||||
|
// n'est pas un signal de fraîcheur, c'est du bruit.
|
||||||
|
const LAST_MODIFIED = {
|
||||||
|
home: "2026-09-10",
|
||||||
|
tarifs: "2026-09-10",
|
||||||
|
assistantIa: "2026-09-10",
|
||||||
|
segments: "2026-09-10",
|
||||||
|
casClients: "2026-08-11",
|
||||||
|
legal: "2026-09-10",
|
||||||
|
pages: "2026-09-10",
|
||||||
|
};
|
||||||
|
|
||||||
function alternates(buildPath: (locale: string) => string) {
|
function alternates(buildPath: (locale: string) => string) {
|
||||||
const languages: Record<string, string> = {};
|
const languages: Record<string, string> = {};
|
||||||
for (const l of LOCALES) {
|
for (const l of LOCALES) {
|
||||||
@ -15,24 +30,80 @@ function alternates(buildPath: (locale: string) => string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function sitemap(): MetadataRoute.Sitemap {
|
export default function sitemap(): MetadataRoute.Sitemap {
|
||||||
const now = new Date();
|
|
||||||
const entries: MetadataRoute.Sitemap = [];
|
const entries: MetadataRoute.Sitemap = [];
|
||||||
|
|
||||||
for (const lang of LOCALES) {
|
for (const lang of LOCALES) {
|
||||||
entries.push({
|
entries.push({
|
||||||
url: `${SITE_URL}/${lang}`,
|
url: `${SITE_URL}/${lang}`,
|
||||||
lastModified: now,
|
lastModified: LAST_MODIFIED.home,
|
||||||
changeFrequency: "monthly",
|
changeFrequency: "monthly",
|
||||||
priority: lang === DEFAULT_LOCALE ? 1 : 0.9,
|
priority: lang === DEFAULT_LOCALE ? 1 : 0.9,
|
||||||
alternates: { languages: alternates((l) => `/${l}`) },
|
alternates: { languages: alternates((l) => `/${l}`) },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const lang of LOCALES) {
|
||||||
|
entries.push({
|
||||||
|
url: `${SITE_URL}/${lang}/tarifs`,
|
||||||
|
lastModified: LAST_MODIFIED.tarifs,
|
||||||
|
changeFrequency: "monthly",
|
||||||
|
priority: 0.9,
|
||||||
|
alternates: { languages: alternates((l) => `/${l}/tarifs`) },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const lang of LOCALES) {
|
||||||
|
entries.push({
|
||||||
|
url: `${SITE_URL}/${lang}/assistant-ia`,
|
||||||
|
lastModified: LAST_MODIFIED.assistantIa,
|
||||||
|
changeFrequency: "monthly",
|
||||||
|
priority: 0.9,
|
||||||
|
alternates: { languages: alternates((l) => `/${l}/assistant-ia`) },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const slug of ["borne-kiosk", "visite-hors-ligne", "marches-publics"]) {
|
||||||
|
for (const lang of LOCALES) {
|
||||||
|
entries.push({
|
||||||
|
url: `${SITE_URL}/${lang}/${slug}`,
|
||||||
|
lastModified: LAST_MODIFIED.pages,
|
||||||
|
changeFrequency: "monthly",
|
||||||
|
priority: 0.8,
|
||||||
|
alternates: { languages: alternates((l) => `/${l}/${slug}`) },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Blog : français uniquement pour l'instant.
|
||||||
|
entries.push({
|
||||||
|
url: `${SITE_URL}/fr/ressources`,
|
||||||
|
lastModified: LAST_MODIFIED.pages,
|
||||||
|
changeFrequency: "monthly",
|
||||||
|
priority: 0.7,
|
||||||
|
});
|
||||||
|
for (const article of getAllArticles()) {
|
||||||
|
entries.push({
|
||||||
|
url: `${SITE_URL}/fr/ressources/${article.slug}`,
|
||||||
|
lastModified: article.published,
|
||||||
|
changeFrequency: "yearly",
|
||||||
|
priority: 0.6,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const slug of getAllComparisonSlugs()) {
|
||||||
|
entries.push({
|
||||||
|
url: `${SITE_URL}/fr/comparatif/${slug}`,
|
||||||
|
lastModified: LAST_MODIFIED.pages,
|
||||||
|
changeFrequency: "monthly",
|
||||||
|
priority: 0.7,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
for (const slug of getAllSegmentSlugs()) {
|
for (const slug of getAllSegmentSlugs()) {
|
||||||
for (const lang of LOCALES) {
|
for (const lang of LOCALES) {
|
||||||
entries.push({
|
entries.push({
|
||||||
url: `${SITE_URL}/${lang}/${slug}`,
|
url: `${SITE_URL}/${lang}/${slug}`,
|
||||||
lastModified: now,
|
lastModified: LAST_MODIFIED.segments,
|
||||||
changeFrequency: "monthly",
|
changeFrequency: "monthly",
|
||||||
priority: 0.8,
|
priority: 0.8,
|
||||||
alternates: { languages: alternates((l) => `/${l}/${slug}`) },
|
alternates: { languages: alternates((l) => `/${l}/${slug}`) },
|
||||||
@ -43,7 +114,7 @@ export default function sitemap(): MetadataRoute.Sitemap {
|
|||||||
for (const lang of LOCALES) {
|
for (const lang of LOCALES) {
|
||||||
entries.push({
|
entries.push({
|
||||||
url: `${SITE_URL}/${lang}/cas-clients`,
|
url: `${SITE_URL}/${lang}/cas-clients`,
|
||||||
lastModified: now,
|
lastModified: LAST_MODIFIED.casClients,
|
||||||
changeFrequency: "monthly",
|
changeFrequency: "monthly",
|
||||||
priority: 0.8,
|
priority: 0.8,
|
||||||
alternates: { languages: alternates((l) => `/${l}/cas-clients`) },
|
alternates: { languages: alternates((l) => `/${l}/cas-clients`) },
|
||||||
@ -54,7 +125,7 @@ export default function sitemap(): MetadataRoute.Sitemap {
|
|||||||
for (const lang of LOCALES) {
|
for (const lang of LOCALES) {
|
||||||
entries.push({
|
entries.push({
|
||||||
url: `${SITE_URL}/${lang}/cas-clients/${slug}`,
|
url: `${SITE_URL}/${lang}/cas-clients/${slug}`,
|
||||||
lastModified: now,
|
lastModified: LAST_MODIFIED.casClients,
|
||||||
changeFrequency: "monthly",
|
changeFrequency: "monthly",
|
||||||
priority: 0.75,
|
priority: 0.75,
|
||||||
alternates: { languages: alternates((l) => `/${l}/cas-clients/${slug}`) },
|
alternates: { languages: alternates((l) => `/${l}/cas-clients/${slug}`) },
|
||||||
@ -62,20 +133,17 @@ export default function sitemap(): MetadataRoute.Sitemap {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
entries.push(
|
for (const slug of ["mentions-legales", "confidentialite", "conditions-generales"]) {
|
||||||
{
|
for (const lang of LOCALES) {
|
||||||
url: `${SITE_URL}/mentions-legales`,
|
entries.push({
|
||||||
lastModified: now,
|
url: `${SITE_URL}/${lang}/${slug}`,
|
||||||
changeFrequency: "yearly",
|
lastModified: LAST_MODIFIED.legal,
|
||||||
priority: 0.3,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
url: `${SITE_URL}/confidentialite`,
|
|
||||||
lastModified: now,
|
|
||||||
changeFrequency: "yearly",
|
changeFrequency: "yearly",
|
||||||
priority: 0.3,
|
priority: 0.3,
|
||||||
|
alternates: { languages: alternates((l) => `/${l}/${slug}`) },
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
);
|
|
||||||
|
|
||||||
return entries;
|
return entries;
|
||||||
}
|
}
|
||||||
|
|||||||
131
src/components/ContentPage.tsx
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
import Link from 'next/link';
|
||||||
|
import { Language } from '@/data/translations';
|
||||||
|
|
||||||
|
export type ContentPageText = {
|
||||||
|
back: string;
|
||||||
|
badge: string;
|
||||||
|
h1Before: string;
|
||||||
|
h1Highlight: string;
|
||||||
|
intro: string;
|
||||||
|
ctaPrimary: string;
|
||||||
|
ctaSecondary: string;
|
||||||
|
pointsTitle: string;
|
||||||
|
points: { icon: string; title: string; text: string }[];
|
||||||
|
caseTitle: string;
|
||||||
|
caseText: string;
|
||||||
|
caseLink: string;
|
||||||
|
caseSlug: string;
|
||||||
|
faqTitle: string;
|
||||||
|
faq: { question: string; answer: string }[];
|
||||||
|
ctaTitle: string;
|
||||||
|
ctaButton: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function ContentPage({ lang, text }: { lang: Language; text: ContentPageText }) {
|
||||||
|
return (
|
||||||
|
<main className="bg-slate-50 text-slate-900 min-h-screen font-display">
|
||||||
|
<header className="fixed top-0 left-0 right-0 z-50 bg-white/80 backdrop-blur-md border-b border-slate-200">
|
||||||
|
<div className="max-w-7xl mx-auto px-6 h-16 flex items-center gap-4">
|
||||||
|
<Link href={`/${lang}`} className="flex items-center gap-2 text-sm font-bold text-slate-600 hover:text-primary transition-colors">
|
||||||
|
<span className="material-symbols-outlined text-base">arrow_back</span>
|
||||||
|
{text.back}
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div className="pt-16">
|
||||||
|
<section className="py-20 lg:py-28 bg-slate-900 relative overflow-hidden">
|
||||||
|
<div className="absolute inset-0 pointer-events-none">
|
||||||
|
<div className="absolute top-10 left-1/4 w-96 h-96 bg-primary/10 rounded-full blur-3xl"></div>
|
||||||
|
<div className="absolute bottom-10 right-1/4 w-80 h-80 bg-accent-violet/10 rounded-full blur-3xl"></div>
|
||||||
|
</div>
|
||||||
|
<div className="max-w-4xl mx-auto px-6 text-center relative z-10">
|
||||||
|
<div className="inline-flex items-center gap-2 bg-primary/10 border border-primary/30 text-primary text-xs font-extrabold uppercase tracking-widest px-4 py-2 rounded-full mb-6">
|
||||||
|
<span className="w-2 h-2 rounded-full bg-primary"></span>
|
||||||
|
{text.badge}
|
||||||
|
</div>
|
||||||
|
<h1 className="text-4xl lg:text-6xl font-extrabold text-white leading-[1.1] mb-6">
|
||||||
|
{text.h1Before}<span className="gradient-text">{text.h1Highlight}</span>
|
||||||
|
</h1>
|
||||||
|
<p className="text-lg text-slate-400 max-w-2xl mx-auto mb-10">{text.intro}</p>
|
||||||
|
<div className="flex flex-col sm:flex-row gap-4 justify-center">
|
||||||
|
<Link
|
||||||
|
href={`/${lang}#contact`}
|
||||||
|
className="px-8 py-4 bg-primary text-slate-900 font-extrabold rounded-full shadow-xl shadow-primary/30 hover:brightness-110 transition-all"
|
||||||
|
>
|
||||||
|
{text.ctaPrimary}
|
||||||
|
</Link>
|
||||||
|
<Link
|
||||||
|
href={`/${lang}/tarifs`}
|
||||||
|
className="px-8 py-4 bg-white/10 text-white font-bold rounded-full border border-white/20 hover:bg-white/20 transition-all"
|
||||||
|
>
|
||||||
|
{text.ctaSecondary}
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section className="py-20 bg-white">
|
||||||
|
<div className="max-w-5xl mx-auto px-6">
|
||||||
|
<h2 className="text-3xl lg:text-4xl font-extrabold text-slate-900 text-center mb-14">{text.pointsTitle}</h2>
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
|
||||||
|
{text.points.map((point) => (
|
||||||
|
<div key={point.title} className="bg-slate-50 rounded-3xl border border-slate-100 p-8">
|
||||||
|
<div className="w-12 h-12 rounded-2xl bg-primary/10 flex items-center justify-center mb-5">
|
||||||
|
<span className="material-symbols-outlined text-primary">{point.icon}</span>
|
||||||
|
</div>
|
||||||
|
<h3 className="text-lg font-extrabold text-slate-900 mb-3">{point.title}</h3>
|
||||||
|
<p className="text-slate-600 text-sm leading-relaxed">{point.text}</p>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section className="py-20 bg-slate-50 border-y border-slate-100">
|
||||||
|
<div className="max-w-3xl mx-auto px-6 text-center">
|
||||||
|
<h2 className="text-3xl lg:text-4xl font-extrabold text-slate-900 mb-6">{text.caseTitle}</h2>
|
||||||
|
<p className="text-slate-600 leading-relaxed mb-8">{text.caseText}</p>
|
||||||
|
<Link
|
||||||
|
href={`/${lang}/cas-clients/${text.caseSlug}`}
|
||||||
|
className="inline-flex items-center gap-2 px-8 py-4 bg-white border-2 border-primary text-primary font-extrabold rounded-full hover:bg-primary hover:text-slate-900 transition-all"
|
||||||
|
>
|
||||||
|
{text.caseLink}
|
||||||
|
<span className="material-symbols-outlined">arrow_forward</span>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section className="py-20 bg-white">
|
||||||
|
<div className="max-w-3xl mx-auto px-6">
|
||||||
|
<h2 className="text-3xl lg:text-4xl font-extrabold text-slate-900 text-center mb-12">{text.faqTitle}</h2>
|
||||||
|
<div className="space-y-4">
|
||||||
|
{text.faq.map((item) => (
|
||||||
|
<details key={item.question} className="group bg-slate-50 rounded-2xl border border-slate-100 p-6">
|
||||||
|
<summary className="flex items-center justify-between gap-4 cursor-pointer list-none">
|
||||||
|
<h3 className="font-extrabold text-slate-900">{item.question}</h3>
|
||||||
|
<span className="material-symbols-outlined text-slate-400 transition-transform group-open:rotate-180">expand_more</span>
|
||||||
|
</summary>
|
||||||
|
<p className="text-slate-600 leading-relaxed mt-4">{item.answer}</p>
|
||||||
|
</details>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section className="py-16 bg-slate-900 text-center">
|
||||||
|
<div className="max-w-2xl mx-auto px-6">
|
||||||
|
<h2 className="text-2xl lg:text-3xl font-extrabold text-white mb-4">{text.ctaTitle}</h2>
|
||||||
|
<Link
|
||||||
|
href={`/${lang}#contact`}
|
||||||
|
className="inline-flex items-center gap-2 mt-6 px-8 py-4 bg-primary text-slate-900 font-extrabold rounded-full shadow-xl shadow-primary/30 hover:brightness-110 transition-all"
|
||||||
|
>
|
||||||
|
{text.ctaButton}
|
||||||
|
<span className="material-symbols-outlined">arrow_forward</span>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -31,8 +31,8 @@ export default function ModulesSection({ lang }: { lang: Language }) {
|
|||||||
<section className="py-24 bg-white" id="features">
|
<section className="py-24 bg-white" id="features">
|
||||||
<div className="max-w-7xl mx-auto px-6">
|
<div className="max-w-7xl mx-auto px-6">
|
||||||
<Reveal className="text-center mb-16">
|
<Reveal className="text-center mb-16">
|
||||||
<h2 className="text-rose-600 font-extrabold uppercase tracking-widest text-sm mb-4">{t.modules.sectionLabel}</h2>
|
<p className="text-rose-600 font-extrabold uppercase tracking-widest text-sm mb-4">{t.modules.sectionLabel}</p>
|
||||||
<h3 className="text-3xl lg:text-5xl font-extrabold text-slate-900 leading-tight mb-6">{t.modules.sectionTitle}</h3>
|
<h2 className="text-3xl lg:text-5xl font-extrabold text-slate-900 leading-tight mb-6">{t.modules.sectionTitle}</h2>
|
||||||
<p className="text-lg text-slate-600 max-w-2xl mx-auto">{t.modules.sectionDesc}</p>
|
<p className="text-lg text-slate-600 max-w-2xl mx-auto">{t.modules.sectionDesc}</p>
|
||||||
</Reveal>
|
</Reveal>
|
||||||
|
|
||||||
@ -65,20 +65,22 @@ export default function ModulesSection({ lang }: { lang: Language }) {
|
|||||||
<Reveal delay={200} className="flex-1 w-full lg:flex lg:flex-col">
|
<Reveal delay={200} className="flex-1 w-full lg:flex lg:flex-col">
|
||||||
{/* Mobile: single centered card */}
|
{/* Mobile: single centered card */}
|
||||||
<div className="lg:hidden bg-slate-50 rounded-[3rem] p-8 border border-slate-100 overflow-hidden">
|
<div className="lg:hidden bg-slate-50 rounded-[3rem] p-8 border border-slate-100 overflow-hidden">
|
||||||
<div className="text-center mb-6">
|
{modules.map((module, index) => (
|
||||||
|
<div key={module.id} className={`text-center mb-6 ${index === activeModule ? '' : 'hidden'}`}>
|
||||||
<div className="inline-flex p-3 rounded-2xl bg-white shadow-sm text-rose-600 mb-4 font-bold gap-2 items-center">
|
<div className="inline-flex p-3 rounded-2xl bg-white shadow-sm text-rose-600 mb-4 font-bold gap-2 items-center">
|
||||||
<span className="material-symbols-outlined">{modules[activeModule].icon}</span>
|
<span className="material-symbols-outlined">{module.icon}</span>
|
||||||
<span className="text-xs uppercase tracking-wider">{modules[activeModule].title}</span>
|
<span className="text-xs uppercase tracking-wider">{module.title}</span>
|
||||||
</div>
|
</div>
|
||||||
<h3 className="text-2xl font-black text-slate-900 mb-4 leading-tight">{modules[activeModule].title}</h3>
|
<h3 className="text-2xl font-black text-slate-900 mb-4 leading-tight">{module.title}</h3>
|
||||||
<p className="text-slate-600 leading-relaxed mb-6">{modules[activeModule].description}</p>
|
<p className="text-slate-600 leading-relaxed mb-6">{module.description}</p>
|
||||||
<div className="p-4 bg-rose-600/5 border border-rose-100 rounded-2xl">
|
<div className="p-4 bg-rose-600/5 border border-rose-100 rounded-2xl">
|
||||||
<p className="text-rose-600 font-bold text-sm flex items-center justify-center gap-2">
|
<p className="text-rose-600 font-bold text-sm flex items-center justify-center gap-2">
|
||||||
<span className="material-symbols-outlined text-base">verified</span>
|
<span className="material-symbols-outlined text-base">verified</span>
|
||||||
{modules[activeModule].value}
|
{module.value}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
))}
|
||||||
<div className="flex justify-center">
|
<div className="flex justify-center">
|
||||||
<div className="relative w-[200px] h-[420px] bg-slate-900 rounded-[3rem] border-[8px] border-slate-800 shadow-2xl overflow-hidden">
|
<div className="relative w-[200px] h-[420px] bg-slate-900 rounded-[3rem] border-[8px] border-slate-800 shadow-2xl overflow-hidden">
|
||||||
<div className="absolute top-0 left-1/2 -translate-x-1/2 w-24 h-5 bg-slate-800 rounded-b-2xl z-20"></div>
|
<div className="absolute top-0 left-1/2 -translate-x-1/2 w-24 h-5 bg-slate-800 rounded-b-2xl z-20"></div>
|
||||||
@ -117,20 +119,22 @@ export default function ModulesSection({ lang }: { lang: Language }) {
|
|||||||
|
|
||||||
{/* Desktop: 3D phone stack */}
|
{/* Desktop: 3D phone stack */}
|
||||||
<div className="hidden lg:flex flex-1 bg-slate-50 rounded-[3rem] p-10 border border-slate-100 gap-10 items-center">
|
<div className="hidden lg:flex flex-1 bg-slate-50 rounded-[3rem] p-10 border border-slate-100 gap-10 items-center">
|
||||||
<div className="flex-1 relative z-10 text-left">
|
{modules.map((module, index) => (
|
||||||
|
<div key={module.id} className={`flex-1 relative z-10 text-left ${index === activeModule ? '' : 'hidden'}`}>
|
||||||
<div className="inline-flex p-3 rounded-2xl bg-white shadow-sm text-rose-600 mb-5 font-bold gap-2 items-center">
|
<div className="inline-flex p-3 rounded-2xl bg-white shadow-sm text-rose-600 mb-5 font-bold gap-2 items-center">
|
||||||
<span className="material-symbols-outlined">{modules[activeModule].icon}</span>
|
<span className="material-symbols-outlined">{module.icon}</span>
|
||||||
<span className="text-xs uppercase tracking-wider">{modules[activeModule].title}</span>
|
<span className="text-xs uppercase tracking-wider">{module.title}</span>
|
||||||
</div>
|
</div>
|
||||||
<h3 className="text-3xl font-black text-slate-900 mb-5 leading-tight">{modules[activeModule].title}</h3>
|
<h3 className="text-3xl font-black text-slate-900 mb-5 leading-tight">{module.title}</h3>
|
||||||
<p className="text-slate-600 text-base leading-relaxed mb-6">{modules[activeModule].description}</p>
|
<p className="text-slate-600 text-base leading-relaxed mb-6">{module.description}</p>
|
||||||
<div className="p-5 bg-rose-600/5 border border-rose-100 rounded-2xl">
|
<div className="p-5 bg-rose-600/5 border border-rose-100 rounded-2xl">
|
||||||
<p className="text-rose-600 font-bold text-sm flex items-center gap-2">
|
<p className="text-rose-600 font-bold text-sm flex items-center gap-2">
|
||||||
<span className="material-symbols-outlined text-base">verified</span>
|
<span className="material-symbols-outlined text-base">verified</span>
|
||||||
{t.modules.valueLabel} {modules[activeModule].value}
|
{t.modules.valueLabel} {module.value}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
))}
|
||||||
|
|
||||||
<div className="flex-shrink-0 relative" style={{ width: '280px', height: '480px' }}>
|
<div className="flex-shrink-0 relative" style={{ width: '280px', height: '480px' }}>
|
||||||
<div style={{ position: 'absolute', inset: 0, transform: 'perspective(900px) rotateX(6deg) rotateY(-15deg)' }}>
|
<div style={{ position: 'absolute', inset: 0, transform: 'perspective(900px) rotateX(6deg) rotateY(-15deg)' }}>
|
||||||
|
|||||||
@ -56,7 +56,7 @@ export default function NavBar({ lang }: { lang: Language }) {
|
|||||||
<>
|
<>
|
||||||
<header className={`fixed top-0 left-0 right-0 z-50 bg-white/80 backdrop-blur-md border-b border-slate-200 transition-transform duration-300 ${navVisible ? 'translate-y-0' : '-translate-y-full'}`}>
|
<header className={`fixed top-0 left-0 right-0 z-50 bg-white/80 backdrop-blur-md border-b border-slate-200 transition-transform duration-300 ${navVisible ? 'translate-y-0' : '-translate-y-full'}`}>
|
||||||
<div className="max-w-7xl mx-auto px-6 h-20 flex items-center justify-between">
|
<div className="max-w-7xl mx-auto px-6 h-20 flex items-center justify-between">
|
||||||
<a className="flex items-center gap-3 shrink-0" href="#">
|
<a className="flex items-center gap-3 shrink-0" href={`/${lang}`}>
|
||||||
<Image
|
<Image
|
||||||
src={resolveImage("{{DATA:IMAGE:IMAGE_14}}")}
|
src={resolveImage("{{DATA:IMAGE:IMAGE_14}}")}
|
||||||
alt="MyInfoMate Logo"
|
alt="MyInfoMate Logo"
|
||||||
@ -74,7 +74,7 @@ export default function NavBar({ lang }: { lang: Language }) {
|
|||||||
{t.nav.ai}
|
{t.nav.ai}
|
||||||
</a>
|
</a>
|
||||||
<a className="text-sm font-semibold text-slate-600 hover:text-primary transition-colors w-[88px] text-center" href="#audience">{t.nav.audience}</a>
|
<a className="text-sm font-semibold text-slate-600 hover:text-primary transition-colors w-[88px] text-center" href="#audience">{t.nav.audience}</a>
|
||||||
<a className="text-sm font-semibold text-slate-600 hover:text-primary transition-colors w-[64px] text-center" href="#pricing">{t.pricing.sectionLabel}</a>
|
<a className="text-sm font-semibold text-slate-600 hover:text-primary transition-colors w-[64px] text-center" href={`/${lang}/tarifs`}>{t.pricing.sectionLabel}</a>
|
||||||
</nav>
|
</nav>
|
||||||
<div className="flex items-center gap-4">
|
<div className="flex items-center gap-4">
|
||||||
<a
|
<a
|
||||||
@ -146,22 +146,19 @@ export default function NavBar({ lang }: { lang: Language }) {
|
|||||||
<nav className="flex-1 flex flex-col p-8 gap-8 overflow-y-auto scrollbar-hide">
|
<nav className="flex-1 flex flex-col p-8 gap-8 overflow-y-auto scrollbar-hide">
|
||||||
<div className="flex flex-col gap-6">
|
<div className="flex flex-col gap-6">
|
||||||
{[
|
{[
|
||||||
{ label: t.mobileMenu.home, href: '#' },
|
{ label: t.mobileMenu.home, href: `/${lang}` },
|
||||||
{ label: t.mobileMenu.solution, href: '#deployment-modes' },
|
{ label: t.mobileMenu.solution, href: '#deployment-modes' },
|
||||||
{ label: t.mobileMenu.features, href: '#features' },
|
{ label: t.mobileMenu.features, href: '#features' },
|
||||||
{ label: t.mobileMenu.ai, href: '#ai-assistant' },
|
{ label: t.mobileMenu.ai, href: '#ai-assistant' },
|
||||||
{ label: t.mobileMenu.audience, href: '#audience' },
|
{ label: t.mobileMenu.audience, href: '#audience' },
|
||||||
{ label: t.pricing.sectionLabel.toUpperCase(), href: '#pricing' },
|
{ label: t.pricing.sectionLabel.toUpperCase(), href: `/${lang}/tarifs` },
|
||||||
{ label: t.mobileMenu.contact, href: '#contact' },
|
{ label: t.mobileMenu.contact, href: '#contact' },
|
||||||
].map((item) => (
|
].map((item) => (
|
||||||
<a
|
<a
|
||||||
key={item.label}
|
key={item.label}
|
||||||
className="text-sm font-bold tracking-[0.2em] text-slate-900 hover:text-primary transition-colors py-3 border-b border-slate-50 flex items-center justify-between"
|
className="text-sm font-bold tracking-[0.2em] text-slate-900 hover:text-primary transition-colors py-3 border-b border-slate-50 flex items-center justify-between"
|
||||||
href={item.href}
|
href={item.href}
|
||||||
onClick={() => {
|
onClick={() => setIsMenuOpen(false)}
|
||||||
if (item.href === '#') window.scrollTo({ top: 0, behavior: 'smooth' });
|
|
||||||
setIsMenuOpen(false);
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
{item.label}
|
{item.label}
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
231
src/components/PricingPlans.tsx
Normal file
@ -0,0 +1,231 @@
|
|||||||
|
import translations, { Language } from '@/data/translations';
|
||||||
|
import Reveal from '@/components/Reveal';
|
||||||
|
|
||||||
|
export default function PricingPlans({ lang, contactHref }: { lang: Language; contactHref: string }) {
|
||||||
|
const t = translations[lang];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="grid grid-cols-1 sm:grid-cols-2 xl:grid-cols-4 gap-6 items-stretch pt-6">
|
||||||
|
<Reveal delay={0}>
|
||||||
|
<div className="flex flex-col h-full bg-white rounded-3xl border border-slate-200 p-8 shadow-sm hover:shadow-md transition-shadow relative">
|
||||||
|
<div className="mb-6">
|
||||||
|
<p className="text-sm font-bold text-slate-400 uppercase tracking-widest mb-2">Essentiel</p>
|
||||||
|
<span className="inline-flex items-center gap-1 text-xs font-semibold px-2.5 py-1 rounded-full bg-slate-100 text-slate-500 mb-3">
|
||||||
|
<span className="material-symbols-outlined" style={{fontSize: '14px'}}>language</span>
|
||||||
|
{t.pricing.channelWeb}
|
||||||
|
</span>
|
||||||
|
<div className="flex items-end gap-1">
|
||||||
|
<span className="text-4xl font-extrabold text-slate-900">€39</span>
|
||||||
|
<span className="text-slate-400 mb-1">{t.pricing.perMonth}</span>
|
||||||
|
</div>
|
||||||
|
<p className="text-xs text-slate-400 mt-1">{t.pricing.htva} · {t.pricing.noCommitment}</p>
|
||||||
|
</div>
|
||||||
|
<ul className="space-y-3 flex-1 mb-8">
|
||||||
|
{[t.pricing.features.webAndKiosk, t.pricing.features.backoffice, t.pricing.features.sections].map((f) => (
|
||||||
|
<li key={f} className="flex items-center gap-3 text-sm text-slate-700">
|
||||||
|
<span className="material-symbols-outlined text-primary text-base shrink-0">check_circle</span>
|
||||||
|
{f}
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
<li className="flex items-center gap-3 text-sm text-slate-700">
|
||||||
|
<span className="material-symbols-outlined text-primary text-base shrink-0">check_circle</span>
|
||||||
|
1 GB {t.pricing.features.storage}
|
||||||
|
</li>
|
||||||
|
<li className="flex items-center gap-3 text-sm text-slate-700">
|
||||||
|
<span className="material-symbols-outlined text-primary text-base shrink-0">check_circle</span>
|
||||||
|
{t.pricing.features.stats} — {t.pricing.features.statsBasicLabel}
|
||||||
|
</li>
|
||||||
|
{[t.pricing.features.nativeApp, t.pricing.features.offlineBeacons, t.pricing.features.pushNotif, t.pricing.features.ai, t.pricing.features.autoTranslation].map((f) => (
|
||||||
|
<li key={f} className="flex items-center gap-3 text-sm text-slate-400">
|
||||||
|
<span className="material-symbols-outlined text-slate-300 text-base shrink-0">cancel</span>
|
||||||
|
{f}
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
<a href={`/${lang}/signup`} className="block w-full py-3 rounded-2xl border-2 border-slate-200 text-slate-700 font-bold text-sm hover:border-primary hover:text-primary transition-all text-center">
|
||||||
|
{t.pricing.ctaStartTrial}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</Reveal>
|
||||||
|
<Reveal delay={60}>
|
||||||
|
<div className="animated-card-border relative p-[2px] rounded-3xl shadow-xl shadow-primary/10 h-full">
|
||||||
|
<div className="flex flex-col h-full bg-white rounded-[22px] p-8 relative">
|
||||||
|
<div className="absolute -top-4 left-1/2 -translate-x-1/2">
|
||||||
|
<span className="bg-primary text-slate-900 text-xs font-extrabold px-4 py-1.5 rounded-full uppercase tracking-wider">{t.pricing.recommended}</span>
|
||||||
|
</div>
|
||||||
|
<div className="mb-6">
|
||||||
|
<p className="text-sm font-bold text-slate-400 uppercase tracking-widest mb-2">Pro</p>
|
||||||
|
<span className="inline-flex items-center gap-1 text-xs font-semibold px-2.5 py-1 rounded-full bg-primary/10 text-primary mb-3">
|
||||||
|
<span className="material-symbols-outlined" style={{fontSize: '14px'}}>smartphone</span>
|
||||||
|
{t.pricing.channelNative}
|
||||||
|
</span>
|
||||||
|
<div className="flex items-end gap-1">
|
||||||
|
<span className="text-4xl font-extrabold text-slate-900">€99</span>
|
||||||
|
<span className="text-slate-400 mb-1">{t.pricing.perMonth}</span>
|
||||||
|
</div>
|
||||||
|
<p className="text-xs text-slate-400 mt-1">{t.pricing.htva}</p>
|
||||||
|
<p className="text-xs text-slate-400 mt-1">{t.pricing.setupFeeNote}</p>
|
||||||
|
</div>
|
||||||
|
<ul className="space-y-3 flex-1 mb-8">
|
||||||
|
{[t.pricing.features.webAndKiosk, t.pricing.features.nativeApp, t.pricing.features.backoffice, t.pricing.features.sections].map((f) => (
|
||||||
|
<li key={f} className="flex items-center gap-3 text-sm text-slate-700">
|
||||||
|
<span className="material-symbols-outlined text-primary text-base shrink-0">check_circle</span>
|
||||||
|
{f}
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
<li className="flex items-center gap-3 text-sm text-slate-700">
|
||||||
|
<span className="material-symbols-outlined text-primary text-base shrink-0">check_circle</span>
|
||||||
|
15 GB {t.pricing.features.storage}
|
||||||
|
</li>
|
||||||
|
{[t.pricing.features.offlineBeacons, t.pricing.features.pushNotif].map((f) => (
|
||||||
|
<li key={f} className="flex items-center gap-3 text-sm text-slate-700">
|
||||||
|
<span className="material-symbols-outlined text-primary text-base shrink-0">check_circle</span>
|
||||||
|
{f}
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
<li className="flex items-center gap-3 text-sm text-slate-700">
|
||||||
|
<span className="material-symbols-outlined text-primary text-base shrink-0">check_circle</span>
|
||||||
|
{t.pricing.features.stats} — {t.pricing.features.statsBasicLabel}
|
||||||
|
</li>
|
||||||
|
{[t.pricing.features.statsAdvancedFeature, t.pricing.features.ai, t.pricing.features.autoTranslation].map((f) => (
|
||||||
|
<li key={f} className="flex items-center gap-3 text-sm text-slate-400">
|
||||||
|
<span className="material-symbols-outlined text-slate-300 text-base shrink-0">cancel</span>
|
||||||
|
{f}
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
<a href={contactHref} className="block w-full py-3 rounded-2xl bg-primary text-slate-900 font-extrabold text-sm hover:brightness-110 transition-all shadow-lg shadow-primary/20 text-center">
|
||||||
|
{t.pricing.ctaStart}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Reveal>
|
||||||
|
<Reveal delay={120}>
|
||||||
|
<div className="flex flex-col h-full bg-gradient-to-br from-slate-900 to-slate-800 rounded-3xl p-8 shadow-xl">
|
||||||
|
<div className="mb-6">
|
||||||
|
<p className="text-sm font-bold text-slate-400 uppercase tracking-widest mb-2">Premium</p>
|
||||||
|
<span className="inline-flex items-center gap-1 text-xs font-semibold px-2.5 py-1 rounded-full bg-primary/10 text-primary mb-3">
|
||||||
|
<span className="material-symbols-outlined" style={{fontSize: '14px'}}>smartphone</span>
|
||||||
|
{t.pricing.channelNative}
|
||||||
|
</span>
|
||||||
|
<div className="flex items-end gap-1">
|
||||||
|
<span className="text-4xl font-extrabold text-white">€179</span>
|
||||||
|
<span className="text-slate-400 mb-1">{t.pricing.perMonth}</span>
|
||||||
|
</div>
|
||||||
|
<p className="text-xs text-slate-400 mt-1">{t.pricing.htva}</p>
|
||||||
|
<p className="text-xs text-slate-500 mt-1">{t.pricing.setupFeeNote}</p>
|
||||||
|
</div>
|
||||||
|
<ul className="space-y-3 flex-1 mb-8">
|
||||||
|
{[t.pricing.features.webAndKiosk, t.pricing.features.nativeApp, t.pricing.features.backoffice, t.pricing.features.sections].map((f) => (
|
||||||
|
<li key={f} className="flex items-center gap-3 text-sm text-slate-300">
|
||||||
|
<span className="material-symbols-outlined text-primary text-base shrink-0">check_circle</span>
|
||||||
|
{f}
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
<li className="flex items-center gap-3 text-sm text-slate-300">
|
||||||
|
<span className="material-symbols-outlined text-primary text-base shrink-0">check_circle</span>
|
||||||
|
50 GB {t.pricing.features.storage}
|
||||||
|
</li>
|
||||||
|
{[t.pricing.features.offlineBeacons, t.pricing.features.pushNotif].map((f) => (
|
||||||
|
<li key={f} className="flex items-center gap-3 text-sm text-slate-300">
|
||||||
|
<span className="material-symbols-outlined text-primary text-base shrink-0">check_circle</span>
|
||||||
|
{f}
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
<li className="flex items-center gap-3 text-sm text-slate-300">
|
||||||
|
<span className="material-symbols-outlined text-primary text-base shrink-0">check_circle</span>
|
||||||
|
{t.pricing.features.statsAdvancedFeature}
|
||||||
|
</li>
|
||||||
|
<li className="flex items-start gap-3 text-sm text-slate-300">
|
||||||
|
<span className="material-symbols-outlined text-primary text-base shrink-0 mt-0.5">check_circle</span>
|
||||||
|
<span>
|
||||||
|
{t.pricing.features.ai} — ≈ 2 000 {t.pricing.features.questionsPerMonth}
|
||||||
|
<span className="block text-xs text-slate-500 mt-0.5">{t.pricing.features.aiNeedMore} → Enterprise</span>
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
<li className="flex items-center gap-3 text-sm text-slate-300">
|
||||||
|
<span className="material-symbols-outlined text-primary text-base shrink-0">check_circle</span>
|
||||||
|
{t.pricing.features.autoTranslation}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<a href={contactHref} className="block w-full py-3 rounded-2xl bg-white/10 text-white font-bold text-sm hover:bg-white/20 transition-all border border-white/10 text-center">
|
||||||
|
{t.pricing.ctaContact}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</Reveal>
|
||||||
|
<Reveal delay={180}>
|
||||||
|
<div className="flex flex-col h-full bg-gradient-to-br from-violet-950 to-slate-900 rounded-3xl p-8 shadow-xl border border-violet-800/40 relative">
|
||||||
|
<div className="mb-6">
|
||||||
|
<p className="text-sm font-bold text-violet-400 uppercase tracking-widest mb-2">Enterprise</p>
|
||||||
|
<span className="inline-flex items-center gap-1 text-xs font-semibold px-2.5 py-1 rounded-full bg-violet-500/10 text-violet-400 mb-3">
|
||||||
|
<span className="material-symbols-outlined" style={{fontSize: '14px'}}>smartphone</span>
|
||||||
|
{t.pricing.channelNative}
|
||||||
|
</span>
|
||||||
|
<div className="flex items-end gap-1">
|
||||||
|
<span className="text-3xl font-extrabold text-white">{t.pricing.enterprisePrice}</span>
|
||||||
|
</div>
|
||||||
|
<p className="text-xs text-slate-400 mt-2 leading-relaxed">{t.pricing.enterpriseDesc}</p>
|
||||||
|
</div>
|
||||||
|
<ul className="space-y-3 flex-1 mb-8">
|
||||||
|
{[
|
||||||
|
t.pricing.features.webAndKiosk,
|
||||||
|
t.pricing.features.nativeApp,
|
||||||
|
t.pricing.features.backoffice,
|
||||||
|
t.pricing.features.sections,
|
||||||
|
t.pricing.features.multiSite,
|
||||||
|
].map((f) => (
|
||||||
|
<li key={f} className="flex items-center gap-3 text-sm text-slate-300">
|
||||||
|
<span className="material-symbols-outlined text-violet-400 text-base shrink-0">check_circle</span>
|
||||||
|
{f}
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
<li className="flex items-center gap-3 text-sm text-slate-300">
|
||||||
|
<span className="material-symbols-outlined text-violet-400 text-base shrink-0">check_circle</span>
|
||||||
|
{t.pricing.features.customStorage}
|
||||||
|
</li>
|
||||||
|
<li className="flex items-center gap-3 text-sm text-slate-300">
|
||||||
|
<span className="material-symbols-outlined text-violet-400 text-base shrink-0">check_circle</span>
|
||||||
|
{t.pricing.features.customAiQuota}
|
||||||
|
</li>
|
||||||
|
{[
|
||||||
|
t.pricing.features.statsAdvancedFeature,
|
||||||
|
t.pricing.features.offlineBeacons,
|
||||||
|
t.pricing.features.pushNotif,
|
||||||
|
t.pricing.features.autoTranslation,
|
||||||
|
t.pricing.features.slaEnhanced,
|
||||||
|
t.pricing.features.dedicatedSupport,
|
||||||
|
t.pricing.features.customDev,
|
||||||
|
].map((f) => (
|
||||||
|
<li key={f} className="flex items-center gap-3 text-sm text-slate-300">
|
||||||
|
<span className="material-symbols-outlined text-violet-400 text-base shrink-0">check_circle</span>
|
||||||
|
{f}
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
<a href={contactHref} className="block w-full py-3 rounded-2xl bg-violet-600 text-white font-bold text-sm hover:bg-violet-500 transition-all shadow-lg shadow-violet-900/40 text-center">
|
||||||
|
{t.pricing.ctaContact}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</Reveal>
|
||||||
|
</div>
|
||||||
|
<Reveal delay={100}>
|
||||||
|
<div className="mt-12 flex flex-col sm:flex-row items-center justify-between gap-6 bg-white rounded-2xl border border-slate-200 px-8 py-6">
|
||||||
|
<div className="flex items-center gap-4">
|
||||||
|
<span className="material-symbols-outlined text-primary text-3xl shrink-0">calendar_month</span>
|
||||||
|
<div>
|
||||||
|
<p className="font-extrabold text-slate-900">{t.pricing.multiYearLabel}</p>
|
||||||
|
<p className="text-sm text-slate-500">{t.pricing.multiYearDesc}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<a
|
||||||
|
href={contactHref}
|
||||||
|
className="shrink-0 px-6 py-3 rounded-full border-2 border-primary text-primary font-bold text-sm hover:bg-primary hover:text-slate-900 transition-all whitespace-nowrap"
|
||||||
|
>
|
||||||
|
{t.pricing.multiYearCta}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</Reveal>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
119
src/data/articles.ts
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
// Articles du blog. Français uniquement pour l'instant — voir audit-seo-geo.md action 20.
|
||||||
|
export type ArticleSection = {
|
||||||
|
title: string;
|
||||||
|
paragraphs: string[];
|
||||||
|
list?: string[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Article = {
|
||||||
|
slug: string;
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
published: string;
|
||||||
|
readingMinutes: number;
|
||||||
|
intro: string;
|
||||||
|
sections: ArticleSection[];
|
||||||
|
closing: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const articles: Article[] = [
|
||||||
|
{
|
||||||
|
slug: 'audioguide-ou-application-visiteur',
|
||||||
|
title: 'Audioguide ou application visiteur : que choisir en 2026 ?',
|
||||||
|
description: "Boîtier audio à louer ou application sur le smartphone du visiteur : coûts réels, contraintes d'exploitation et cas où l'audioguide classique reste le bon choix.",
|
||||||
|
published: '2026-09-10',
|
||||||
|
readingMinutes: 6,
|
||||||
|
intro: "La question revient dans presque tous les projets de médiation numérique : faut-il investir dans des audioguides, ou basculer sur une application que le visiteur ouvre avec son propre téléphone ? Les deux fonctionnent. Ce qui les sépare tient moins à la technologie qu'à la manière dont votre équipe travaille au quotidien.",
|
||||||
|
sections: [
|
||||||
|
{
|
||||||
|
title: "Ce que coûte vraiment un parc d'audioguides",
|
||||||
|
paragraphs: [
|
||||||
|
"Le prix d'achat des boîtiers n'est que la partie visible. Il faut y ajouter la recharge quotidienne, le nettoyage entre deux visiteurs, le remplacement des appareils perdus ou cassés, le temps d'accueil consacré à la distribution et à la récupération, et surtout la caution que réclame le personnel — un geste anodin qui allonge la file à l'entrée.",
|
||||||
|
"À cela s'ajoute la mise à jour du contenu. Sur un audioguide classique, changer une piste suppose de rebrancher les appareils un par un, ou de faire revenir le prestataire. C'est précisément ce qui explique qu'on entende encore, dans certains musées, des commentaires enregistrés il y a dix ans qui mentionnent une salle qui n'existe plus.",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Ce que change une application sur le téléphone du visiteur",
|
||||||
|
paragraphs: [
|
||||||
|
"Le visiteur utilise son propre appareil : rien à distribuer, rien à recharger, rien à désinfecter. Il a ses écouteurs, il connaît son téléphone, et il peut continuer la visite chez lui. Pour l'équipe d'accueil, la charge logistique disparaît presque entièrement.",
|
||||||
|
"L'autre différence est éditoriale. Le contenu vit dans un back-office : une correction de date, une nouvelle salle, une exposition temporaire sont publiées en quelques minutes, sans intervention externe. C'est là que se joue la vraie économie, pas seulement sur le matériel.",
|
||||||
|
],
|
||||||
|
list: [
|
||||||
|
"Multilingue sans multiplier les appareils ni les stocks",
|
||||||
|
"Textes, images et vidéos en plus de l'audio, pour les visiteurs qui n'écoutent pas",
|
||||||
|
"Statistiques d'usage : ce qui est consulté, ce qui ne l'est pas",
|
||||||
|
"La visite reste accessible après la sortie",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Les trois objections sérieuses, et ce qu'elles valent",
|
||||||
|
paragraphs: [
|
||||||
|
"« Nos visiteurs sont âgés et n'ont pas de smartphone. » L'objection est réelle mais recule chaque année, et elle ne concerne jamais tout le public. La réponse pragmatique est de garder un point d'accès collectif — une borne tactile à l'accueil — pour ceux qui ne veulent rien installer.",
|
||||||
|
"« Ils n'ont pas de batterie. » C'est le vrai risque, davantage que le refus de télécharger. Un mur de prises ou quelques batteries de prêt à l'accueil coûtent bien moins cher qu'un parc de boîtiers.",
|
||||||
|
"« Ça ne capte pas chez nous. » C'est un problème résoluble : une application qui télécharge la visite à l'entrée fonctionne ensuite sans réseau. Un fort souterrain fonctionne ainsi tous les jours, avec des balises et des codes QR pour déclencher les contenus au bon endroit.",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Quand l'audioguide classique reste le bon choix",
|
||||||
|
paragraphs: [
|
||||||
|
"Il ne faut pas caricaturer : le boîtier garde des avantages. Sur une visite guidée en groupe où chacun doit entendre le guide, sur un site où l'on veut absolument éviter que les visiteurs regardent un écran, ou dans un contexte où l'usage du téléphone personnel poserait un problème de sécurité, le matériel dédié reste pertinent.",
|
||||||
|
"Le critère décisif est simple : si votre contenu bouge — agenda, expositions temporaires, langues qui s'ajoutent — l'application gagne. S'il est figé et que la visite est strictement accompagnée, le boîtier peut suffire.",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
closing: "Chez MyInfoMate, nous voyons surtout des lieux qui combinent les deux logiques : une application pour ceux qui viennent avec leur téléphone, une borne à l'accueil pour les autres, et un seul back-office pour alimenter les deux.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
slug: 'borne-tactile-ou-byod',
|
||||||
|
title: 'Borne tactile ou smartphone du visiteur : comment trancher',
|
||||||
|
description: "Kiosk tactile ou BYOD dans un musée ou un office du tourisme : ce que chaque option apporte, ce qu'elle coûte en exploitation, et pourquoi la question du public prime sur la technologie.",
|
||||||
|
published: '2026-09-10',
|
||||||
|
readingMinutes: 5,
|
||||||
|
intro: "Borne tactile installée dans le hall, ou application ouverte sur le téléphone du visiteur ? La réponse dépend d'une seule chose : à quel moment de la visite se pose la question à laquelle vous voulez répondre.",
|
||||||
|
sections: [
|
||||||
|
{
|
||||||
|
title: "La borne répond aux questions du seuil",
|
||||||
|
paragraphs: [
|
||||||
|
"Une borne est efficace là où les gens s'arrêtent : à l'entrée, à l'accueil d'un office du tourisme, devant une salle. Elle absorbe les questions répétitives — horaires, plan, événements du week-end, itinéraire — et elle le fait sans que personne n'installe quoi que ce soit.",
|
||||||
|
"C'est aussi le canal le plus inclusif : pas de compte, pas de téléchargement, pas de batterie à surveiller. Pour un public âgé, ou pour des visiteurs étrangers qui ne veulent pas consommer leurs données mobiles, c'est souvent le seul point de contact numérique réellement utilisé.",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Le smartphone accompagne le mouvement",
|
||||||
|
paragraphs: [
|
||||||
|
"Dès que la visite se déplace — un parcours, un site en extérieur, un grand bâtiment — la borne ne suit plus. Le téléphone du visiteur, lui, est déjà dans sa poche : audio au casque, géolocalisation, jeux pour les familles, contenu qui s'ouvre au bon endroit.",
|
||||||
|
"Il a un autre mérite, rarement cité : la visite continue après la sortie. Un visiteur qui rouvre l'application le soir pour relire une fiche, c'est un contact que la borne ne permettra jamais.",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Ce que coûte chacune, en exploitation",
|
||||||
|
paragraphs: [
|
||||||
|
"La borne suppose du matériel, une alimentation, un emplacement pensé — la hauteur d'écran compte autant que le logiciel si vous accueillez des personnes en fauteuil — et une surveillance minimale contre les dégradations. En revanche, elle ne demande rien au visiteur.",
|
||||||
|
"L'application ne coûte pas de matériel, mais elle demande un effort d'incitation : signalétique, codes QR bien placés, personnel qui en parle à l'accueil. Une application que personne n'annonce ne sera pas utilisée, quelle que soit sa qualité.",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "La vraie question : un contenu, plusieurs canaux",
|
||||||
|
paragraphs: [
|
||||||
|
"Le piège classique consiste à traiter les deux canaux comme deux projets. Résultat : deux contenus à maintenir, qui divergent en six mois, et une équipe qui finit par n'en mettre à jour qu'un seul.",
|
||||||
|
"La bonne question n'est donc pas « borne ou application », mais « est-ce que je gère mes contenus à un seul endroit ». Si la réponse est oui, ajouter un canal devient une décision de confort, pas un second chantier.",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
closing: "C'est le principe de MyInfoMate : le même back-office alimente la borne, l'application mobile et l'application web. Vous publiez une fois, et vous choisissez ensuite par quels canaux vos visiteurs y accèdent.",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export function getAllArticles() {
|
||||||
|
return [...articles].sort((a, b) => b.published.localeCompare(a.published));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getArticle(slug: string) {
|
||||||
|
return articles.find((article) => article.slug === slug);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getAllArticleSlugs() {
|
||||||
|
return articles.map((article) => article.slug);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default articles;
|
||||||
153
src/data/comparisons.ts
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
// Comparatifs concurrents. Français uniquement.
|
||||||
|
// ⚠️ Les prix des concurrents sont relevés à la main sur leurs pages publiques.
|
||||||
|
// Chaque entrée porte sa date de vérification : la revérifier avant toute republication.
|
||||||
|
export type ComparisonRow = {
|
||||||
|
label: string;
|
||||||
|
myinfomate: string;
|
||||||
|
competitor: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Comparison = {
|
||||||
|
slug: string;
|
||||||
|
competitor: string;
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
checkedOn: string;
|
||||||
|
intro: string;
|
||||||
|
priceIntro: string;
|
||||||
|
rows: ComparisonRow[];
|
||||||
|
fairTitle: string;
|
||||||
|
fair: string[];
|
||||||
|
differenceTitle: string;
|
||||||
|
differences: string[];
|
||||||
|
verdictTitle: string;
|
||||||
|
verdict: string[];
|
||||||
|
faq: { question: string; answer: string }[];
|
||||||
|
sources: { label: string; url: string }[];
|
||||||
|
};
|
||||||
|
|
||||||
|
const comparisons: Comparison[] = [
|
||||||
|
{
|
||||||
|
slug: 'myinfomate-vs-smartify',
|
||||||
|
competitor: 'Smartify',
|
||||||
|
title: 'MyInfoMate ou Smartify : quelle solution pour votre musée ?',
|
||||||
|
description: "Comparatif factuel MyInfoMate / Smartify : tarifs publics relevés le 10 septembre 2026, canaux couverts, langue du support, et les cas où Smartify reste le meilleur choix.",
|
||||||
|
checkedOn: '10 septembre 2026',
|
||||||
|
intro: "Smartify est l'une des solutions les plus connues du secteur muséal, portée par une application grand public utilisée dans de grandes institutions. MyInfoMate est une plateforme belge qui couvre l'application visiteur, la borne d'accueil et le web depuis un seul back-office. Les deux font de la médiation numérique ; elles ne visent pas le même type de lieu.",
|
||||||
|
priceIntro: "Smartify facture à l'année et en livres sterling ; MyInfoMate au mois et en euros hors TVA. Pour comparer, les montants annuels sont ramenés au mois — le taux de change fait varier l'équivalent en euros.",
|
||||||
|
rows: [
|
||||||
|
{ label: 'Entrée de gamme', myinfomate: '39 €/mois HTVA (468 €/an)', competitor: 'Plan gratuit limité à un parcours, puis Starter à 1 800 £/an (~150 £/mois)' },
|
||||||
|
{ label: 'Application à votre marque', myinfomate: '99 €/mois HTVA — application native sur l\'App Store et Google Play', competitor: 'Plan Branded à 3 500 £/an — application web personnalisée' },
|
||||||
|
{ label: 'Haut de gamme', myinfomate: '179 €/mois HTVA — assistant IA et traduction automatique', competitor: 'Plan Premium à 9 500 £/an — parcours illimités, parcours personnalisés par IA' },
|
||||||
|
{ label: 'Borne tactile', myinfomate: 'Incluse dès le premier plan', competitor: 'Non proposée dans les plans publics' },
|
||||||
|
{ label: 'Escape game intégré', myinfomate: 'Oui, avec narration et énigmes', competitor: 'Jeux, quiz et badges' },
|
||||||
|
{ label: 'Langue de l\'interface et du support', myinfomate: 'Français, néerlandais, anglais, allemand — équipe à Namur', competitor: 'Anglais, équipe à Londres' },
|
||||||
|
],
|
||||||
|
fairTitle: 'Ce que Smartify fait mieux',
|
||||||
|
fair: [
|
||||||
|
"Son application grand public est déjà installée par des visiteurs qui l'ont utilisée ailleurs : un musée y gagne une visibilité que MyInfoMate ne procure pas.",
|
||||||
|
"Sa notoriété auprès des grandes institutions internationales rassure un comité, surtout hors de Belgique.",
|
||||||
|
"Son plan gratuit permet de tester la mise en ligne d'un parcours sans budget, ce que nous ne proposons pas — nous offrons 14 jours d'essai sur le plan Essentiel.",
|
||||||
|
],
|
||||||
|
differenceTitle: 'Ce que MyInfoMate apporte en plus',
|
||||||
|
differences: [
|
||||||
|
"Trois canaux depuis un seul back-office : application mobile, borne tactile et application web — la borne n'existe pas dans l'offre publique de Smartify.",
|
||||||
|
"Un assistant IA limité aux contenus de votre lieu, inclus à 179 €/mois.",
|
||||||
|
"Le mode hors ligne complet avec balises BLE, éprouvé dans un fort souterrain sans réseau.",
|
||||||
|
"Une interface et un support en français, et un interlocuteur à une heure de route de la plupart des musées wallons.",
|
||||||
|
"Un ordre de grandeur de prix différent : 2 148 €/an pour notre plan le plus complet, contre 9 500 £/an pour le Premium de Smartify.",
|
||||||
|
],
|
||||||
|
verdictTitle: 'Comment choisir, honnêtement',
|
||||||
|
verdict: [
|
||||||
|
"Si vous êtes une grande institution internationale, que votre public voyage et connaît déjà l'application Smartify, leur réseau a une valeur réelle que nous n'égalons pas.",
|
||||||
|
"Si vous êtes un musée régional, une commune ou un office du tourisme, avec un budget contraint, un besoin de borne à l'accueil et une équipe qui travaille en français, MyInfoMate est conçu pour ce cas-là.",
|
||||||
|
],
|
||||||
|
faq: [
|
||||||
|
{
|
||||||
|
question: 'MyInfoMate est-il moins cher que Smartify ?',
|
||||||
|
answer: "Oui, sur les plans comparables. MyInfoMate coûte 468 €/an en entrée de gamme et 2 148 €/an pour le plan Premium avec assistant IA. Smartify facture 1 800 £/an pour son plan Starter et 9 500 £/an pour son plan Premium, selon sa page tarifaire publique consultée le 10 septembre 2026. Smartify propose en revanche un plan gratuit limité que nous n'avons pas.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Smartify propose-t-il une borne tactile ?',
|
||||||
|
answer: "Pas dans ses plans publics, qui portent sur l'application grand public, une application web personnalisée et les contenus associés. MyInfoMate inclut le mode borne dès son premier plan, sur des tablettes Android standard.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: "Peut-on migrer des contenus depuis Smartify vers MyInfoMate ?",
|
||||||
|
answer: "Les contenus que vous avez rédigés — textes, images, fichiers audio — vous appartiennent et peuvent être réimportés dans le back-office MyInfoMate. Il n'existe pas d'import automatique : la reprise se fait manuellement, ou avec notre aide selon le volume.",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
sources: [
|
||||||
|
{ label: 'Page tarifaire Smartify (partners)', url: 'https://smartify.org/partners/pricing' },
|
||||||
|
{ label: 'Tarifs MyInfoMate', url: 'https://myinfomate.be/fr/tarifs' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
slug: 'myinfomate-vs-stqry',
|
||||||
|
competitor: 'STQRY',
|
||||||
|
title: 'MyInfoMate ou STQRY : comparatif pour musées et sites culturels',
|
||||||
|
description: "Comparatif factuel MyInfoMate / STQRY : tarifs publics relevés le 10 septembre 2026, frais uniques d'application native, canaux couverts et langue du support.",
|
||||||
|
checkedOn: '10 septembre 2026',
|
||||||
|
intro: "STQRY est une plateforme néo-zélandaise très implantée dans le monde anglophone, qui couvre l'application visiteur, les appareils prêtés sur site et une place de marché de parcours. MyInfoMate est une plateforme belge qui couvre l'application, la borne et le web depuis un seul back-office, en quatre langues.",
|
||||||
|
priceIntro: "STQRY facture en dollars américains, au mois ou à l'année, avec des frais uniques pour la publication d'une application native. MyInfoMate facture en euros hors TVA, au mois.",
|
||||||
|
rows: [
|
||||||
|
{ label: 'Entrée de gamme', myinfomate: '39 €/mois HTVA', competitor: 'Plan Standard à 199 $/mois (2 295 $/an), 10 parcours par application' },
|
||||||
|
{ label: 'Palier supérieur', myinfomate: '99 €/mois HTVA — application native incluse dans l\'abonnement', competitor: 'Plan Pro à +100 $/mois, soit environ 299 $/mois, 25 parcours' },
|
||||||
|
{ label: 'Application native sur les stores', myinfomate: 'Frais de mise en place uniques, chiffrés dans le devis, puis inclus dans l\'abonnement', competitor: 'Frais uniques annoncés à 2 000 $ pour la construction et la soumission aux stores' },
|
||||||
|
{ label: 'Assistant IA visiteur', myinfomate: 'Inclus à 179 €/mois, limité à vos contenus', competitor: 'Non annoncé dans les plans publics' },
|
||||||
|
{ label: 'Borne tactile', myinfomate: 'Incluse dès le premier plan', competitor: 'Offre séparée d\'appareils prêtés sur site (STQRY Fleet)' },
|
||||||
|
{ label: 'Langue de l\'interface et du support', myinfomate: 'Français, néerlandais, anglais, allemand — équipe à Namur', competitor: 'Anglais, équipes en Nouvelle-Zélande et aux États-Unis' },
|
||||||
|
],
|
||||||
|
fairTitle: 'Ce que STQRY fait mieux',
|
||||||
|
fair: [
|
||||||
|
"Un catalogue de fonctionnalités très large, construit sur plus d'une décennie, avec une place de marché où un visiteur peut découvrir des parcours d'autres lieux.",
|
||||||
|
"Une offre matérielle dédiée pour les sites qui veulent prêter des appareils plutôt que compter sur le téléphone du visiteur.",
|
||||||
|
"Une base installée importante dans le monde anglophone, utile si votre public est majoritairement international.",
|
||||||
|
],
|
||||||
|
differenceTitle: 'Ce que MyInfoMate apporte en plus',
|
||||||
|
differences: [
|
||||||
|
"Un support et une interface en français, néerlandais et allemand — STQRY traduit les contenus, mais son back-office et son accompagnement sont anglophones.",
|
||||||
|
"Un assistant IA visiteur inclus, strictement limité aux contenus du lieu.",
|
||||||
|
"Un escape game complet intégré au CMS, avec narration, énigmes et points cachés.",
|
||||||
|
"Un fuseau horaire compatible : un appel à 9 h du matin trouve quelqu'un.",
|
||||||
|
"Un coût d'entrée nettement inférieur : 39 €/mois contre 199 $/mois pour le plan Standard.",
|
||||||
|
],
|
||||||
|
verdictTitle: 'Comment choisir, honnêtement',
|
||||||
|
verdict: [
|
||||||
|
"Si vous prêtez des appareils à vos visiteurs et cherchez un fournisseur unique pour le matériel et le logiciel, l'offre Fleet de STQRY répond à un besoin que nous ne couvrons pas.",
|
||||||
|
"Si votre équipe travaille en français ou en néerlandais, que vous voulez une borne à l'accueil et un budget prévisible en euros, MyInfoMate est plus proche de votre réalité.",
|
||||||
|
],
|
||||||
|
faq: [
|
||||||
|
{
|
||||||
|
question: 'Combien coûte STQRY par rapport à MyInfoMate ?',
|
||||||
|
answer: "Selon les tarifs publiés par STQRY et consultés le 10 septembre 2026, le plan Standard est à 199 $/mois (2 295 $/an) et le plan Pro à environ 299 $/mois, avec des frais uniques annoncés à 2 000 $ pour publier une application native sur les stores. MyInfoMate démarre à 39 €/mois hors TVA, et son plan Pro à 99 €/mois inclut l'application native, avec des frais de mise en place chiffrés dans le devis.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'STQRY propose-t-il un assistant IA pour les visiteurs ?',
|
||||||
|
answer: "Ce n'est pas annoncé dans ses plans publics à la date de notre vérification. MyInfoMate inclut un assistant IA dans son plan Premium, limité aux contenus publiés par le lieu.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Et si nous voulons prêter des appareils à nos visiteurs ?',
|
||||||
|
answer: "STQRY propose une offre dédiée d'appareils gérés sur site. MyInfoMate fonctionne sur le téléphone du visiteur ou sur vos propres tablettes en mode borne, mais ne fournit pas de parc d'appareils prêtés.",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
sources: [
|
||||||
|
{ label: 'STQRY — coût d\'une application de visite', url: 'https://www.stqry.com/blog/how-much-does-it-cost-to-create-a-professional' },
|
||||||
|
{ label: 'STQRY Fleet', url: 'https://www.stqry.com/products/stqry-fleet' },
|
||||||
|
{ label: 'Tarifs MyInfoMate', url: 'https://myinfomate.be/fr/tarifs' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export function getAllComparisons() {
|
||||||
|
return comparisons;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getComparison(slug: string) {
|
||||||
|
return comparisons.find((comparison) => comparison.slug === slug);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getAllComparisonSlugs() {
|
||||||
|
return comparisons.map((comparison) => comparison.slug);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default comparisons;
|
||||||
@ -99,7 +99,7 @@ const musees: Segment = {
|
|||||||
hero: {
|
hero: {
|
||||||
badge: 'Musées & Patrimoine',
|
badge: 'Musées & Patrimoine',
|
||||||
title: 'Votre musée mérite une application à la hauteur de vos collections',
|
title: 'Votre musée mérite une application à la hauteur de vos collections',
|
||||||
subtitle: 'Audio guide, cartes interactives, escape game et assistant IA — tout dans un seul outil, sans ligne de code, dès €39/mois.',
|
subtitle: 'Médiation numérique, audio guide, cartes interactives, escape game et assistant IA — tout dans un seul outil, sans ligne de code, dès €39/mois.',
|
||||||
cta: 'Demander une démo gratuite',
|
cta: 'Demander une démo gratuite',
|
||||||
ctaSecondary: 'Voir les tarifs',
|
ctaSecondary: 'Voir les tarifs',
|
||||||
},
|
},
|
||||||
@ -127,14 +127,14 @@ const musees: Segment = {
|
|||||||
features: {
|
features: {
|
||||||
label: 'Ce que MyInfoMate fait pour vous',
|
label: 'Ce que MyInfoMate fait pour vous',
|
||||||
title: 'Tout ce qu\'un musée peut faire avec MyInfoMate',
|
title: 'Tout ce qu\'un musée peut faire avec MyInfoMate',
|
||||||
desc: 'Un seul outil no-code pour digitaliser votre expérience visiteur de A à Z — sans équipe technique, sans délai.',
|
desc: 'Un seul outil no-code pour construire votre parcours de visite et votre médiation numérique de A à Z — sans équipe technique, sans délai.',
|
||||||
valueLabel: 'Valeur ajoutée :',
|
valueLabel: 'Valeur ajoutée :',
|
||||||
items: [
|
items: [
|
||||||
{
|
{
|
||||||
icon: 'headphones',
|
icon: 'headphones',
|
||||||
title: 'Audio guide immersif',
|
title: 'Audio guide immersif',
|
||||||
desc: 'Créez votre audio guide directement dans le CMS : importez vos fichiers audio, associez-les à vos œuvres ou espaces. Vos visiteurs l\'écoutent sur leur propre smartphone.',
|
desc: 'Créez votre audio guide directement dans le CMS : importez vos fichiers audio, associez-les à vos œuvres ou espaces. Vos visiteurs l\'écoutent sur leur propre smartphone, sans matériel à louer ni à désinfecter.',
|
||||||
value: 'Un audio guide professionnel sans équipement à louer ni borne physique.',
|
value: 'Un audio guide professionnel sans borne physique — et un vrai gain d\'accessibilité pour les visiteurs qui lisent mal les cartels.',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: 'map',
|
icon: 'map',
|
||||||
@ -145,7 +145,7 @@ const musees: Segment = {
|
|||||||
{
|
{
|
||||||
icon: 'article',
|
icon: 'article',
|
||||||
title: 'Collections & PDF numérisés',
|
title: 'Collections & PDF numérisés',
|
||||||
desc: 'Fiches descriptives d\'œuvres, documents d\'archives, brochures PDF : toute votre documentation accessible en un clic depuis l\'application.',
|
desc: 'Cartels numériques, fiches descriptives d\'œuvres, documents d\'archives, brochures PDF : toute votre documentation accessible en un clic depuis l\'application, dans plusieurs langues.',
|
||||||
value: 'Digitalisez vos collections sans budget de développement.',
|
value: 'Digitalisez vos collections sans budget de développement.',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -236,6 +236,18 @@ const musees: Segment = {
|
|||||||
question: 'Est-il possible de proposer une tablette kiosk en plus de l\'application mobile ?',
|
question: 'Est-il possible de proposer une tablette kiosk en plus de l\'application mobile ?',
|
||||||
answer: 'Oui. MyInfoMate permet de déployer simultanément une application web/mobile pour les visiteurs BYOD (sur leur propre smartphone) et une application kiosk sur des tablettes fixes à l\'entrée ou dans les salles. Les deux affichent le même contenu, géré depuis un seul back-office.',
|
answer: 'Oui. MyInfoMate permet de déployer simultanément une application web/mobile pour les visiteurs BYOD (sur leur propre smartphone) et une application kiosk sur des tablettes fixes à l\'entrée ou dans les salles. Les deux affichent le même contenu, géré depuis un seul back-office.',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
question: 'MyInfoMate est-il conforme au RGPD ?',
|
||||||
|
answer: 'Les données sont hébergées dans l\'Union européenne. Les statistiques de visite sont anonymes : sections consultées, durée, langue, type d\'appareil — rien qui permette d\'identifier un visiteur. Si vous activez l\'assistant IA, les questions posées sont conservées 90 jours puis supprimées automatiquement, sans identifiant nominatif ni adresse IP. Le musée reste responsable de traitement, MyInfoMate agit comme sous-traitant. Le détail figure au point 8 de nos conditions générales et dans notre politique de confidentialité.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Un musée communal peut-il acheter MyInfoMate dans le cadre d\'un marché public ?',
|
||||||
|
answer: 'Oui. MyInfoMate a été retenu par l\'office du tourisme de Namur à l\'issue d\'un cahier des charges publié, et équipe des lieux publics belges depuis 2021. Pour les montants modestes, une commune ou un musée communal peut généralement commander sur simple devis, dans le cadre du régime des marchés de faible montant — le seuil applicable est à vérifier avec votre service marchés. Nous fournissons un devis détaillé et une description technique reprenant fonctionnalités, hébergement et traitement des données pour votre dossier.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'L\'application est-elle accessible aux publics en situation de handicap ?',
|
||||||
|
answer: 'L\'audio guide est un vrai gain pour les visiteurs qui lisent difficilement les cartels, et les contenus multilingues profitent aux visiteurs non francophones. L\'application respecte les réglages d\'accessibilité du téléphone du visiteur, notamment la taille de police. En revanche, soyons clairs : l\'application n\'est pas encore certifiée Access-i et nous n\'avons pas fait réaliser d\'audit d\'accessibilité formel. Si votre marché l\'exige, parlons-en avant votre dossier.',
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
cta: {
|
cta: {
|
||||||
@ -388,6 +400,18 @@ const musees: Segment = {
|
|||||||
question: 'Is it possible to have a kiosk tablet as well as the mobile app?',
|
question: 'Is it possible to have a kiosk tablet as well as the mobile app?',
|
||||||
answer: 'Yes. MyInfoMate allows you to deploy simultaneously a web/mobile app for BYOD visitors (on their own smartphone) and a kiosk app on fixed tablets at the entrance or in the rooms. Both display the same content, managed from a single back-office.',
|
answer: 'Yes. MyInfoMate allows you to deploy simultaneously a web/mobile app for BYOD visitors (on their own smartphone) and a kiosk app on fixed tablets at the entrance or in the rooms. Both display the same content, managed from a single back-office.',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
question: "Is MyInfoMate GDPR compliant?",
|
||||||
|
answer: "Data is hosted in the European Union. Visit statistics are anonymous — sections viewed, duration, language, device type — with nothing that could identify a visitor. If you enable the AI assistant, the questions asked are kept for 90 days and then deleted automatically, with no name and no IP address attached. The museum remains the data controller and MyInfoMate acts as processor. The details are in section 8 of our terms and conditions and in our privacy policy.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: "Can a municipal museum buy MyInfoMate through public procurement?",
|
||||||
|
answer: "Yes. MyInfoMate was selected by the Namur tourism office following a published call for tenders, and has been running in Belgian public venues since 2021. For modest amounts, a municipality or a municipal museum can usually order on a simple quotation, under the low-value contract regime — check the applicable threshold with your procurement department. We provide a detailed quotation and a technical description covering features, hosting and data processing for your file.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: "Is the app accessible to visitors with disabilities?",
|
||||||
|
answer: "The audio guide is a real gain for visitors who struggle to read wall labels, and multilingual content helps those who do not speak the local language. The app respects the accessibility settings of the visitor's phone, font size included. To be clear, though: the app is not yet Access-i certified and no formal accessibility audit has been carried out. If your tender requires it, let's talk before you file it.",
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
cta: {
|
cta: {
|
||||||
@ -540,6 +564,18 @@ const musees: Segment = {
|
|||||||
question: 'Is het mogelijk om zowel een tablet-kiosk als de mobiele app te hebben?',
|
question: 'Is het mogelijk om zowel een tablet-kiosk als de mobiele app te hebben?',
|
||||||
answer: 'Ja. MyInfoMate laat u toe om tegelijk een web/mobiele app voor BYOD-bezoekers (op hun eigen smartphone) en een kiosk-app op vaste tablets te implementeren. Beide tonen dezelfde inhoud, beheerd vanuit één back-office.',
|
answer: 'Ja. MyInfoMate laat u toe om tegelijk een web/mobiele app voor BYOD-bezoekers (op hun eigen smartphone) en een kiosk-app op vaste tablets te implementeren. Beide tonen dezelfde inhoud, beheerd vanuit één back-office.',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
question: "Is MyInfoMate conform de GDPR?",
|
||||||
|
answer: "De gegevens worden in de Europese Unie gehost. De bezoekstatistieken zijn anoniem — geraadpleegde secties, duur, taal, toesteltype — en laten niet toe een bezoeker te identificeren. Activeert u de AI-assistent, dan worden de gestelde vragen 90 dagen bewaard en daarna automatisch verwijderd, zonder naam en zonder IP-adres. Het museum blijft verwerkingsverantwoordelijke, MyInfoMate treedt op als verwerker. De details staan in punt 8 van onze algemene voorwaarden en in ons privacybeleid.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: "Kan een gemeentelijk museum MyInfoMate via een overheidsopdracht aankopen?",
|
||||||
|
answer: "Ja. MyInfoMate werd door het toerismekantoor van Namen geselecteerd na een gepubliceerd bestek en is sinds 2021 in Belgische openbare locaties in gebruik. Voor bescheiden bedragen kan een gemeente of een gemeentelijk museum meestal bestellen op eenvoudige offerte, binnen de regeling van opdrachten van beperkte waarde — de toepasselijke drempel controleert u best met uw dienst overheidsopdrachten. Wij bezorgen een gedetailleerde offerte en een technische beschrijving met functionaliteiten, hosting en gegevensverwerking voor uw dossier.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: "Is de app toegankelijk voor bezoekers met een beperking?",
|
||||||
|
answer: "De audiogids is een echte winst voor bezoekers die de zaalteksten moeilijk lezen, en meertalige inhoud helpt wie de landstaal niet spreekt. De app respecteert de toegankelijkheidsinstellingen van het toestel van de bezoeker, inclusief de lettergrootte. Maar laten we duidelijk zijn: de app is nog niet Access-i-gecertificeerd en er is geen formele toegankelijkheidsaudit uitgevoerd. Vereist uw opdracht dat, laat het ons weten vóór u uw dossier indient.",
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
cta: {
|
cta: {
|
||||||
@ -692,6 +728,18 @@ const musees: Segment = {
|
|||||||
question: 'Ist es möglich, sowohl einen Tablet-Kiosk als auch die mobile App zu haben?',
|
question: 'Ist es möglich, sowohl einen Tablet-Kiosk als auch die mobile App zu haben?',
|
||||||
answer: 'Ja. MyInfoMate ermöglicht die gleichzeitige Bereitstellung einer Web-/Mobil-App für BYOD-Besucher (auf ihrem eigenen Smartphone) und einer Kiosk-App auf fest installierten Tablets. Beide zeigen denselben Inhalt, verwaltet von einem einzigen Back-Office.',
|
answer: 'Ja. MyInfoMate ermöglicht die gleichzeitige Bereitstellung einer Web-/Mobil-App für BYOD-Besucher (auf ihrem eigenen Smartphone) und einer Kiosk-App auf fest installierten Tablets. Beide zeigen denselben Inhalt, verwaltet von einem einzigen Back-Office.',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
question: "Ist MyInfoMate DSGVO-konform?",
|
||||||
|
answer: "Die Daten werden in der Europäischen Union gehostet. Die Besuchsstatistiken sind anonym — aufgerufene Bereiche, Dauer, Sprache, Gerätetyp — und lassen keinen Rückschluss auf einen Besucher zu. Aktivieren Sie den KI-Assistenten, werden die gestellten Fragen 90 Tage gespeichert und danach automatisch gelöscht, ohne Namen und ohne IP-Adresse. Das Museum bleibt Verantwortlicher, MyInfoMate handelt als Auftragsverarbeiter. Details stehen in Punkt 8 unserer AGB und in unserer Datenschutzerklärung.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: "Kann ein kommunales Museum MyInfoMate über eine öffentliche Ausschreibung beschaffen?",
|
||||||
|
answer: "Ja. MyInfoMate wurde vom Tourismusbüro Namur nach einer veröffentlichten Ausschreibung ausgewählt und ist seit 2021 in belgischen öffentlichen Einrichtungen im Einsatz. Bei geringen Beträgen kann eine Gemeinde oder ein kommunales Museum in der Regel auf einfaches Angebot bestellen, im Rahmen der Regelung für Aufträge geringen Wertes — den geltenden Schwellenwert klären Sie am besten mit Ihrer Vergabestelle. Wir liefern ein detailliertes Angebot und eine technische Beschreibung zu Funktionen, Hosting und Datenverarbeitung für Ihre Akte.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: "Ist die App für Besucher mit Behinderung zugänglich?",
|
||||||
|
answer: "Der Audioguide ist ein echter Gewinn für Besucher, die Saaltexte schwer lesen können, und mehrsprachige Inhalte helfen jenen, die die Landessprache nicht sprechen. Die App übernimmt die Barrierefreiheitseinstellungen des Besuchergeräts, einschließlich der Schriftgröße. Klar gesagt: Die App ist noch nicht Access-i-zertifiziert und es wurde kein formelles Barrierefreiheits-Audit durchgeführt. Verlangt Ihre Ausschreibung das, sprechen wir vor der Einreichung darüber.",
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
cta: {
|
cta: {
|
||||||
@ -758,7 +806,7 @@ const officesDeToursime: Segment = {
|
|||||||
features: {
|
features: {
|
||||||
label: 'Ce que MyInfoMate fait pour vous',
|
label: 'Ce que MyInfoMate fait pour vous',
|
||||||
title: 'Tout ce qu\'un office de tourisme peut faire avec MyInfoMate',
|
title: 'Tout ce qu\'un office de tourisme peut faire avec MyInfoMate',
|
||||||
desc: 'Une plateforme complète pour valoriser votre territoire et engager vos visiteurs — en ligne, sur tablette et sur mobile.',
|
desc: 'Une plateforme complète de médiation numérique pour valoriser votre territoire et engager vos visiteurs — en ligne, sur tablette et sur mobile.',
|
||||||
valueLabel: 'Valeur ajoutée :',
|
valueLabel: 'Valeur ajoutée :',
|
||||||
items: [
|
items: [
|
||||||
{
|
{
|
||||||
@ -867,6 +915,18 @@ const officesDeToursime: Segment = {
|
|||||||
question: 'Quelle est la différence entre MyInfoMate et GuidiGO ?',
|
question: 'Quelle est la différence entre MyInfoMate et GuidiGO ?',
|
||||||
answer: 'MyInfoMate inclut un agenda & événements, un kiosk tablette, des push notifications, un escape game complet avec narration et une chasse au trésor avec points cachés — GuidiGO propose une gamification basique (badges, quiz) sans ces fonctionnalités. MyInfoMate ne limite pas le nombre de tours ou de contenus, contrairement à GuidiGO. Les prix sont similaires pour un périmètre bien plus large.',
|
answer: 'MyInfoMate inclut un agenda & événements, un kiosk tablette, des push notifications, un escape game complet avec narration et une chasse au trésor avec points cachés — GuidiGO propose une gamification basique (badges, quiz) sans ces fonctionnalités. MyInfoMate ne limite pas le nombre de tours ou de contenus, contrairement à GuidiGO. Les prix sont similaires pour un périmètre bien plus large.',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
question: 'Un office du tourisme peut-il acheter MyInfoMate dans le cadre d\'un marché public ?',
|
||||||
|
answer: 'Oui. L\'office du tourisme de Namur a retenu MyInfoMate à l\'issue d\'un cahier des charges publié, et ses bornes interactives sont en service depuis 2024. Pour les montants modestes, une commune, une province ou une maison du tourisme peut généralement commander sur simple devis, dans le cadre du régime des marchés de faible montant — le seuil applicable est à vérifier avec votre service marchés. Nous fournissons un devis détaillé et une description technique reprenant fonctionnalités, hébergement et traitement des données pour votre dossier.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'MyInfoMate est-il conforme au RGPD ?',
|
||||||
|
answer: 'Les données sont hébergées dans l\'Union européenne. Les statistiques de fréquentation sont anonymes : sections consultées, durée, langue, type d\'appareil — rien qui permette d\'identifier un visiteur. Si vous activez l\'assistant IA, les questions posées sont conservées 90 jours puis supprimées automatiquement, sans identifiant nominatif ni adresse IP. L\'office reste responsable de traitement, MyInfoMate agit comme sous-traitant. Le détail figure au point 8 de nos conditions générales et dans notre politique de confidentialité.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'La solution est-elle accessible aux publics en situation de handicap ?',
|
||||||
|
answer: 'L\'audio et les contenus multilingues profitent aux visiteurs qui lisent difficilement les panneaux ou ne parlent pas français, et l\'application respecte les réglages d\'accessibilité du téléphone, notamment la taille de police. Sur une borne, la hauteur d\'installation compte autant que le logiciel : nous en parlons avant le déploiement. En revanche, soyons clairs : nous ne sommes pas encore certifiés Access-i et aucun audit d\'accessibilité formel n\'a été réalisé. Si votre marché l\'exige, parlons-en avant votre dossier.',
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
cta: {
|
cta: {
|
||||||
@ -1019,6 +1079,18 @@ const officesDeToursime: Segment = {
|
|||||||
question: 'What is the difference between MyInfoMate and GuidiGO?',
|
question: 'What is the difference between MyInfoMate and GuidiGO?',
|
||||||
answer: 'MyInfoMate includes an event agenda, tablet kiosk, push notifications, a full escape game with narrative, and a treasure hunt with hidden points — GuidiGO offers basic gamification (badges, quizzes) without these features. MyInfoMate does not limit the number of tours or content, unlike GuidiGO. Prices are similar for a much broader scope.',
|
answer: 'MyInfoMate includes an event agenda, tablet kiosk, push notifications, a full escape game with narrative, and a treasure hunt with hidden points — GuidiGO offers basic gamification (badges, quizzes) without these features. MyInfoMate does not limit the number of tours or content, unlike GuidiGO. Prices are similar for a much broader scope.',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
question: "Can a tourism office buy MyInfoMate through public procurement?",
|
||||||
|
answer: "Yes. The Namur tourism office selected MyInfoMate following a published call for tenders, and its interactive kiosks have been in service since 2024. For modest amounts, a municipality, a province or a tourism house can usually order on a simple quotation, under the low-value contract regime — check the applicable threshold with your procurement department. We provide a detailed quotation and a technical description covering features, hosting and data processing for your file.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: "Is MyInfoMate GDPR compliant?",
|
||||||
|
answer: "Data is hosted in the European Union. Visitor statistics are anonymous — sections viewed, duration, language, device type — with nothing that could identify a visitor. If you enable the AI assistant, the questions asked are kept for 90 days and then deleted automatically, with no name and no IP address attached. The tourism office remains the data controller and MyInfoMate acts as processor. The details are in section 8 of our terms and conditions.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: "Is the solution accessible to visitors with disabilities?",
|
||||||
|
answer: "Audio and multilingual content help visitors who struggle to read panels or do not speak the local language, and the app respects the accessibility settings of the phone, font size included. On a kiosk, the mounting height matters as much as the software: we discuss it before installation. To be clear, though: we are not yet Access-i certified and no formal accessibility audit has been carried out. If your tender requires it, let's talk before you file it.",
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
cta: {
|
cta: {
|
||||||
@ -1171,6 +1243,18 @@ const officesDeToursime: Segment = {
|
|||||||
question: 'Wat is het verschil tussen MyInfoMate en GuidiGO?',
|
question: 'Wat is het verschil tussen MyInfoMate en GuidiGO?',
|
||||||
answer: 'MyInfoMate bevat een evenementenagenda, tablet-kiosk, pushmeldingen, een volledig escape game met verhaal en een schattenjacht met verborgen punten — GuidiGO biedt basale gamificatie (badges, quizzen) zonder deze functies. MyInfoMate beperkt het aantal tours of inhoud niet, in tegenstelling tot GuidiGO. Prijzen zijn vergelijkbaar voor een veel breder bereik.',
|
answer: 'MyInfoMate bevat een evenementenagenda, tablet-kiosk, pushmeldingen, een volledig escape game met verhaal en een schattenjacht met verborgen punten — GuidiGO biedt basale gamificatie (badges, quizzen) zonder deze functies. MyInfoMate beperkt het aantal tours of inhoud niet, in tegenstelling tot GuidiGO. Prijzen zijn vergelijkbaar voor een veel breder bereik.',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
question: "Kan een toerismekantoor MyInfoMate via een overheidsopdracht aankopen?",
|
||||||
|
answer: "Ja. Het toerismekantoor van Namen koos MyInfoMate na een gepubliceerd bestek; de interactieve kiosken draaien er sinds 2024. Voor bescheiden bedragen kan een gemeente, een provincie of een toeristisch huis meestal bestellen op eenvoudige offerte, binnen de regeling van opdrachten van beperkte waarde — de toepasselijke drempel controleert u best met uw dienst overheidsopdrachten. Wij bezorgen een gedetailleerde offerte en een technische beschrijving voor uw dossier.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: "Is MyInfoMate conform de GDPR?",
|
||||||
|
answer: "De gegevens worden in de Europese Unie gehost. De bezoekcijfers zijn anoniem — geraadpleegde secties, duur, taal, toesteltype — en laten niet toe een bezoeker te identificeren. Activeert u de AI-assistent, dan worden de gestelde vragen 90 dagen bewaard en daarna automatisch verwijderd, zonder naam en zonder IP-adres. Het toerismekantoor blijft verwerkingsverantwoordelijke, MyInfoMate treedt op als verwerker. De details staan in punt 8 van onze algemene voorwaarden.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: "Is de oplossing toegankelijk voor bezoekers met een beperking?",
|
||||||
|
answer: "Audio en meertalige inhoud helpen bezoekers die borden moeilijk lezen of de landstaal niet spreken, en de app respecteert de toegankelijkheidsinstellingen van het toestel, inclusief de lettergrootte. Bij een kiosk telt de plaatsingshoogte even hard mee als de software: dat bespreken we vóór de installatie. Maar laten we duidelijk zijn: we zijn nog niet Access-i-gecertificeerd en er is geen formele toegankelijkheidsaudit uitgevoerd. Vereist uw opdracht dat, laat het ons weten vóór u uw dossier indient.",
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
cta: {
|
cta: {
|
||||||
@ -1323,6 +1407,18 @@ const officesDeToursime: Segment = {
|
|||||||
question: 'Was ist der Unterschied zwischen MyInfoMate und GuidiGO?',
|
question: 'Was ist der Unterschied zwischen MyInfoMate und GuidiGO?',
|
||||||
answer: 'MyInfoMate enthält einen Veranstaltungskalender, Tablet-Kiosk, Push-Benachrichtigungen, ein vollständiges Escape Game mit Handlung und eine Schatzsuche mit verborgenen Punkten — GuidiGO bietet grundlegende Gamification (Abzeichen, Quiz) ohne diese Funktionen. MyInfoMate begrenzt die Anzahl der Touren oder Inhalte nicht, im Gegensatz zu GuidiGO.',
|
answer: 'MyInfoMate enthält einen Veranstaltungskalender, Tablet-Kiosk, Push-Benachrichtigungen, ein vollständiges Escape Game mit Handlung und eine Schatzsuche mit verborgenen Punkten — GuidiGO bietet grundlegende Gamification (Abzeichen, Quiz) ohne diese Funktionen. MyInfoMate begrenzt die Anzahl der Touren oder Inhalte nicht, im Gegensatz zu GuidiGO.',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
question: "Kann ein Tourismusbüro MyInfoMate über eine öffentliche Ausschreibung beschaffen?",
|
||||||
|
answer: "Ja. Das Tourismusbüro Namur hat MyInfoMate nach einer veröffentlichten Ausschreibung ausgewählt; die interaktiven Kioske sind dort seit 2024 in Betrieb. Bei geringen Beträgen kann eine Gemeinde, eine Provinz oder ein Tourismusverband in der Regel auf einfaches Angebot bestellen, im Rahmen der Regelung für Aufträge geringen Wertes — den geltenden Schwellenwert klären Sie am besten mit Ihrer Vergabestelle. Wir liefern ein detailliertes Angebot und eine technische Beschreibung für Ihre Akte.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: "Ist MyInfoMate DSGVO-konform?",
|
||||||
|
answer: "Die Daten werden in der Europäischen Union gehostet. Die Besucherzahlen sind anonym — aufgerufene Bereiche, Dauer, Sprache, Gerätetyp — und lassen keinen Rückschluss auf einen Besucher zu. Aktivieren Sie den KI-Assistenten, werden die gestellten Fragen 90 Tage gespeichert und danach automatisch gelöscht, ohne Namen und ohne IP-Adresse. Das Tourismusbüro bleibt Verantwortlicher, MyInfoMate handelt als Auftragsverarbeiter. Details stehen in Punkt 8 unserer AGB.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: "Ist die Lösung für Besucher mit Behinderung zugänglich?",
|
||||||
|
answer: "Audio und mehrsprachige Inhalte helfen Besuchern, die Tafeln schwer lesen oder die Landessprache nicht sprechen, und die App übernimmt die Barrierefreiheitseinstellungen des Geräts, einschließlich der Schriftgröße. Bei einem Kiosk zählt die Montagehöhe ebenso wie die Software: Das besprechen wir vor der Installation. Klar gesagt: Wir sind noch nicht Access-i-zertifiziert und es wurde kein formelles Barrierefreiheits-Audit durchgeführt. Verlangt Ihre Ausschreibung das, sprechen wir vor der Einreichung darüber.",
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
cta: {
|
cta: {
|
||||||
@ -1389,7 +1485,7 @@ const parcsNaturels: Segment = {
|
|||||||
features: {
|
features: {
|
||||||
label: 'Ce que MyInfoMate fait pour vous',
|
label: 'Ce que MyInfoMate fait pour vous',
|
||||||
title: 'Tout ce qu\'un parc naturel peut faire avec MyInfoMate',
|
title: 'Tout ce qu\'un parc naturel peut faire avec MyInfoMate',
|
||||||
desc: 'Une plateforme pensée pour les espaces naturels : géolocalisation, mode hors ligne et engagement famille, sans équipe technique.',
|
desc: 'Une plateforme de médiation numérique pensée pour les espaces naturels : parcours de visite géolocalisés, mode hors ligne et engagement famille, sans équipe technique.',
|
||||||
valueLabel: 'Valeur ajoutée :',
|
valueLabel: 'Valeur ajoutée :',
|
||||||
items: [
|
items: [
|
||||||
{
|
{
|
||||||
@ -1494,6 +1590,14 @@ const parcsNaturels: Segment = {
|
|||||||
question: 'Peut-on gérer un agenda d\'ateliers et de sorties guidées ?',
|
question: 'Peut-on gérer un agenda d\'ateliers et de sorties guidées ?',
|
||||||
answer: 'Oui. MyInfoMate dispose d\'un module Agenda & Événements natif. Vous publiez vos sorties nature, ateliers pédagogiques et événements saisonniers depuis le back-office, et les visiteurs peuvent les consulter et recevoir des rappels.',
|
answer: 'Oui. MyInfoMate dispose d\'un module Agenda & Événements natif. Vous publiez vos sorties nature, ateliers pédagogiques et événements saisonniers depuis le back-office, et les visiteurs peuvent les consulter et recevoir des rappels.',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
question: 'Un parc géré par une commune ou une intercommunale peut-il l\'acheter en marché public ?',
|
||||||
|
answer: 'Oui. MyInfoMate équipe des lieux publics belges depuis 2021 et a été retenu par l\'office du tourisme de Namur à l\'issue d\'un cahier des charges publié. Pour les montants modestes, une commune, une intercommunale ou un parc naturel peut généralement commander sur simple devis, dans le cadre du régime des marchés de faible montant — le seuil applicable est à vérifier avec votre service marchés. Nous fournissons un devis détaillé et une description technique reprenant fonctionnalités, hébergement et traitement des données pour votre dossier.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'MyInfoMate est-il conforme au RGPD ?',
|
||||||
|
answer: 'Les données sont hébergées dans l\'Union européenne. Les statistiques de fréquentation des sentiers sont anonymes : sections consultées, durée, langue, type d\'appareil — rien qui permette d\'identifier un promeneur. Si vous activez l\'assistant IA, les questions posées sont conservées 90 jours puis supprimées automatiquement, sans identifiant nominatif ni adresse IP. Le gestionnaire du site reste responsable de traitement, MyInfoMate agit comme sous-traitant. Le détail figure au point 8 de nos conditions générales.',
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
cta: {
|
cta: {
|
||||||
@ -1642,6 +1746,14 @@ const parcsNaturels: Segment = {
|
|||||||
question: 'Can we manage a workshop and guided outings agenda?',
|
question: 'Can we manage a workshop and guided outings agenda?',
|
||||||
answer: 'Yes. MyInfoMate has a native Agenda & Events module. You publish your nature outings, educational workshops and seasonal events from the back-office, and visitors can browse them and receive reminders.',
|
answer: 'Yes. MyInfoMate has a native Agenda & Events module. You publish your nature outings, educational workshops and seasonal events from the back-office, and visitors can browse them and receive reminders.',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
question: "Can a park run by a municipality or an inter-municipal body buy it through public procurement?",
|
||||||
|
answer: "Yes. MyInfoMate has been running in Belgian public venues since 2021 and was selected by the Namur tourism office following a published call for tenders. For modest amounts, a municipality, an inter-municipal body or a nature park can usually order on a simple quotation, under the low-value contract regime — check the applicable threshold with your procurement department. We provide a detailed quotation and a technical description for your file.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: "Is MyInfoMate GDPR compliant?",
|
||||||
|
answer: "Data is hosted in the European Union. Trail statistics are anonymous — sections viewed, duration, language, device type — with nothing that could identify a walker. If you enable the AI assistant, the questions asked are kept for 90 days and then deleted automatically, with no name and no IP address attached. The site operator remains the data controller and MyInfoMate acts as processor. The details are in section 8 of our terms and conditions.",
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
cta: {
|
cta: {
|
||||||
@ -1790,6 +1902,14 @@ const parcsNaturels: Segment = {
|
|||||||
question: 'Kunnen we een agenda van workshops en geleide uitstappen beheren?',
|
question: 'Kunnen we een agenda van workshops en geleide uitstappen beheren?',
|
||||||
answer: 'Ja. MyInfoMate beschikt over een native Agenda & Evenementen-module. U publiceert uw natuuruitstappen, educatieve workshops en seizoensgebonden evenementen vanuit het back-office, en bezoekers kunnen deze raadplegen en herinneringen ontvangen.',
|
answer: 'Ja. MyInfoMate beschikt over een native Agenda & Evenementen-module. U publiceert uw natuuruitstappen, educatieve workshops en seizoensgebonden evenementen vanuit het back-office, en bezoekers kunnen deze raadplegen en herinneringen ontvangen.',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
question: "Kan een park beheerd door een gemeente of intercommunale het via een overheidsopdracht aankopen?",
|
||||||
|
answer: "Ja. MyInfoMate is sinds 2021 in Belgische openbare locaties in gebruik en werd door het toerismekantoor van Namen geselecteerd na een gepubliceerd bestek. Voor bescheiden bedragen kan een gemeente, een intercommunale of een natuurpark meestal bestellen op eenvoudige offerte, binnen de regeling van opdrachten van beperkte waarde — de toepasselijke drempel controleert u best met uw dienst overheidsopdrachten. Wij bezorgen een gedetailleerde offerte en een technische beschrijving voor uw dossier.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: "Is MyInfoMate conform de GDPR?",
|
||||||
|
answer: "De gegevens worden in de Europese Unie gehost. De cijfers over het gebruik van de wandelpaden zijn anoniem — geraadpleegde secties, duur, taal, toesteltype — en laten niet toe een wandelaar te identificeren. Activeert u de AI-assistent, dan worden de gestelde vragen 90 dagen bewaard en daarna automatisch verwijderd. De beheerder van het gebied blijft verwerkingsverantwoordelijke, MyInfoMate treedt op als verwerker. De details staan in punt 8 van onze algemene voorwaarden.",
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
cta: {
|
cta: {
|
||||||
@ -1938,6 +2058,14 @@ const parcsNaturels: Segment = {
|
|||||||
question: 'Können wir einen Workshop- und Tourenkalender verwalten?',
|
question: 'Können wir einen Workshop- und Tourenkalender verwalten?',
|
||||||
answer: 'Ja. MyInfoMate verfügt über ein natives Agenda & Veranstaltungen-Modul. Sie veröffentlichen Ihre Naturausflüge, pädagogischen Workshops und saisonalen Veranstaltungen aus dem Back-Office, und Besucher können sie ansehen und Erinnerungen erhalten.',
|
answer: 'Ja. MyInfoMate verfügt über ein natives Agenda & Veranstaltungen-Modul. Sie veröffentlichen Ihre Naturausflüge, pädagogischen Workshops und saisonalen Veranstaltungen aus dem Back-Office, und Besucher können sie ansehen und Erinnerungen erhalten.',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
question: "Kann ein von einer Gemeinde oder einem Gemeindeverband betriebener Park ihn öffentlich beschaffen?",
|
||||||
|
answer: "Ja. MyInfoMate ist seit 2021 in belgischen öffentlichen Einrichtungen im Einsatz und wurde vom Tourismusbüro Namur nach einer veröffentlichten Ausschreibung ausgewählt. Bei geringen Beträgen kann eine Gemeinde, ein Gemeindeverband oder ein Naturpark in der Regel auf einfaches Angebot bestellen, im Rahmen der Regelung für Aufträge geringen Wertes — den geltenden Schwellenwert klären Sie am besten mit Ihrer Vergabestelle. Wir liefern ein detailliertes Angebot und eine technische Beschreibung für Ihre Akte.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: "Ist MyInfoMate DSGVO-konform?",
|
||||||
|
answer: "Die Daten werden in der Europäischen Union gehostet. Die Nutzungsstatistiken der Wege sind anonym — aufgerufene Bereiche, Dauer, Sprache, Gerätetyp — und lassen keinen Rückschluss auf einen Wanderer zu. Aktivieren Sie den KI-Assistenten, werden die gestellten Fragen 90 Tage gespeichert und danach automatisch gelöscht. Der Betreiber des Geländes bleibt Verantwortlicher, MyInfoMate handelt als Auftragsverarbeiter. Details stehen in Punkt 8 unserer AGB.",
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
cta: {
|
cta: {
|
||||||
@ -2109,6 +2237,10 @@ const hotelsLoisirs: Segment = {
|
|||||||
question: 'L\'application est-elle disponible en plusieurs langues ?',
|
question: 'L\'application est-elle disponible en plusieurs langues ?',
|
||||||
answer: 'Oui. Le back-office supporte la gestion multilingue manuelle, et les plans Pro et Premium incluent la traduction automatique par IA. Le concierge virtuel répond dans la langue du client — français, anglais, néerlandais, allemand et bien d\'autres — sans configuration supplémentaire.',
|
answer: 'Oui. Le back-office supporte la gestion multilingue manuelle, et les plans Pro et Premium incluent la traduction automatique par IA. Le concierge virtuel répond dans la langue du client — français, anglais, néerlandais, allemand et bien d\'autres — sans configuration supplémentaire.',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
question: 'Que deviennent les données de nos clients ? Êtes-vous conforme au RGPD ?',
|
||||||
|
answer: 'Les données sont hébergées dans l\'Union européenne. MyInfoMate ne demande aucun compte au client de l\'hôtel : les statistiques d\'usage sont anonymes — sections consultées, durée, langue, type d\'appareil. Si vous activez le concierge IA, les questions posées sont conservées 90 jours puis supprimées automatiquement, sans identifiant nominatif ni adresse IP. L\'établissement reste responsable de traitement, MyInfoMate agit comme sous-traitant. Le détail figure au point 8 de nos conditions générales et dans notre politique de confidentialité.',
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
cta: {
|
cta: {
|
||||||
@ -2257,6 +2389,10 @@ const hotelsLoisirs: Segment = {
|
|||||||
question: 'Is the app available in multiple languages?',
|
question: 'Is the app available in multiple languages?',
|
||||||
answer: 'Yes. The back-office supports manual multilingual content management, and Pro and Premium plans include AI-powered automatic translation. The virtual concierge responds in the guest\'s language — French, English, Dutch, German and many more — with no extra setup.',
|
answer: 'Yes. The back-office supports manual multilingual content management, and Pro and Premium plans include AI-powered automatic translation. The virtual concierge responds in the guest\'s language — French, English, Dutch, German and many more — with no extra setup.',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
question: "What happens to our guests' data? Are you GDPR compliant?",
|
||||||
|
answer: "Data is hosted in the European Union. MyInfoMate asks the hotel guest for no account at all: usage statistics are anonymous — sections viewed, duration, language, device type. If you enable the AI concierge, the questions asked are kept for 90 days and then deleted automatically, with no name and no IP address attached. The property remains the data controller and MyInfoMate acts as processor. The details are in section 8 of our terms and conditions and in our privacy policy.",
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
cta: {
|
cta: {
|
||||||
@ -2405,6 +2541,10 @@ const hotelsLoisirs: Segment = {
|
|||||||
question: 'Is de app beschikbaar in meerdere talen?',
|
question: 'Is de app beschikbaar in meerdere talen?',
|
||||||
answer: 'Ja. Het back-office ondersteunt handmatig meertalig beheer, en Pro- en Premium-abonnementen omvatten automatische AI-vertaling. De virtuele conciërge antwoordt in de taal van de gast — Frans, Engels, Nederlands, Duits en vele andere — zonder extra configuratie.',
|
answer: 'Ja. Het back-office ondersteunt handmatig meertalig beheer, en Pro- en Premium-abonnementen omvatten automatische AI-vertaling. De virtuele conciërge antwoordt in de taal van de gast — Frans, Engels, Nederlands, Duits en vele andere — zonder extra configuratie.',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
question: "Wat gebeurt er met de gegevens van onze gasten? Zijn jullie GDPR-conform?",
|
||||||
|
answer: "De gegevens worden in de Europese Unie gehost. MyInfoMate vraagt de hotelgast geen enkel account: de gebruiksstatistieken zijn anoniem — geraadpleegde secties, duur, taal, toesteltype. Activeert u de AI-conciërge, dan worden de gestelde vragen 90 dagen bewaard en daarna automatisch verwijderd, zonder naam en zonder IP-adres. Het hotel blijft verwerkingsverantwoordelijke, MyInfoMate treedt op als verwerker. De details staan in punt 8 van onze algemene voorwaarden.",
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
cta: {
|
cta: {
|
||||||
@ -2553,6 +2693,10 @@ const hotelsLoisirs: Segment = {
|
|||||||
question: 'Ist die App in mehreren Sprachen verfügbar?',
|
question: 'Ist die App in mehreren Sprachen verfügbar?',
|
||||||
answer: 'Ja. Das Back-Office unterstützt manuelle mehrsprachige Verwaltung, und Pro- und Premium-Pläne umfassen automatische KI-Übersetzung. Der virtuelle Concierge antwortet in der Sprache des Gastes — Französisch, Englisch, Niederländisch, Deutsch und viele mehr — ohne zusätzliche Konfiguration.',
|
answer: 'Ja. Das Back-Office unterstützt manuelle mehrsprachige Verwaltung, und Pro- und Premium-Pläne umfassen automatische KI-Übersetzung. Der virtuelle Concierge antwortet in der Sprache des Gastes — Französisch, Englisch, Niederländisch, Deutsch und viele mehr — ohne zusätzliche Konfiguration.',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
question: "Was geschieht mit den Daten unserer Gäste? Sind Sie DSGVO-konform?",
|
||||||
|
answer: "Die Daten werden in der Europäischen Union gehostet. MyInfoMate verlangt vom Hotelgast kein Konto: Die Nutzungsstatistiken sind anonym — aufgerufene Bereiche, Dauer, Sprache, Gerätetyp. Aktivieren Sie den KI-Concierge, werden die gestellten Fragen 90 Tage gespeichert und danach automatisch gelöscht, ohne Namen und ohne IP-Adresse. Das Haus bleibt Verantwortlicher, MyInfoMate handelt als Auftragsverarbeiter. Details stehen in Punkt 8 unserer AGB.",
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
cta: {
|
cta: {
|
||||||
@ -2724,6 +2868,14 @@ const evenements: Segment = {
|
|||||||
question: 'L\'application est-elle multilingue pour les événements internationaux ?',
|
question: 'L\'application est-elle multilingue pour les événements internationaux ?',
|
||||||
answer: 'Oui. Le back-office supporte la gestion multilingue, et les plans Pro et Premium incluent la traduction automatique par IA. Idéal pour les salons et conférences avec un public international — votre contenu est disponible dans toutes les langues sans effort de traduction manuelle.',
|
answer: 'Oui. Le back-office supporte la gestion multilingue, et les plans Pro et Premium incluent la traduction automatique par IA. Idéal pour les salons et conférences avec un public international — votre contenu est disponible dans toutes les langues sans effort de traduction manuelle.',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
question: 'MyInfoMate est-il conforme au RGPD ?',
|
||||||
|
answer: 'Les données sont hébergées dans l\'Union européenne. Aucun compte n\'est demandé au participant : les statistiques de fréquentation sont anonymes — sections consultées, durée, langue, type d\'appareil. Si vous activez l\'assistant IA, les questions posées sont conservées 90 jours puis supprimées automatiquement, sans identifiant nominatif ni adresse IP. L\'organisateur reste responsable de traitement, MyInfoMate agit comme sous-traitant. Le détail figure au point 8 de nos conditions générales.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Une commune ou une ASBL subsidiée peut-elle l\'acheter en marché public ?',
|
||||||
|
answer: 'Oui. MyInfoMate équipe des lieux publics belges depuis 2021 et a été retenu par l\'office du tourisme de Namur à l\'issue d\'un cahier des charges publié. Pour un événement au budget modeste, une commune ou une ASBL peut généralement commander sur simple devis, dans le cadre du régime des marchés de faible montant — le seuil applicable est à vérifier avec votre service marchés. Nous fournissons un devis détaillé et une description technique pour votre dossier.',
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
cta: {
|
cta: {
|
||||||
@ -2872,6 +3024,14 @@ const evenements: Segment = {
|
|||||||
question: 'Is the app multilingual for international events?',
|
question: 'Is the app multilingual for international events?',
|
||||||
answer: 'Yes. The back-office supports multilingual content management, and Pro and Premium plans include AI-powered automatic translation. Perfect for international trade shows and conferences — your content is available in any language with no manual translation effort.',
|
answer: 'Yes. The back-office supports multilingual content management, and Pro and Premium plans include AI-powered automatic translation. Perfect for international trade shows and conferences — your content is available in any language with no manual translation effort.',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
question: "Is MyInfoMate GDPR compliant?",
|
||||||
|
answer: "Data is hosted in the European Union. Attendees are asked for no account: attendance statistics are anonymous — sections viewed, duration, language, device type. If you enable the AI assistant, the questions asked are kept for 90 days and then deleted automatically, with no name and no IP address attached. The organiser remains the data controller and MyInfoMate acts as processor. The details are in section 8 of our terms and conditions.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: "Can a municipality or a subsidised non-profit buy it through public procurement?",
|
||||||
|
answer: "Yes. MyInfoMate has been running in Belgian public venues since 2021 and was selected by the Namur tourism office following a published call for tenders. For an event with a modest budget, a municipality or a non-profit can usually order on a simple quotation, under the low-value contract regime — check the applicable threshold with your procurement department. We provide a detailed quotation and a technical description for your file.",
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
cta: {
|
cta: {
|
||||||
@ -3020,6 +3180,14 @@ const evenements: Segment = {
|
|||||||
question: 'Is de app meertalig voor internationale evenementen?',
|
question: 'Is de app meertalig voor internationale evenementen?',
|
||||||
answer: 'Ja. Het back-office ondersteunt meertalig contentbeheer, en Pro- en Premium-abonnementen omvatten automatische AI-vertaling. Ideaal voor internationale beurzen en conferenties — uw inhoud is in elke taal beschikbaar zonder handmatige vertaalinspanning.',
|
answer: 'Ja. Het back-office ondersteunt meertalig contentbeheer, en Pro- en Premium-abonnementen omvatten automatische AI-vertaling. Ideaal voor internationale beurzen en conferenties — uw inhoud is in elke taal beschikbaar zonder handmatige vertaalinspanning.',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
question: "Is MyInfoMate conform de GDPR?",
|
||||||
|
answer: "De gegevens worden in de Europese Unie gehost. Aan de deelnemer wordt geen account gevraagd: de bezoekcijfers zijn anoniem — geraadpleegde secties, duur, taal, toesteltype. Activeert u de AI-assistent, dan worden de gestelde vragen 90 dagen bewaard en daarna automatisch verwijderd, zonder naam en zonder IP-adres. De organisator blijft verwerkingsverantwoordelijke, MyInfoMate treedt op als verwerker. De details staan in punt 8 van onze algemene voorwaarden.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: "Kan een gemeente of een gesubsidieerde vzw het via een overheidsopdracht aankopen?",
|
||||||
|
answer: "Ja. MyInfoMate is sinds 2021 in Belgische openbare locaties in gebruik en werd door het toerismekantoor van Namen geselecteerd na een gepubliceerd bestek. Voor een evenement met een bescheiden budget kan een gemeente of een vzw meestal bestellen op eenvoudige offerte, binnen de regeling van opdrachten van beperkte waarde — de toepasselijke drempel controleert u best met uw dienst overheidsopdrachten. Wij bezorgen een gedetailleerde offerte en een technische beschrijving voor uw dossier.",
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
cta: {
|
cta: {
|
||||||
@ -3168,6 +3336,14 @@ const evenements: Segment = {
|
|||||||
question: 'Ist die App mehrsprachig für internationale Veranstaltungen?',
|
question: 'Ist die App mehrsprachig für internationale Veranstaltungen?',
|
||||||
answer: 'Ja. Das Back-Office unterstützt mehrsprachige Inhaltsverwaltung, und Pro- und Premium-Pläne umfassen automatische KI-Übersetzung. Ideal für internationale Messen und Konferenzen — Ihr Inhalt ist in jeder Sprache ohne manuellen Übersetzungsaufwand verfügbar.',
|
answer: 'Ja. Das Back-Office unterstützt mehrsprachige Inhaltsverwaltung, und Pro- und Premium-Pläne umfassen automatische KI-Übersetzung. Ideal für internationale Messen und Konferenzen — Ihr Inhalt ist in jeder Sprache ohne manuellen Übersetzungsaufwand verfügbar.',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
question: "Ist MyInfoMate DSGVO-konform?",
|
||||||
|
answer: "Die Daten werden in der Europäischen Union gehostet. Vom Teilnehmer wird kein Konto verlangt: Die Besucherzahlen sind anonym — aufgerufene Bereiche, Dauer, Sprache, Gerätetyp. Aktivieren Sie den KI-Assistenten, werden die gestellten Fragen 90 Tage gespeichert und danach automatisch gelöscht, ohne Namen und ohne IP-Adresse. Der Veranstalter bleibt Verantwortlicher, MyInfoMate handelt als Auftragsverarbeiter. Details stehen in Punkt 8 unserer AGB.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: "Kann eine Gemeinde oder ein geförderter Verein es öffentlich beschaffen?",
|
||||||
|
answer: "Ja. MyInfoMate ist seit 2021 in belgischen öffentlichen Einrichtungen im Einsatz und wurde vom Tourismusbüro Namur nach einer veröffentlichten Ausschreibung ausgewählt. Für eine Veranstaltung mit bescheidenem Budget kann eine Gemeinde oder ein Verein in der Regel auf einfaches Angebot bestellen, im Rahmen der Regelung für Aufträge geringen Wertes — den geltenden Schwellenwert klären Sie am besten mit Ihrer Vergabestelle. Wir liefern ein detailliertes Angebot und eine technische Beschreibung für Ihre Akte.",
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
cta: {
|
cta: {
|
||||||
@ -3234,7 +3410,7 @@ const educationCulture: Segment = {
|
|||||||
features: {
|
features: {
|
||||||
label: 'Ce que MyInfoMate fait pour vous',
|
label: 'Ce que MyInfoMate fait pour vous',
|
||||||
title: 'Tout ce qu\'un lieu éducatif peut faire avec MyInfoMate',
|
title: 'Tout ce qu\'un lieu éducatif peut faire avec MyInfoMate',
|
||||||
desc: 'Une plateforme pédagogique no-code pour adapter votre contenu à chaque public, sans équipe technique ni budget de production multimédia.',
|
desc: 'Une plateforme de médiation numérique no-code pour adapter votre parcours de visite à chaque public, sans équipe technique ni budget de production multimédia.',
|
||||||
valueLabel: 'Valeur ajoutée :',
|
valueLabel: 'Valeur ajoutée :',
|
||||||
items: [
|
items: [
|
||||||
{
|
{
|
||||||
@ -3339,6 +3515,18 @@ const educationCulture: Segment = {
|
|||||||
question: 'Combien coûte une application pour un centre éducatif ?',
|
question: 'Combien coûte une application pour un centre éducatif ?',
|
||||||
answer: 'À partir de €39/mois HTVA sans engagement pour l\'Essentiel. Le plan Pro à €99/mois inclut l\'application native white-label, le mode hors ligne et les push notifications. Le plan Premium à €179/mois ajoute l\'assistant IA et la traduction automatique. Beaucoup plus accessible qu\'une app sur mesure ou une production multimédia classique.',
|
answer: 'À partir de €39/mois HTVA sans engagement pour l\'Essentiel. Le plan Pro à €99/mois inclut l\'application native white-label, le mode hors ligne et les push notifications. Le plan Premium à €179/mois ajoute l\'assistant IA et la traduction automatique. Beaucoup plus accessible qu\'une app sur mesure ou une production multimédia classique.',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
question: 'Que deviennent les données des élèves et des étudiants ? Êtes-vous conforme au RGPD ?',
|
||||||
|
answer: 'Les données sont hébergées dans l\'Union européenne, et MyInfoMate ne demande aucun compte au visiteur : rien ne permet d\'identifier un élève. Les statistiques sont anonymes — sections consultées, durée, langue, type d\'appareil — et les résultats de quiz ne sont pas rattachés à une personne. Si vous activez l\'assistant IA, les questions posées sont conservées 90 jours puis supprimées automatiquement. L\'établissement reste responsable de traitement, MyInfoMate agit comme sous-traitant. Le détail figure au point 8 de nos conditions générales et dans notre politique de confidentialité.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Un établissement public peut-il l\'acheter dans le cadre d\'un marché public ?',
|
||||||
|
answer: 'Oui. MyInfoMate équipe des lieux publics belges depuis 2021 et a été retenu par l\'office du tourisme de Namur à l\'issue d\'un cahier des charges publié. Pour les montants modestes, un établissement peut généralement commander sur simple devis, dans le cadre du régime des marchés de faible montant — le seuil applicable est à vérifier avec votre service marchés. Nous fournissons un devis détaillé et une description technique reprenant fonctionnalités, hébergement et traitement des données pour votre dossier.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Les contenus sont-ils accessibles aux publics en situation de handicap ?',
|
||||||
|
answer: 'L\'audio et les contenus multilingues profitent aux élèves qui lisent difficilement ou ne parlent pas français, et l\'application respecte les réglages d\'accessibilité de l\'appareil, notamment la taille de police. En revanche, soyons clairs : l\'application n\'est pas encore certifiée Access-i et aucun audit d\'accessibilité formel n\'a été réalisé. Si votre marché l\'exige, parlons-en avant votre dossier.',
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
cta: {
|
cta: {
|
||||||
@ -3487,6 +3675,18 @@ const educationCulture: Segment = {
|
|||||||
question: 'How much does an app for an educational venue cost?',
|
question: 'How much does an app for an educational venue cost?',
|
||||||
answer: 'From €39/month excl. VAT with no commitment for Essential. The Pro plan at €99/month includes the native white-label app, offline mode and push notifications. The Premium plan at €179/month adds the AI assistant and automatic translation. Far more accessible than a custom app or classic multimedia production.',
|
answer: 'From €39/month excl. VAT with no commitment for Essential. The Pro plan at €99/month includes the native white-label app, offline mode and push notifications. The Premium plan at €179/month adds the AI assistant and automatic translation. Far more accessible than a custom app or classic multimedia production.',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
question: "What happens to pupils' and students' data? Are you GDPR compliant?",
|
||||||
|
answer: "Data is hosted in the European Union, and MyInfoMate asks visitors for no account: nothing can identify a pupil. Statistics are anonymous — sections viewed, duration, language, device type — and quiz results are not tied to a person. If you enable the AI assistant, the questions asked are kept for 90 days and then deleted automatically. The institution remains the data controller and MyInfoMate acts as processor. The details are in section 8 of our terms and conditions and in our privacy policy.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: "Can a public institution buy it through public procurement?",
|
||||||
|
answer: "Yes. MyInfoMate has been running in Belgian public venues since 2021 and was selected by the Namur tourism office following a published call for tenders. For modest amounts, an institution can usually order on a simple quotation, under the low-value contract regime — check the applicable threshold with your procurement department. We provide a detailed quotation and a technical description covering features, hosting and data processing for your file.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: "Is the content accessible to learners with disabilities?",
|
||||||
|
answer: "Audio and multilingual content help learners who struggle to read or do not speak the local language, and the app respects the accessibility settings of the device, font size included. To be clear, though: the app is not yet Access-i certified and no formal accessibility audit has been carried out. If your tender requires it, let's talk before you file it.",
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
cta: {
|
cta: {
|
||||||
@ -3635,6 +3835,18 @@ const educationCulture: Segment = {
|
|||||||
question: 'Wat kost een app voor een educatief centrum?',
|
question: 'Wat kost een app voor een educatief centrum?',
|
||||||
answer: 'Vanaf €39/maand excl. BTW zonder engagement voor Essentieel. Het Pro-abonnement voor €99/maand omvat de native white-label app, offline modus en pushmeldingen. Het Premium-abonnement voor €179/maand voegt de AI-assistent en automatische vertaling toe. Veel toegankelijker dan een app op maat of klassieke multimedia-productie.',
|
answer: 'Vanaf €39/maand excl. BTW zonder engagement voor Essentieel. Het Pro-abonnement voor €99/maand omvat de native white-label app, offline modus en pushmeldingen. Het Premium-abonnement voor €179/maand voegt de AI-assistent en automatische vertaling toe. Veel toegankelijker dan een app op maat of klassieke multimedia-productie.',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
question: "Wat gebeurt er met de gegevens van leerlingen en studenten? Zijn jullie GDPR-conform?",
|
||||||
|
answer: "De gegevens worden in de Europese Unie gehost en MyInfoMate vraagt de bezoeker geen account: niets laat toe een leerling te identificeren. De statistieken zijn anoniem — geraadpleegde secties, duur, taal, toesteltype — en quizresultaten worden niet aan een persoon gekoppeld. Activeert u de AI-assistent, dan worden de gestelde vragen 90 dagen bewaard en daarna automatisch verwijderd. De instelling blijft verwerkingsverantwoordelijke, MyInfoMate treedt op als verwerker. De details staan in punt 8 van onze algemene voorwaarden.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: "Kan een openbare instelling het via een overheidsopdracht aankopen?",
|
||||||
|
answer: "Ja. MyInfoMate is sinds 2021 in Belgische openbare locaties in gebruik en werd door het toerismekantoor van Namen geselecteerd na een gepubliceerd bestek. Voor bescheiden bedragen kan een instelling meestal bestellen op eenvoudige offerte, binnen de regeling van opdrachten van beperkte waarde — de toepasselijke drempel controleert u best met uw dienst overheidsopdrachten. Wij bezorgen een gedetailleerde offerte en een technische beschrijving voor uw dossier.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: "Zijn de inhouden toegankelijk voor leerlingen met een beperking?",
|
||||||
|
answer: "Audio en meertalige inhoud helpen leerlingen die moeilijk lezen of de landstaal niet spreken, en de app respecteert de toegankelijkheidsinstellingen van het toestel, inclusief de lettergrootte. Maar laten we duidelijk zijn: de app is nog niet Access-i-gecertificeerd en er is geen formele toegankelijkheidsaudit uitgevoerd. Vereist uw opdracht dat, laat het ons weten vóór u uw dossier indient.",
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
cta: {
|
cta: {
|
||||||
@ -3783,6 +3995,18 @@ const educationCulture: Segment = {
|
|||||||
question: 'Was kostet eine App für ein Bildungszentrum?',
|
question: 'Was kostet eine App für ein Bildungszentrum?',
|
||||||
answer: 'Ab €39/Monat zzgl. MwSt. ohne Mindestlaufzeit für Essential. Der Pro-Plan für €99/Monat umfasst die native White-Label-App, Offline-Modus und Push-Benachrichtigungen. Der Premium-Plan für €179/Monat fügt den KI-Assistenten und die automatische Übersetzung hinzu. Viel zugänglicher als eine maßgeschneiderte App oder klassische Multimedia-Produktion.',
|
answer: 'Ab €39/Monat zzgl. MwSt. ohne Mindestlaufzeit für Essential. Der Pro-Plan für €99/Monat umfasst die native White-Label-App, Offline-Modus und Push-Benachrichtigungen. Der Premium-Plan für €179/Monat fügt den KI-Assistenten und die automatische Übersetzung hinzu. Viel zugänglicher als eine maßgeschneiderte App oder klassische Multimedia-Produktion.',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
question: "Was geschieht mit den Daten von Schülern und Studierenden? Sind Sie DSGVO-konform?",
|
||||||
|
answer: "Die Daten werden in der Europäischen Union gehostet, und MyInfoMate verlangt vom Besucher kein Konto: Nichts lässt einen Rückschluss auf einen Schüler zu. Die Statistiken sind anonym — aufgerufene Bereiche, Dauer, Sprache, Gerätetyp — und Quizergebnisse werden keiner Person zugeordnet. Aktivieren Sie den KI-Assistenten, werden die gestellten Fragen 90 Tage gespeichert und danach automatisch gelöscht. Die Einrichtung bleibt Verantwortlicher, MyInfoMate handelt als Auftragsverarbeiter. Details stehen in Punkt 8 unserer AGB.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: "Kann eine öffentliche Einrichtung es über eine Ausschreibung beschaffen?",
|
||||||
|
answer: "Ja. MyInfoMate ist seit 2021 in belgischen öffentlichen Einrichtungen im Einsatz und wurde vom Tourismusbüro Namur nach einer veröffentlichten Ausschreibung ausgewählt. Bei geringen Beträgen kann eine Einrichtung in der Regel auf einfaches Angebot bestellen, im Rahmen der Regelung für Aufträge geringen Wertes — den geltenden Schwellenwert klären Sie am besten mit Ihrer Vergabestelle. Wir liefern ein detailliertes Angebot und eine technische Beschreibung für Ihre Akte.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: "Sind die Inhalte für Lernende mit Behinderung zugänglich?",
|
||||||
|
answer: "Audio und mehrsprachige Inhalte helfen Lernenden, die schwer lesen oder die Landessprache nicht sprechen, und die App übernimmt die Barrierefreiheitseinstellungen des Geräts, einschließlich der Schriftgröße. Klar gesagt: Die App ist noch nicht Access-i-zertifiziert und es wurde kein formelles Barrierefreiheits-Audit durchgeführt. Verlangt Ihre Ausschreibung das, sprechen wir vor der Einreichung darüber.",
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
cta: {
|
cta: {
|
||||||
|
|||||||
@ -4,10 +4,11 @@
|
|||||||
*/
|
*/
|
||||||
export const STITCH_IMAGES: Record<string, string> = {
|
export const STITCH_IMAGES: Record<string, string> = {
|
||||||
"{{DATA:IMAGE:IMAGE_14}}": "/myinfomate-logo.png",
|
"{{DATA:IMAGE:IMAGE_14}}": "/myinfomate-logo.png",
|
||||||
"{{DATA:IMAGE:IMAGE_4}}": "/map_generated.png",
|
"{{DATA:IMAGE:IMAGE_4}}": "/app-map.jpg",
|
||||||
"{{DATA:IMAGE:IMAGE_5}}": "/app-screenshot-2.png",
|
// Captures réelles de l'app du Fort de Saint-Héribert, mises à jour le 2026-09-10 (V3).
|
||||||
"{{DATA:IMAGE:IMAGE_6}}": "/app-screenshot-1.png",
|
"{{DATA:IMAGE:IMAGE_5}}": "/app-screenshot-1.jpg",
|
||||||
"{{DATA:IMAGE:IMAGE_7}}": "/app-screenshot-1.png",
|
"{{DATA:IMAGE:IMAGE_6}}": "/app-screenshot-3.jpg",
|
||||||
|
"{{DATA:IMAGE:IMAGE_7}}": "/app-screenshot-2.jpg",
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
43
src/data/structured-data.ts
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
export const MYINFOMATE_LINKEDIN = 'https://www.linkedin.com/showcase/myinfomate/';
|
||||||
|
|
||||||
|
const SITE_URL = 'https://myinfomate.be';
|
||||||
|
|
||||||
|
export function breadcrumbSchema(items: { name: string; path: string }[]) {
|
||||||
|
return {
|
||||||
|
'@context': 'https://schema.org',
|
||||||
|
'@type': 'BreadcrumbList',
|
||||||
|
itemListElement: items.map((item, index) => ({
|
||||||
|
'@type': 'ListItem',
|
||||||
|
position: index + 1,
|
||||||
|
name: item.name,
|
||||||
|
item: `${SITE_URL}${item.path}`,
|
||||||
|
})),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const PLANS = [
|
||||||
|
{ name: 'Essentiel', price: '39' },
|
||||||
|
{ name: 'Pro', price: '99' },
|
||||||
|
{ name: 'Premium', price: '179' },
|
||||||
|
];
|
||||||
|
|
||||||
|
export const softwareOffers = {
|
||||||
|
'@type': 'AggregateOffer',
|
||||||
|
lowPrice: '39',
|
||||||
|
highPrice: '179',
|
||||||
|
priceCurrency: 'EUR',
|
||||||
|
offerCount: PLANS.length,
|
||||||
|
offers: PLANS.map((plan) => ({
|
||||||
|
'@type': 'Offer',
|
||||||
|
name: plan.name,
|
||||||
|
price: plan.price,
|
||||||
|
priceCurrency: 'EUR',
|
||||||
|
priceSpecification: {
|
||||||
|
'@type': 'UnitPriceSpecification',
|
||||||
|
price: plan.price,
|
||||||
|
priceCurrency: 'EUR',
|
||||||
|
unitText: 'MONTH',
|
||||||
|
valueAddedTaxIncluded: false,
|
||||||
|
},
|
||||||
|
})),
|
||||||
|
};
|
||||||
@ -28,6 +28,12 @@ const translations = {
|
|||||||
subtitle: "Transformez l'expérience de vos visiteurs. Gérez vos parcours sur tablettes et mobiles en temps réel, sans aucune connaissance technique.",
|
subtitle: "Transformez l'expérience de vos visiteurs. Gérez vos parcours sur tablettes et mobiles en temps réel, sans aucune connaissance technique.",
|
||||||
cta: 'Demander une démo',
|
cta: 'Demander une démo',
|
||||||
},
|
},
|
||||||
|
imgAlt: {
|
||||||
|
map: 'Carte interactive d\'un parcours de visite : points d\'intérêt géolocalisés, filtres par catégorie et fiche de lieu',
|
||||||
|
appHome: 'Accueil de l\'application du Fort de Saint-Héribert : sections en grille avec photos',
|
||||||
|
appArticle: 'Fiche article de l\'application : photo d\'archive, texte et lecture audio',
|
||||||
|
appWhitelabel: 'Application aux couleurs du Fort de Saint-Héribert : liste des sections et recherche',
|
||||||
|
},
|
||||||
mockup: {
|
mockup: {
|
||||||
mapTitle: 'Carte Interactive',
|
mapTitle: 'Carte Interactive',
|
||||||
mapSubtitle: 'Parcours Découverte',
|
mapSubtitle: 'Parcours Découverte',
|
||||||
@ -134,6 +140,7 @@ const translations = {
|
|||||||
feature3Desc: "Contexte mémorisé tout au long de la visite pour des échanges fluides et cohérents.",
|
feature3Desc: "Contexte mémorisé tout au long de la visite pour des échanges fluides et cohérents.",
|
||||||
feature4Title: 'Scopé à votre lieu',
|
feature4Title: 'Scopé à votre lieu',
|
||||||
feature4Desc: "Chaque lieu a son propre assistant, limité strictement à vos contenus. Aucune dérive hors sujet.",
|
feature4Desc: "Chaque lieu a son propre assistant, limité strictement à vos contenus. Aucune dérive hors sujet.",
|
||||||
|
learnMore: "Tout savoir sur l'assistant IA",
|
||||||
},
|
},
|
||||||
whitelabel: {
|
whitelabel: {
|
||||||
sectionLabel: 'White label',
|
sectionLabel: 'White label',
|
||||||
@ -269,7 +276,7 @@ const translations = {
|
|||||||
sectionLabel: 'Tarifs',
|
sectionLabel: 'Tarifs',
|
||||||
sectionTitle: 'Un plan pour chaque lieu',
|
sectionTitle: 'Un plan pour chaque lieu',
|
||||||
sectionDesc: "Interface web incluse dans tous les plans. Ajoutez une app mobile à votre nom pour aller plus loin.",
|
sectionDesc: "Interface web incluse dans tous les plans. Ajoutez une app mobile à votre nom pour aller plus loin.",
|
||||||
setupFeeNote: "Frais de mise en place + engagement 12 mois (app mobile).",
|
setupFeeNote: "Frais de mise en place uniques, chiffrés dans le devis + engagement 12 mois (app mobile).",
|
||||||
noCommitment: "Sans engagement.",
|
noCommitment: "Sans engagement.",
|
||||||
perMonth: '/mois',
|
perMonth: '/mois',
|
||||||
htva: 'HTVA',
|
htva: 'HTVA',
|
||||||
@ -316,6 +323,44 @@ const translations = {
|
|||||||
customDev: 'Développements sur mesure',
|
customDev: 'Développements sur mesure',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
homeFaq: {
|
||||||
|
sectionLabel: 'FAQ',
|
||||||
|
title: 'Les questions qu\'on nous pose le plus',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
question: 'Qu\'est-ce que MyInfoMate, concrètement ?',
|
||||||
|
answer: 'MyInfoMate est une plateforme de médiation numérique pour les lieux qui accueillent du public : musées, sites patrimoniaux, offices de tourisme, parcs naturels, hôtels et événements. Depuis un seul back-office, vous créez vos contenus et vos parcours de visite, puis vous les diffusez sur une application mobile à votre marque, sur des bornes tablettes et sur le web.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Faut-il des compétences techniques pour l\'utiliser ?',
|
||||||
|
answer: 'Non. Tout se gère depuis un back-office visuel, sans écrire une ligne de code : vous écrivez vos textes, importez vos images, vos audios et vos vidéos, et vous publiez. Les mises à jour sont visibles immédiatement, sans intervention de notre part et sans budget imprévu.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Combien coûte MyInfoMate ?',
|
||||||
|
answer: 'Les prix sont publics : 39 €/mois pour le plan Essentiel (application web et mode borne, sans engagement), 99 €/mois pour le plan Pro (votre application mobile sur l\'App Store et Google Play, mode hors ligne, notifications) et 179 €/mois pour le plan Premium (assistant IA et traduction automatique). Tous les prix sont hors TVA. Les organisations multi-sites relèvent d\'un devis Enterprise.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Sur quels supports mes visiteurs accèdent-ils au contenu ?',
|
||||||
|
answer: 'Trois canaux alimentés par le même contenu : leur propre smartphone via l\'application mobile, une borne tablette installée dans votre lieu, et une application web ouverte depuis un navigateur ou un QR code, sans installation. Vous choisissez ceux qui conviennent à votre public.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Cela fonctionne-t-il dans un lieu sans réseau ?',
|
||||||
|
answer: 'Oui, avec le mode hors ligne inclus dès le plan Pro : le visiteur télécharge les contenus à l\'entrée, puis la visite se déroule sans 4G ni Wi-Fi. C\'est ainsi que fonctionne le Fort de Saint-Héribert, dont les galeries souterraines ne captent pas.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'L\'application porte-t-elle notre marque ou la vôtre ?',
|
||||||
|
answer: 'La vôtre. MyInfoMate est une solution en marque blanche : votre logo, vos couleurs, votre typographie, et votre nom sur les stores. Vos visiteurs voient votre lieu, pas notre marque.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Combien de temps faut-il pour démarrer ?',
|
||||||
|
answer: 'Quelques jours pour les premières sections — un plan et un audio guide, par exemple — puis vous enrichissez progressivement. Le plan Essentiel s\'essaie gratuitement pendant 14 jours, sans carte bancaire. Pour une application mobile publiée sur les stores, comptez le délai de validation des stores en plus.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Où sont hébergées les données de nos visiteurs ?',
|
||||||
|
answer: 'Dans l\'Union européenne. Les statistiques de visite sont anonymes et ne permettent pas d\'identifier un visiteur. Si vous activez l\'assistant IA, les questions posées sont conservées 90 jours puis supprimées automatiquement. Votre lieu est responsable de traitement, MyInfoMate agit comme sous-traitant : le détail figure dans nos conditions générales.',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
casClients: {
|
casClients: {
|
||||||
sectionLabel: 'Cas clients',
|
sectionLabel: 'Cas clients',
|
||||||
title: 'Ils nous font confiance',
|
title: 'Ils nous font confiance',
|
||||||
@ -328,8 +373,15 @@ const translations = {
|
|||||||
contactTitle: 'Contact',
|
contactTitle: 'Contact',
|
||||||
casClientsLink: 'Cas clients',
|
casClientsLink: 'Cas clients',
|
||||||
copyright: '© 2026 MyInfoMate. Tous droits réservés.',
|
copyright: '© 2026 MyInfoMate. Tous droits réservés.',
|
||||||
|
pagesTitle: "Solutions",
|
||||||
|
pageTarifs: "Tarifs",
|
||||||
|
pageAssistant: "Assistant IA",
|
||||||
|
pageKiosk: "Borne interactive",
|
||||||
|
pageOffline: "Visite hors ligne",
|
||||||
|
pagePublic: "Marchés publics",
|
||||||
legal: 'Mentions Légales',
|
legal: 'Mentions Légales',
|
||||||
privacy: 'Confidentialité',
|
privacy: 'Confidentialité',
|
||||||
|
terms: 'Conditions générales',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -360,6 +412,12 @@ const translations = {
|
|||||||
subtitle: "Transform your visitors' experience. Manage your tours on tablets and mobiles in real time, with no technical knowledge required.",
|
subtitle: "Transform your visitors' experience. Manage your tours on tablets and mobiles in real time, with no technical knowledge required.",
|
||||||
cta: 'Request a demo',
|
cta: 'Request a demo',
|
||||||
},
|
},
|
||||||
|
imgAlt: {
|
||||||
|
map: 'Interactive map of a visitor trail: geolocated points of interest, category filters and a place card',
|
||||||
|
appHome: 'Home screen of the Fort de Saint-Héribert app: sections in a grid with photos',
|
||||||
|
appArticle: 'Article screen in the app: archive photo, text and audio playback',
|
||||||
|
appWhitelabel: 'App in the Fort de Saint-Héribert colours: list of sections and search',
|
||||||
|
},
|
||||||
mockup: {
|
mockup: {
|
||||||
mapTitle: 'Interactive Map',
|
mapTitle: 'Interactive Map',
|
||||||
mapSubtitle: 'Discovery Tour',
|
mapSubtitle: 'Discovery Tour',
|
||||||
@ -466,6 +524,7 @@ const translations = {
|
|||||||
feature3Desc: 'Context remembered throughout the visit for smooth and coherent exchanges.',
|
feature3Desc: 'Context remembered throughout the visit for smooth and coherent exchanges.',
|
||||||
feature4Title: 'Scoped to your venue',
|
feature4Title: 'Scoped to your venue',
|
||||||
feature4Desc: 'Each venue has its own assistant, strictly limited to your content. No off-topic drift.',
|
feature4Desc: 'Each venue has its own assistant, strictly limited to your content. No off-topic drift.',
|
||||||
|
learnMore: 'Everything about the AI assistant',
|
||||||
},
|
},
|
||||||
whitelabel: {
|
whitelabel: {
|
||||||
sectionLabel: 'White label',
|
sectionLabel: 'White label',
|
||||||
@ -601,7 +660,7 @@ const translations = {
|
|||||||
sectionLabel: 'Pricing',
|
sectionLabel: 'Pricing',
|
||||||
sectionTitle: 'A plan for every venue',
|
sectionTitle: 'A plan for every venue',
|
||||||
sectionDesc: 'Web interface included in every plan. Add a branded mobile app to go further.',
|
sectionDesc: 'Web interface included in every plan. Add a branded mobile app to go further.',
|
||||||
setupFeeNote: 'Setup fee + 12-month commitment (mobile app).',
|
setupFeeNote: 'One-off setup fee, quoted upfront + 12-month commitment (mobile app).',
|
||||||
noCommitment: 'No commitment.',
|
noCommitment: 'No commitment.',
|
||||||
perMonth: '/month',
|
perMonth: '/month',
|
||||||
htva: 'excl. VAT',
|
htva: 'excl. VAT',
|
||||||
@ -648,6 +707,44 @@ const translations = {
|
|||||||
customDev: 'Custom development',
|
customDev: 'Custom development',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
homeFaq: {
|
||||||
|
sectionLabel: 'FAQ',
|
||||||
|
title: 'The questions we get most often',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
question: 'What is MyInfoMate, in practice?',
|
||||||
|
answer: 'MyInfoMate is a digital interpretation platform for venues that welcome visitors: museums, heritage sites, tourism offices, natural parks, hotels and events. From a single back-office you create your content and visitor trails, then publish them to a mobile app under your own brand, to tablet kiosks and to the web.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Do we need technical skills to use it?',
|
||||||
|
answer: 'No. Everything is managed from a visual back-office, without writing a line of code: you write your texts, upload your images, audio and video, and publish. Updates are live immediately, with no intervention from us and no unplanned budget.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'How much does MyInfoMate cost?',
|
||||||
|
answer: 'Prices are public: €39/month for the Essential plan (web app and kiosk mode, no commitment), €99/month for Pro (your own mobile app on the App Store and Google Play, offline mode, notifications) and €179/month for Premium (AI assistant and automatic translation). All prices exclude VAT. Multi-site organisations get an Enterprise quote.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'On which devices do visitors access the content?',
|
||||||
|
answer: 'Three channels fed by the same content: their own smartphone through the mobile app, a tablet kiosk installed in your venue, and a web app opened from a browser or a QR code, with no install. You pick the ones that suit your audience.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Does it work in a venue with no network?',
|
||||||
|
answer: 'Yes, with the offline mode included from the Pro plan: visitors download the content at the entrance, then the visit runs without 4G or Wi-Fi. That is how Fort de Saint-Héribert works — its underground galleries have no coverage.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Does the app carry our brand or yours?',
|
||||||
|
answer: 'Yours. MyInfoMate is a white-label solution: your logo, your colours, your typography, and your name on the stores. Visitors see your venue, not our brand.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'How long does it take to get started?',
|
||||||
|
answer: 'A few days for the first sections — a map and an audio guide, for instance — then you enrich it step by step. The Essential plan comes with a 14-day free trial, no credit card required. For a mobile app published on the stores, add the stores\' review time.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Where is our visitors\' data hosted?',
|
||||||
|
answer: 'In the European Union. Visit statistics are anonymous and cannot identify a visitor. If you enable the AI assistant, the questions asked are kept for 90 days and then deleted automatically. Your venue is the data controller and MyInfoMate acts as processor: the details are in our terms and conditions.',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
casClients: {
|
casClients: {
|
||||||
sectionLabel: 'Case studies',
|
sectionLabel: 'Case studies',
|
||||||
title: 'They trust us',
|
title: 'They trust us',
|
||||||
@ -660,8 +757,15 @@ const translations = {
|
|||||||
contactTitle: 'Contact',
|
contactTitle: 'Contact',
|
||||||
casClientsLink: 'Case studies',
|
casClientsLink: 'Case studies',
|
||||||
copyright: '© 2026 MyInfoMate. All rights reserved.',
|
copyright: '© 2026 MyInfoMate. All rights reserved.',
|
||||||
|
pagesTitle: "Solutions",
|
||||||
|
pageTarifs: "Pricing",
|
||||||
|
pageAssistant: "AI assistant",
|
||||||
|
pageKiosk: "Interactive kiosk",
|
||||||
|
pageOffline: "Offline visit",
|
||||||
|
pagePublic: "Public procurement",
|
||||||
legal: 'Legal Notice',
|
legal: 'Legal Notice',
|
||||||
privacy: 'Privacy',
|
privacy: 'Privacy',
|
||||||
|
terms: 'Terms & Conditions',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -692,6 +796,12 @@ const translations = {
|
|||||||
subtitle: 'Transformeer de ervaring van uw bezoekers. Beheer uw routes op tablets en mobiele telefoons in real time, zonder technische kennis.',
|
subtitle: 'Transformeer de ervaring van uw bezoekers. Beheer uw routes op tablets en mobiele telefoons in real time, zonder technische kennis.',
|
||||||
cta: 'Demo aanvragen',
|
cta: 'Demo aanvragen',
|
||||||
},
|
},
|
||||||
|
imgAlt: {
|
||||||
|
map: 'Interactieve kaart van een bezoekersparcours: gelokaliseerde bezienswaardigheden, filters per categorie en een plaatsfiche',
|
||||||
|
appHome: 'Startscherm van de app van Fort de Saint-Héribert: secties in een raster met foto\'s',
|
||||||
|
appArticle: 'Artikelscherm in de app: archieffoto, tekst en audioweergave',
|
||||||
|
appWhitelabel: 'App in de kleuren van Fort de Saint-Héribert: lijst met secties en zoekfunctie',
|
||||||
|
},
|
||||||
mockup: {
|
mockup: {
|
||||||
mapTitle: 'Interactieve Kaart',
|
mapTitle: 'Interactieve Kaart',
|
||||||
mapSubtitle: 'Ontdekkingsroute',
|
mapSubtitle: 'Ontdekkingsroute',
|
||||||
@ -798,6 +908,7 @@ const translations = {
|
|||||||
feature3Desc: 'Context onthouden gedurende het hele bezoek voor soepele en coherente uitwisselingen.',
|
feature3Desc: 'Context onthouden gedurende het hele bezoek voor soepele en coherente uitwisselingen.',
|
||||||
feature4Title: 'Afgestemd op uw locatie',
|
feature4Title: 'Afgestemd op uw locatie',
|
||||||
feature4Desc: 'Elke locatie heeft zijn eigen assistent, strikt beperkt tot uw inhoud. Geen afdwaling.',
|
feature4Desc: 'Elke locatie heeft zijn eigen assistent, strikt beperkt tot uw inhoud. Geen afdwaling.',
|
||||||
|
learnMore: 'Alles over de AI-assistent',
|
||||||
},
|
},
|
||||||
whitelabel: {
|
whitelabel: {
|
||||||
sectionLabel: 'White label',
|
sectionLabel: 'White label',
|
||||||
@ -933,7 +1044,7 @@ const translations = {
|
|||||||
sectionLabel: 'Tarieven',
|
sectionLabel: 'Tarieven',
|
||||||
sectionTitle: 'Een plan voor elke locatie',
|
sectionTitle: 'Een plan voor elke locatie',
|
||||||
sectionDesc: 'Webinterface inbegrepen in elk plan. Voeg een app op uw naam toe om verder te gaan.',
|
sectionDesc: 'Webinterface inbegrepen in elk plan. Voeg een app op uw naam toe om verder te gaan.',
|
||||||
setupFeeNote: 'Opstartkosten + 12 maanden engagement (mobiele app).',
|
setupFeeNote: 'Eenmalige opstartkosten, vermeld in de offerte + 12 maanden engagement (mobiele app).',
|
||||||
noCommitment: 'Zonder engagement.',
|
noCommitment: 'Zonder engagement.',
|
||||||
perMonth: '/maand',
|
perMonth: '/maand',
|
||||||
htva: 'excl. BTW',
|
htva: 'excl. BTW',
|
||||||
@ -980,6 +1091,44 @@ const translations = {
|
|||||||
customDev: 'Maatwerkontwikkeling',
|
customDev: 'Maatwerkontwikkeling',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
homeFaq: {
|
||||||
|
sectionLabel: 'FAQ',
|
||||||
|
title: 'De vragen die we het vaakst krijgen',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
question: 'Wat is MyInfoMate concreet?',
|
||||||
|
answer: 'MyInfoMate is een platform voor digitale publiekswerking voor locaties die bezoekers ontvangen: musea, erfgoedsites, toerismekantoren, natuurparken, hotels en evenementen. Vanuit één back-office maakt u uw inhoud en bezoekersparcours, en publiceert u ze in een mobiele app onder uw eigen merk, op tabletkiosken en op het web.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Zijn technische vaardigheden nodig?',
|
||||||
|
answer: 'Nee. Alles wordt beheerd vanuit een visuele back-office, zonder één regel code: u schrijft uw teksten, laadt uw beelden, audio en video op, en publiceert. Wijzigingen zijn meteen zichtbaar, zonder tussenkomst van ons en zonder onvoorzien budget.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Hoeveel kost MyInfoMate?',
|
||||||
|
answer: 'De prijzen zijn publiek: €39/maand voor het Essentieel-abonnement (web-app en kioskmodus, zonder verbintenis), €99/maand voor Pro (uw eigen mobiele app in de App Store en Google Play, offline modus, meldingen) en €179/maand voor Premium (AI-assistent en automatische vertaling). Alle prijzen zijn exclusief btw. Organisaties met meerdere sites krijgen een Enterprise-offerte.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Via welke kanalen bereiken bezoekers de inhoud?',
|
||||||
|
answer: 'Drie kanalen, gevoed door dezelfde inhoud: hun eigen smartphone via de mobiele app, een tabletkiosk in uw locatie, en een web-app die met een browser of QR-code wordt geopend, zonder installatie. U kiest wat bij uw publiek past.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Werkt het op een locatie zonder netwerk?',
|
||||||
|
answer: 'Ja, met de offline modus vanaf het Pro-abonnement: de bezoeker downloadt de inhoud aan de ingang en het bezoek verloopt zonder 4G of wifi. Zo werkt het Fort de Saint-Héribert, waar de ondergrondse galerijen geen bereik hebben.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Draagt de app ons merk of het uwe?',
|
||||||
|
answer: 'Het uwe. MyInfoMate is een white-labeloplossing: uw logo, uw kleuren, uw typografie en uw naam in de stores. Bezoekers zien uw locatie, niet ons merk.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Hoe snel kunnen we van start?',
|
||||||
|
answer: 'Enkele dagen voor de eerste secties — bijvoorbeeld een plattegrond en een audiogids — daarna breidt u stap voor stap uit. Het Essentieel-abonnement kunt u 14 dagen gratis uitproberen, zonder kredietkaart. Voor een mobiele app in de stores komt de beoordelingstijd van de stores erbij.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Waar worden de gegevens van onze bezoekers gehost?',
|
||||||
|
answer: 'In de Europese Unie. De bezoekstatistieken zijn anoniem en laten niet toe een bezoeker te identificeren. Activeert u de AI-assistent, dan worden de gestelde vragen 90 dagen bewaard en daarna automatisch verwijderd. Uw locatie is verwerkingsverantwoordelijke, MyInfoMate treedt op als verwerker: de details staan in onze algemene voorwaarden.',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
casClients: {
|
casClients: {
|
||||||
sectionLabel: 'Klantcases',
|
sectionLabel: 'Klantcases',
|
||||||
title: 'Zij vertrouwen ons',
|
title: 'Zij vertrouwen ons',
|
||||||
@ -992,8 +1141,15 @@ const translations = {
|
|||||||
contactTitle: 'Contact',
|
contactTitle: 'Contact',
|
||||||
casClientsLink: 'Klantcases',
|
casClientsLink: 'Klantcases',
|
||||||
copyright: '© 2026 MyInfoMate. Alle rechten voorbehouden.',
|
copyright: '© 2026 MyInfoMate. Alle rechten voorbehouden.',
|
||||||
|
pagesTitle: "Oplossingen",
|
||||||
|
pageTarifs: "Tarieven",
|
||||||
|
pageAssistant: "AI-assistent",
|
||||||
|
pageKiosk: "Interactieve kiosk",
|
||||||
|
pageOffline: "Offline bezoek",
|
||||||
|
pagePublic: "Overheidsopdrachten",
|
||||||
legal: 'Wettelijke vermeldingen',
|
legal: 'Wettelijke vermeldingen',
|
||||||
privacy: 'Privacy',
|
privacy: 'Privacy',
|
||||||
|
terms: 'Algemene voorwaarden',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -1024,6 +1180,12 @@ const translations = {
|
|||||||
subtitle: 'Transformieren Sie das Erlebnis Ihrer Besucher. Verwalten Sie Ihre Touren auf Tablets und Mobilgeräten in Echtzeit, ohne technische Kenntnisse.',
|
subtitle: 'Transformieren Sie das Erlebnis Ihrer Besucher. Verwalten Sie Ihre Touren auf Tablets und Mobilgeräten in Echtzeit, ohne technische Kenntnisse.',
|
||||||
cta: 'Demo anfordern',
|
cta: 'Demo anfordern',
|
||||||
},
|
},
|
||||||
|
imgAlt: {
|
||||||
|
map: 'Interaktive Karte eines Besucherrundgangs: verortete Sehenswürdigkeiten, Filter nach Kategorie und Ortskarte',
|
||||||
|
appHome: 'Startbildschirm der App von Fort de Saint-Héribert: Bereiche als Raster mit Fotos',
|
||||||
|
appArticle: 'Artikelansicht in der App: Archivfoto, Text und Audiowiedergabe',
|
||||||
|
appWhitelabel: 'App in den Farben von Fort de Saint-Héribert: Liste der Bereiche und Suche',
|
||||||
|
},
|
||||||
mockup: {
|
mockup: {
|
||||||
mapTitle: 'Interaktive Karte',
|
mapTitle: 'Interaktive Karte',
|
||||||
mapSubtitle: 'Entdeckungsroute',
|
mapSubtitle: 'Entdeckungsroute',
|
||||||
@ -1130,6 +1292,7 @@ const translations = {
|
|||||||
feature3Desc: 'Kontext wird während des gesamten Besuchs gespeichert für reibungslose und kohärente Gespräche.',
|
feature3Desc: 'Kontext wird während des gesamten Besuchs gespeichert für reibungslose und kohärente Gespräche.',
|
||||||
feature4Title: 'Auf Ihren Standort zugeschnitten',
|
feature4Title: 'Auf Ihren Standort zugeschnitten',
|
||||||
feature4Desc: 'Jeder Standort hat seinen eigenen Assistenten, strikt auf Ihre Inhalte begrenzt. Kein Abdriften vom Thema.',
|
feature4Desc: 'Jeder Standort hat seinen eigenen Assistenten, strikt auf Ihre Inhalte begrenzt. Kein Abdriften vom Thema.',
|
||||||
|
learnMore: 'Alles zum KI-Assistenten',
|
||||||
},
|
},
|
||||||
whitelabel: {
|
whitelabel: {
|
||||||
sectionLabel: 'White Label',
|
sectionLabel: 'White Label',
|
||||||
@ -1265,7 +1428,7 @@ const translations = {
|
|||||||
sectionLabel: 'Preise',
|
sectionLabel: 'Preise',
|
||||||
sectionTitle: 'Ein Plan für jeden Standort',
|
sectionTitle: 'Ein Plan für jeden Standort',
|
||||||
sectionDesc: 'Web-Oberfläche in jedem Plan enthalten. Fügen Sie eine gebrandete App hinzu, um mehr zu erreichen.',
|
sectionDesc: 'Web-Oberfläche in jedem Plan enthalten. Fügen Sie eine gebrandete App hinzu, um mehr zu erreichen.',
|
||||||
setupFeeNote: 'Einrichtungsgebühr + 12 Monate Mindestlaufzeit (mobile App).',
|
setupFeeNote: 'Einmalige Einrichtungsgebühr, im Angebot ausgewiesen + 12 Monate Mindestlaufzeit (mobile App).',
|
||||||
noCommitment: 'Ohne Verpflichtung.',
|
noCommitment: 'Ohne Verpflichtung.',
|
||||||
perMonth: '/Monat',
|
perMonth: '/Monat',
|
||||||
htva: 'zzgl. MwSt.',
|
htva: 'zzgl. MwSt.',
|
||||||
@ -1312,6 +1475,44 @@ const translations = {
|
|||||||
customDev: 'Individuelle Entwicklung',
|
customDev: 'Individuelle Entwicklung',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
homeFaq: {
|
||||||
|
sectionLabel: 'FAQ',
|
||||||
|
title: 'Die Fragen, die uns am häufigsten gestellt werden',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
question: 'Was ist MyInfoMate konkret?',
|
||||||
|
answer: 'MyInfoMate ist eine Plattform für digitale Vermittlung an Orten, die Publikum empfangen: Museen, Kulturstätten, Tourismusbüros, Naturparks, Hotels und Veranstaltungen. Aus einem einzigen Back-Office erstellen Sie Ihre Inhalte und Besucherrundgänge und veröffentlichen sie in einer Mobile App unter Ihrer eigenen Marke, auf Tablet-Kiosken und im Web.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Sind technische Kenntnisse nötig?',
|
||||||
|
answer: 'Nein. Alles wird über ein visuelles Back-Office verwaltet, ohne eine Zeile Code: Sie schreiben Ihre Texte, laden Bilder, Audio und Video hoch und veröffentlichen. Änderungen sind sofort sichtbar — ohne unser Zutun und ohne ungeplantes Budget.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Was kostet MyInfoMate?',
|
||||||
|
answer: 'Die Preise sind öffentlich: 39 €/Monat für den Essential-Plan (Web-App und Kiosk-Modus, ohne Mindestlaufzeit), 99 €/Monat für Pro (Ihre eigene Mobile App im App Store und bei Google Play, Offline-Modus, Benachrichtigungen) und 179 €/Monat für Premium (KI-Assistent und automatische Übersetzung). Alle Preise zzgl. MwSt. Organisationen mit mehreren Standorten erhalten ein Enterprise-Angebot.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Über welche Kanäle erreichen Besucher die Inhalte?',
|
||||||
|
answer: 'Drei Kanäle, gespeist aus denselben Inhalten: das eigene Smartphone über die Mobile App, ein Tablet-Kiosk an Ihrem Ort und eine Web-App, die per Browser oder QR-Code geöffnet wird — ohne Installation. Sie wählen, was zu Ihrem Publikum passt.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Funktioniert es an einem Ort ohne Netz?',
|
||||||
|
answer: 'Ja, mit dem Offline-Modus ab dem Pro-Plan: Der Besucher lädt die Inhalte am Eingang herunter, danach läuft der Besuch ohne 4G oder WLAN. So arbeitet das Fort de Saint-Héribert, dessen unterirdische Galerien keinen Empfang haben.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Trägt die App unsere Marke oder Ihre?',
|
||||||
|
answer: 'Ihre. MyInfoMate ist eine White-Label-Lösung: Ihr Logo, Ihre Farben, Ihre Typografie und Ihr Name in den Stores. Besucher sehen Ihren Ort, nicht unsere Marke.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Wie schnell können wir starten?',
|
||||||
|
answer: 'Wenige Tage für die ersten Bereiche — etwa ein Plan und ein Audioguide — danach erweitern Sie Schritt für Schritt. Den Essential-Plan können Sie 14 Tage kostenlos testen, ohne Kreditkarte. Für eine in den Stores veröffentlichte Mobile App kommt die Prüfzeit der Stores hinzu.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
question: 'Wo werden die Daten unserer Besucher gehostet?',
|
||||||
|
answer: 'In der Europäischen Union. Die Besuchsstatistiken sind anonym und lassen keinen Rückschluss auf einen Besucher zu. Aktivieren Sie den KI-Assistenten, werden die gestellten Fragen 90 Tage gespeichert und danach automatisch gelöscht. Ihr Ort ist Verantwortlicher, MyInfoMate handelt als Auftragsverarbeiter: Details stehen in unseren Allgemeinen Geschäftsbedingungen.',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
casClients: {
|
casClients: {
|
||||||
sectionLabel: 'Referenzen',
|
sectionLabel: 'Referenzen',
|
||||||
title: 'Sie vertrauen uns',
|
title: 'Sie vertrauen uns',
|
||||||
@ -1324,8 +1525,15 @@ const translations = {
|
|||||||
contactTitle: 'Kontakt',
|
contactTitle: 'Kontakt',
|
||||||
casClientsLink: 'Referenzen',
|
casClientsLink: 'Referenzen',
|
||||||
copyright: '© 2026 MyInfoMate. Alle Rechte vorbehalten.',
|
copyright: '© 2026 MyInfoMate. Alle Rechte vorbehalten.',
|
||||||
|
pagesTitle: "Lösungen",
|
||||||
|
pageTarifs: "Preise",
|
||||||
|
pageAssistant: "KI-Assistent",
|
||||||
|
pageKiosk: "Interaktiver Kiosk",
|
||||||
|
pageOffline: "Offline-Besuch",
|
||||||
|
pagePublic: "Öffentliche Aufträge",
|
||||||
legal: 'Rechtliche Hinweise',
|
legal: 'Rechtliche Hinweise',
|
||||||
privacy: 'Datenschutz',
|
privacy: 'Datenschutz',
|
||||||
|
terms: 'Allgemeine Geschäftsbedingungen',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@ -2,7 +2,6 @@ import { NextRequest, NextResponse } from 'next/server';
|
|||||||
import { DEFAULT_LOCALE, detectLocaleFromAcceptLanguage, isLocale } from './i18n';
|
import { DEFAULT_LOCALE, detectLocaleFromAcceptLanguage, isLocale } from './i18n';
|
||||||
|
|
||||||
const PUBLIC_FILE = /\.(.*)$/;
|
const PUBLIC_FILE = /\.(.*)$/;
|
||||||
const SKIP_PATHS = ['/mentions-legales', '/confidentialite'];
|
|
||||||
|
|
||||||
export function proxy(request: NextRequest) {
|
export function proxy(request: NextRequest) {
|
||||||
const { pathname } = request.nextUrl;
|
const { pathname } = request.nextUrl;
|
||||||
@ -10,8 +9,7 @@ export function proxy(request: NextRequest) {
|
|||||||
if (
|
if (
|
||||||
pathname.startsWith('/_next') ||
|
pathname.startsWith('/_next') ||
|
||||||
pathname.startsWith('/api') ||
|
pathname.startsWith('/api') ||
|
||||||
PUBLIC_FILE.test(pathname) ||
|
PUBLIC_FILE.test(pathname)
|
||||||
SKIP_PATHS.some((p) => pathname === p || pathname.startsWith(p + '/'))
|
|
||||||
) {
|
) {
|
||||||
return NextResponse.next();
|
return NextResponse.next();
|
||||||
}
|
}
|
||||||
@ -20,9 +18,7 @@ export function proxy(request: NextRequest) {
|
|||||||
const first = segments[0];
|
const first = segments[0];
|
||||||
|
|
||||||
if (first && isLocale(first)) {
|
if (first && isLocale(first)) {
|
||||||
const requestHeaders = new Headers(request.headers);
|
return NextResponse.next();
|
||||||
requestHeaders.set('x-pathname', pathname);
|
|
||||||
return NextResponse.next({ request: { headers: requestHeaders } });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const detected = detectLocaleFromAcceptLanguage(request.headers.get('accept-language'));
|
const detected = detectLocaleFromAcceptLanguage(request.headers.get('accept-language'));
|
||||||
|
|||||||