diff --git a/CHANGELOG.fr.md b/CHANGELOG.fr.md index 81aa248..56f7c70 100644 --- a/CHANGELOG.fr.md +++ b/CHANGELOG.fr.md @@ -4,13 +4,13 @@ ### Ajouté -- Achat de l'édition Base depuis chaque écran verrouillé : « Obtenir Base » est désormais actif sur Budget, Ajustements, les rapports avancés et les profils supplémentaires, et ouvre la page produit dans la langue de l'application (#346). +- Achat de l'édition Base depuis chaque écran qui la requiert : « Obtenir Base » est désormais actif sur Budget, Ajustements, les rapports avancés et les profils supplémentaires, et ouvre la page produit dans la langue de l'application (#346). - En édition Gratuite, la carte Mises à jour propose « Obtenir Base », « J'ai déjà une clé » et « Télécharger la dernière version », et la page d'erreur « Obtenir Base » et « Télécharger la dernière version ». Le lien de téléchargement ouvre la page produit, qui sert les derniers installateurs ; aucune vérification de mise à jour n'a lieu (#346). ### Modifié - La carte Compte Maximus n'affirme plus qu'un compte est requis pour Premium : le compte sert à retrouver vos licences sur lacompagniemaximus.com et à vous identifier dans vos rétroactions, et les éditions viennent de la clé de licence (#346). -- L'écran verrouillé du Bilan (Premium) indique désormais que Premium n'est pas encore offert en ligne, au lieu de « Achat en ligne bientôt disponible » (#346). +- L'écran verrouillé du Bilan (Premium) indique désormais que Premium n'est pas encore offert en ligne, au lieu d'« Achat en ligne bientôt disponible » (#346). - En édition Gratuite, la carte Mises à jour indique que les mises à jour automatiques sont incluses dans l'édition Base (#346). ### Corrigé diff --git a/CHANGELOG.md b/CHANGELOG.md index 58f06de..a1e30e3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,12 +4,12 @@ ### Added -- Buy the Base edition from every locked screen: "Get Base" is now active on Budget, Adjustments, the advanced reports and extra profiles, and opens the product page in the app's language (#346). +- Buy the Base edition from every screen that requires it: "Get Base" is now active on Budget, Adjustments, the advanced reports and extra profiles, and opens the product page in the app's language (#346). - In the free edition, the Updates card offers "Get Base", "I already have a key" and "Download the latest version", and the error page offers "Get Base" and "Download the latest version". The download link opens the product page, which serves the latest installers; no update check runs (#346). ### Changed -- The Compte Maximus card no longer says an account is required for Premium: the account lets you find your licenses on lacompagniemaximus.com and identifies you in your feedback, and editions come from the license key (#346). +- The Maximus Account card no longer says an account is required for Premium: the account lets you find your licenses on lacompagniemaximus.com and identifies you in your feedback, and editions come from the license key (#346). - The Balance locked screen (Premium) now says Premium isn't sold online yet, instead of "Online purchase coming soon" (#346). - In the free edition, the Updates card says automatic updates are included in the Base edition (#346). diff --git a/docs/adr/0017-feature-gating-par-tier.md b/docs/adr/0017-feature-gating-par-tier.md index db7820c..5beb8b2 100644 --- a/docs/adr/0017-feature-gating-par-tier.md +++ b/docs/adr/0017-feature-gating-par-tier.md @@ -6,7 +6,7 @@ - Spec: [`spec-decisions-feature-gating.md`](../../spec-decisions-feature-gating.md), [`spec-plan-feature-gating.md`](../../spec-plan-feature-gating.md) - S'appuie sur la licence JWT Ed25519 machine-bindée (Phase 3b monétisation) et sur [ADR 0009](0009-proxy-price-fetching-via-maximus-api.md) / [ADR 0011](0011-providers-best-effort-yahoo.md) (récupération de cours via maximus-api, seul gate appliqué côté serveur) -> **Amendement du 2026-09-27 (#346)** — le CTA d'achat n'est plus inerte. « Obtenir Base » est actif sur tous les écrans verrouillés Base : il ouvre la page produit dans la langue de l'app (`purchaseUrl`, livré par #270, via le composant `PurchaseButton`). Premium reste désactivé, avec la note « Premium n'est pas encore offert en ligne. », tant qu'aucune offre Premium n'est vendable ; la règle vit dans une fonction pure testée, `upsellCtaFor` (`src/shared/upsellCta.ts`). En édition Gratuite, la carte Mises à jour et la page d'erreur proposent aussi « Obtenir Base » et « Télécharger la dernière version » (page produit), sans vérification de mise à jour ni appel réseau. `ProfileFormModal` réutilise désormais `UpsellGate` : le « mode upsell compact » a disparu, et « J'ai déjà une clé » ne s'affiche que sous un routeur (`HaveKeyButton`). Le reste de la décision est inchangé. +> **Amendement du 2026-09-27 (#346)** — le CTA d'achat n'est plus inerte. « Obtenir Base » est actif sur tous les écrans verrouillés Base : il ouvre la page produit dans la langue de l'app (`purchaseUrl`, livré par #270, via le composant `PurchaseButton`). Premium reste désactivé, avec la note « Premium n'est pas encore offert en ligne. », tant qu'aucune offre Premium n'est vendable ; la règle vit dans une fonction pure testée, `upsellCtaFor` (`src/shared/upsellCta.ts`). En édition Gratuite, la carte Mises à jour et la page d'erreur proposent aussi « Obtenir Base » et « Télécharger la dernière version » (page produit), sans vérification de mise à jour ni appel réseau. `ProfileFormModal` réutilise désormais `UpsellGate` : le « mode upsell compact » a disparu, et « J'ai déjà une clé » ne s'affiche que sous un routeur (`HaveKeyButton`). Réserve sur la carte Compte Maximus : son texte dit que les éditions viennent de la clé de licence, pas du compte, ce qui n'est exact qu'en pratique. `current_entitlements` accorde encore Premium à un compte dont le cache signé porte un abonnement actif (`check_account_edition`, `license_commands.rs`), comme le rappelle le Contexte ci-dessous. Ce chemin reste dormant tant qu'aucun abonnement n'est vendu ; le jour où un abonnement existera, il faudra revoir ce texte ou retirer le chemin. Le reste de la décision est inchangé. ## Contexte diff --git a/docs/guide-utilisateur.md b/docs/guide-utilisateur.md index 31a96e7..e957887 100644 --- a/docs/guide-utilisateur.md +++ b/docs/guide-utilisateur.md @@ -542,15 +542,16 @@ Simpl'Résultat existe en trois éditions : **Gratuite**, **Base** et **Premium* Les modules au-dessus de votre édition restent **visibles mais verrouillés** : un cadenas apparaît dans la barre latérale (Budget, Ajustements, Bilan) et sur les tuiles de rapports avancés du hub Rapports. Les ouvrir affiche un écran de déverrouillage qui indique l'édition requise, avec deux actions : -- **Obtenir Base** — ouvre la page produit dans votre navigateur pour acheter l'édition Base. Sur l'écran du Bilan, réservé à Premium, le bouton reste désactivé : Premium n'est pas encore offert en ligne +- **Obtenir Base** — ouvre la page produit dans votre navigateur pour acheter l'édition Base. Sur l'écran du Bilan, réservé à Premium, le bouton s'intitule « Obtenir Premium » et reste désactivé : Premium n'est pas encore offert en ligne - **J'ai déjà une clé** — mène directement à la carte de licence (Paramètres → Utilisateurs) pour entrer votre clé ### Comment faire 1. Repérez le cadenas dans la barre latérale ou sur les tuiles du hub Rapports : il marque les modules au-dessus de votre édition 2. Cliquez sur un module verrouillé pour voir l'édition requise -3. Si vous avez une clé de licence, cliquez sur « J'ai déjà une clé » (ou allez dans Paramètres → Utilisateurs) et entrez-la -4. Les modules se déverrouillent immédiatement — aucune réinstallation ni redémarrage nécessaire ; pour acheter l'édition Base, cliquez sur « Obtenir Base », qui ouvre la page produit (Premium n'est pas encore offert en ligne) +3. Pour acheter l'édition Base, cliquez sur « Obtenir Base » : la page produit s'ouvre dans votre navigateur (Premium n'est pas encore offert en ligne) +4. Une fois votre clé de licence en main, cliquez sur « J'ai déjà une clé » (ou allez dans Paramètres → Utilisateurs) et entrez-la +5. Les modules se déverrouillent immédiatement — aucune réinstallation ni redémarrage nécessaire ### Astuces diff --git a/src/components/settings/LicenseCard.tsx b/src/components/settings/LicenseCard.tsx index b8e7c2b..8a7abbb 100644 --- a/src/components/settings/LicenseCard.tsx +++ b/src/components/settings/LicenseCard.tsx @@ -6,6 +6,7 @@ import { useLicenseContext } from "../../contexts/LicenseContext"; import { useLicenseMachines } from "../../hooks/useLicenseMachines"; import type { LicenseError } from "../../services/licenseService"; import { purchaseUrl } from "../../shared/purchaseUrl"; +import { logError } from "../../services/logService"; export default function LicenseCard() { const { t, i18n } = useTranslation(); @@ -37,7 +38,9 @@ export default function LicenseCard() { }; const handlePurchase = () => { - void openUrl(purchaseUrl(i18n.language)); + void openUrl(purchaseUrl(i18n.language)).catch((e) => + logError("Product page: openUrl failed", e), + ); }; const formatExpiry = (timestamp: number) => { diff --git a/src/components/shared/DownloadLatestButton.tsx b/src/components/shared/DownloadLatestButton.tsx index 1d8c62a..0367765 100644 --- a/src/components/shared/DownloadLatestButton.tsx +++ b/src/components/shared/DownloadLatestButton.tsx @@ -2,6 +2,7 @@ import { useTranslation } from "react-i18next"; import { openUrl } from "@tauri-apps/plugin-opener"; import { Download } from "lucide-react"; import { purchaseUrl } from "../../shared/purchaseUrl"; +import { logError } from "../../services/logService"; const DEFAULT_LAYOUT = "inline-flex items-center justify-center gap-2 text-sm"; const COLOURS = "text-[var(--primary)] hover:underline"; @@ -15,7 +16,8 @@ interface DownloadLatestButtonProps { * "Download the latest version", shown in the free edition where automatic updates * are locked (issue #346). It opens the product page, which serves the latest * installers directly (la-compagnie-maximus#153). No update check runs here: the - * free edition makes no network call for updates. + * free edition makes no network call for updates. A failure to open the browser + * is logged, like PurchaseButton's. */ export default function DownloadLatestButton({ className = DEFAULT_LAYOUT, @@ -24,7 +26,11 @@ export default function DownloadLatestButton({ return (