import 'package:flutter/material.dart'; import 'package:flutter_widget_from_html/flutter_widget_from_html.dart'; import 'package:manager_api_new/api.dart'; import 'package:manager_app/constants.dart'; import 'package:manager_app/Screens/Configurations/Section/SubSection/Parcours/showNewOrUpdateGuidedPath.dart'; import 'package:provider/provider.dart'; import 'package:manager_app/app_context.dart'; import 'package:manager_app/Models/managerContext.dart'; import 'package:manager_app/Components/message_notification.dart'; class ParcoursConfig extends StatefulWidget { final List initialValue; final String parentId; final bool isEvent; final bool isEscapeMode; final ValueChanged> onChanged; const ParcoursConfig({ Key? key, required this.initialValue, required this.parentId, required this.isEvent, this.isEscapeMode = false, required this.onChanged, }) : super(key: key); @override _ParcoursConfigState createState() => _ParcoursConfigState(); } class _ParcoursConfigState extends State { late List paths; @override void initState() { super.initState(); paths = List.from(widget.initialValue); paths.sort((a, b) => (a.order ?? 0).compareTo(b.order ?? 0)); WidgetsBinding.instance.addPostFrameCallback((_) => _loadFromApi()); } Future _loadFromApi() async { final appContext = Provider.of(context, listen: false); final api = (appContext.getContext() as ManagerAppContext) .clientAPI! .sectionMapApi!; try { // Backend already includes steps + quiz questions via .Include() final fetchedPaths = await api.sectionMapGetAllGuidedPathFromSection(widget.parentId); if (fetchedPaths == null || !mounted) return; fetchedPaths.sort((a, b) => (a.order ?? 0).compareTo(b.order ?? 0)); setState(() { paths = List.from(fetchedPaths); }); } catch (e) { // Silently keep initial value on error } } @override Widget build(BuildContext context) { return Column( children: [ Padding( padding: const EdgeInsets.all(8.0), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text("Parcours Guidés", style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)), ElevatedButton.icon( icon: Icon(Icons.add), label: Text("Ajouter un parcours"), onPressed: () { final appContext = Provider.of(context, listen: false); showNewOrUpdateGuidedPath( context, null, widget.parentId, widget.isEvent, widget.isEscapeMode, (newPath) async { try { newPath.order = paths.length; newPath.instanceId = (appContext.getContext() as ManagerAppContext) .instanceId; if (widget.isEscapeMode) { newPath.sectionGameId = widget.parentId; } else if (widget.isEvent) { newPath.sectionEventId = widget.parentId; } else { newPath.sectionMapId = widget.parentId; } final createdPath = await (appContext.getContext() as ManagerAppContext) .clientAPI! .sectionMapApi! .sectionMapCreateGuidedPath( widget.parentId, newPath); if (createdPath != null) { if (mounted) { setState(() { paths.add(createdPath); widget.onChanged(paths); }); } showNotification(kSuccess, kWhite, 'Parcours créé avec succès', context, null); } } catch (e) { showNotification( kError, kWhite, 'Erreur lors de la création du parcours', context, null); rethrow; // Important so showNewOrUpdateGuidedPath knows it failed } }, ); }, style: ElevatedButton.styleFrom( backgroundColor: kSuccess, foregroundColor: kWhite), ), ], ), ), Expanded( child: paths.isEmpty ? Center( child: Text("Aucun parcours configuré", style: TextStyle(fontStyle: FontStyle.italic))) : ReorderableListView.builder( buildDefaultDragHandles: false, itemCount: paths.length, onReorder: (oldIndex, newIndex) async { if (newIndex > oldIndex) newIndex -= 1; final item = paths.removeAt(oldIndex); paths.insert(newIndex, item); for (int i = 0; i < paths.length; i++) { paths[i].order = i; } setState(() {}); widget.onChanged(paths); final appContext = Provider.of(context, listen: false); final api = (appContext.getContext() as ManagerAppContext) .clientAPI! .sectionMapApi!; try { // Update all affected paths orders await Future.wait( paths.map((p) => api.sectionMapUpdateGuidedPath(p))); } catch (e) { showNotification( kError, kWhite, 'Erreur lors de la mise à jour de l\'ordre', context, null); } }, itemBuilder: (context, index) { final path = paths[index]; return Card( key: ValueKey(path.id ?? index.toString()), margin: EdgeInsets.symmetric(horizontal: 10, vertical: 5), child: ListTile( leading: CircleAvatar( child: Text("${index + 1}"), backgroundColor: kPrimaryColor, foregroundColor: kWhite), title: path.title != null && path.title!.isNotEmpty ? HtmlWidget( path.title! .firstWhere((t) => t.language == 'FR', orElse: () => path.title![0]) .value ?? "Parcours sans titre", ) : Text("Parcours sans titre"), subtitle: Text("${path.steps?.length ?? 0} étapes"), trailing: Row( mainAxisSize: MainAxisSize.min, children: [ IconButton( icon: Icon(Icons.edit, color: kPrimaryColor), onPressed: () { final appContext = Provider.of( context, listen: false); showNewOrUpdateGuidedPath( context, path, widget.parentId, widget.isEvent, widget.isEscapeMode, (updatedPath) async { try { final api = (appContext.getContext() as ManagerAppContext) .clientAPI! .sectionMapApi!; final result = await api.sectionMapUpdateGuidedPath( updatedPath); if (result != null) { if (mounted) { setState(() { paths[index] = result; widget.onChanged(paths); }); } showNotification( kSuccess, kWhite, 'Parcours mis à jour avec succès', context, null); } } catch (e) { showNotification( kError, kWhite, 'Erreur lors de la mise à jour du parcours', context, null); rethrow; } }, ); }, ), IconButton( icon: Icon(Icons.delete, color: kError), onPressed: () async { final appContext = Provider.of( context, listen: false); try { if (path.id != null) { await (appContext.getContext() as ManagerAppContext) .clientAPI! .sectionMapApi! .sectionMapDeleteGuidedPath(path.id!); } setState(() { paths.removeAt(index); for (int i = 0; i < paths.length; i++) { paths[i].order = i; } widget.onChanged(paths); }); showNotification( kSuccess, kWhite, 'Parcours supprimé avec succès', context, null); } catch (e) { showNotification( kError, kWhite, 'Erreur lors de la suppression du parcours', context, null); } }, ), ReorderableDragStartListener( index: index, child: Icon(Icons.drag_handle), ), ], ), ), ); }, ), ), ], ); } }