Initial commit: app Fideliter client (Flutter)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-17 21:32:39 +02:00
commit 01a0f1029f
49 changed files with 2613 additions and 0 deletions
+35
View File
@@ -0,0 +1,35 @@
/// Le compte fidélité du client connecté. Le [code] est encodé dans son QR.
class Client {
final String id; // uuid Supabase
final String code; // ex : « FID-3F9K2A »
final String nom;
final String? prenom;
final String? telephone;
final double points;
const Client({
required this.id,
required this.code,
required this.nom,
this.prenom,
this.telephone,
this.points = 0,
});
/// Nom complet affiché : « Prénom Nom » (ou juste le nom si pas de prénom).
String get nomComplet {
final p = (prenom ?? '').trim();
return p.isEmpty ? nom : '$p $nom';
}
factory Client.fromMap(Map<String, dynamic> map) {
return Client(
id: map['id'].toString(),
code: (map['code'] as String?) ?? '',
nom: (map['nom'] as String?) ?? '',
prenom: map['prenom'] as String?,
telephone: map['telephone'] as String?,
points: (map['points'] as num?)?.toDouble() ?? 0,
);
}
}
+39
View File
@@ -0,0 +1,39 @@
/// Type d'un mouvement de points dans l'historique.
class TypeMouvement {
static const facture = 'facture';
static const recompense = 'recompense';
static const ajustement = 'ajustement';
}
/// Une ligne d'historique : gain (facture) ou dépense (récompense).
class Mouvement {
final String id;
final String type;
final double? montantEuros;
final double points; // signé
final String libelle;
final DateTime date;
const Mouvement({
required this.id,
required this.type,
this.montantEuros,
required this.points,
required this.libelle,
required this.date,
});
bool get estGain => points >= 0;
factory Mouvement.fromMap(Map<String, dynamic> map) {
return Mouvement(
id: map['id'].toString(),
type: (map['type'] as String?) ?? TypeMouvement.ajustement,
montantEuros: (map['montant_euros'] as num?)?.toDouble(),
points: (map['points'] as num?)?.toDouble() ?? 0,
libelle: (map['libelle'] as String?) ?? '',
date: DateTime.tryParse(map['created_at']?.toString() ?? '')?.toLocal() ??
DateTime.fromMillisecondsSinceEpoch(0),
);
}
}
+23
View File
@@ -0,0 +1,23 @@
/// Une récompense du catalogue que le client peut viser avec ses points.
class Recompense {
final String id;
final String nom;
final double coutPoints;
final bool actif;
const Recompense({
required this.id,
required this.nom,
required this.coutPoints,
this.actif = true,
});
factory Recompense.fromMap(Map<String, dynamic> map) {
return Recompense(
id: map['id'].toString(),
nom: (map['nom'] as String?) ?? '',
coutPoints: (map['cout_points'] as num?)?.toDouble() ?? 0,
actif: (map['actif'] as bool?) ?? true,
);
}
}