feat(frontend): add material catalogue screen with search and filters

This commit is contained in:
SaidSoighiri94
2026-07-06 11:44:43 +02:00
parent 97a1ad9e84
commit 84bd2cc629
6 changed files with 398 additions and 2 deletions
@@ -0,0 +1,90 @@
import "package:flutter/material.dart";
import "package:google_fonts/google_fonts.dart";
import "../theme/ensup_colors.dart";
import "../models/materiel_item.dart";
import "status_pill.dart";
/// Ligne du catalogue matériel (fidèle au `.mat-card` de la maquette).
class MaterielCard extends StatelessWidget {
const MaterielCard({super.key, required this.item, this.onSelect});
final MaterielItem item;
final VoidCallback? onSelect;
@override
Widget build(BuildContext context) {
final disponible = item.disponible;
final accent = disponible ? EnsupColors.cyan : EnsupColors.muted;
return Opacity(
opacity: disponible ? 1 : 0.55,
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 18, vertical: 16),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
border: Border.all(color: EnsupColors.line, width: 1.5),
),
child: Row(
children: [
Container(
width: 44,
height: 44,
decoration: BoxDecoration(
color: accent.withValues(alpha: 0.08),
borderRadius: BorderRadius.circular(10),
),
child: Icon(item.icon, color: accent, size: 20),
),
const SizedBox(width: 14),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
item.nom,
style: GoogleFonts.darkerGrotesque(
fontWeight: FontWeight.w700,
fontSize: 16,
color: EnsupColors.text,
),
),
const SizedBox(height: 2),
Text(
"${item.categorie} · Réf. ${item.reference} · ${item.campus}",
style: GoogleFonts.titilliumWeb(fontSize: 12, color: EnsupColors.muted),
),
],
),
),
const SizedBox(width: 10),
StatusPill(disponible: disponible),
const SizedBox(width: 12),
if (disponible)
FilledButton(
onPressed: onSelect,
style: FilledButton.styleFrom(
backgroundColor: EnsupColors.cyan,
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
),
child: Text(
"Sélectionner",
style: GoogleFonts.darkerGrotesque(fontWeight: FontWeight.w700, fontSize: 14),
),
)
else
Text(
"Indisponible",
style: GoogleFonts.darkerGrotesque(
fontWeight: FontWeight.w700,
fontSize: 14,
color: EnsupColors.muted,
),
),
],
),
),
);
}
}
+29
View File
@@ -0,0 +1,29 @@
import "package:flutter/material.dart";
import "package:google_fonts/google_fonts.dart";
/// Pastille de statut d'un matériel (disponible / emprunté).
class StatusPill extends StatelessWidget {
const StatusPill({super.key, required this.disponible});
final bool disponible;
@override
Widget build(BuildContext context) {
final label = disponible ? "Disponible" : "Emprunté";
final background = disponible ? const Color(0xFFDCFCE7) : const Color(0xFFFEF9C3);
final foreground = disponible ? const Color(0xFF15803D) : const Color(0xFFA16207);
return Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 4),
decoration: BoxDecoration(color: background, borderRadius: BorderRadius.circular(999)),
child: Text(
label,
style: GoogleFonts.darkerGrotesque(
fontSize: 14,
fontWeight: FontWeight.w700,
color: foreground,
),
),
);
}
}