Skip to Content

Projet Niv. 2 — Habitudes

Le brief : le tracker d’habitudes (« méditer », « lire 20 min », « pas de sucre ») : cocher chaque jour, entretenir des séries, voir la grille de chaleur des 3 derniers mois. Le projet des STREAKS — la mécanique psychologique la plus puissante du mobile.

Ce que vous allez pratiquer

La logique de dates/séries en lib/ pur (testée à fond — c’est piégeux), la grille de chaleur custom (flexbox + dérivation SQL), les notifications par habitude (channels, ch. 9.2), et la première vraie complexité de domaine. Chapitres liés : 6.1, 8.3, 9.2, 14.2.

Les features

  1. CRUD habitudes : nom, emoji, fréquence (quotidienne — hebdo en bonus), heure de rappel optionnelle.
  2. Le check du jour : un tap = fait (haptic Success !), re-tap = annulé.
  3. Streaks : série courante et record, par habitude — avec la règle de grâce explicite (rater AUJOURD’HUI ne casse la série qu’à minuit).
  4. La grille de chaleur (90 jours, façon GitHub) par habitude.
  5. Rappels par habitude à son heure (et le channel « Rappels d’habitudes »).

L’architecture recommandée

  • Le schéma : habits (id, name, emoji, reminder_hour, notification_id, created_at)
    • checks (habit_id, day TEXT ‘YYYY-MM-DD’, UNIQUE(habit_id, day)). Le jour en TEXTE local (pas un timestamp !) : « fait le 12 mars » est un fait de CALENDRIER, pas d’horloge — ça élimine toute la classe de bugs fuseaux/minuit.
  • La logique de streak en lib/streaks.ts, PURE — et c’est le cœur du projet :
// computeStreak(checkedDays: Set<string>, today: string): { current: number; best: number } // Règles : consécutifs jusqu'à hier (ou aujourd'hui si coché) ; // aujourd'hui non coché ≠ cassé (la grâce court jusqu'à minuit).

Écrivez les tests AVANT (ch. 14.2) : série qui traverse un mois, série de 1, aujourd’hui coché/pas coché, trou d’hier — la table des cas fait la moitié de la conception. today est un PARAMÈTRE (l’horloge s’injecte — testabilité).

  • La grille de chaleur : 13 semaines × 7 — un simple flexWrap de Views 10×10 teintées par intensité (0 → ink-900, fait → brand). Pas de lib : ~40 lignes avec la dérivation SELECT day FROM checks WHERE habit_id = ? AND day >= ?.

Les jalons

  1. lib/streaks.ts + la suite de tests COMPLÈTE (le jalon le plus important).
  2. Schéma + CRUD habitudes + le check du jour (l’écran principal en liste).
  3. Streaks affichées (badge 🔥 N) + la règle de grâce vérifiée en manuel.
  4. La grille de chaleur.
  5. Rappels par habitude (planification/annulation cohérentes — le pattern du Todo).
  6. APK + une VRAIE habitude suivie 2 semaines.

Critères de réussite

  • La suite de tests de streaks passe — y compris le cas « 23 h 59 vs 00 h 01 »
  • Cocher hier soir + aujourd’hui matin = série de 2 (pas de doublon, pas de trou)
  • La grille affiche exactement les 90 derniers jours locaux, alignée sur les semaines
  • Supprimer une habitude annule son rappel ET efface ses checks (CASCADE vérifié)
  • Le re-tap du check du jour décoche (l’UNIQUE(habit_id, day) rend l’upsert propre)
  • 2 semaines d’usage réel : votre streak à VOUS tient

Pièges connus

  • Le jour local : new Date().toISOString().slice(0,10) est UTC — FAUX après 22-23 h en France. La fonction localDay() (getFullYear/Month/Date locaux) va dans lib/ et s’utilise PARTOUT.
  • Ne recalculez pas les streaks en SQL (les gaps consécutifs en SQL = douleur) : SELECT des jours → Set → la fonction pure. La base stocke des FAITS, lib/ calcule.
  • La notification « tu vas perdre ta série de 12 ! » à 21 h est LE rappel qui marche (bonus : conditionnez le message à la streak courante — replanification quotidienne au premier lancement du jour).

💡 L’upgrade : les habitudes hebdomadaires (« 3 fois par semaine » — la logique de streak devient un vrai sujet de conception : qu’est-ce qu’une « semaine réussie » ?), et le partage de la grille en image (le pattern view-shot du ch. 9.4).