manager-app/lib/Screens/Applications/web_app_screen.dart
Thomas Fransolet a6463acce6 Guide IA : libellés de canaux, activation depuis la carte, notifications topRight
La carte « Où le guide est disponible » affichait la valeur entière de l'enum
AppType (0, 1, 2…) au lieu d'un libellé. Réutilise les clés statsChannel*
déjà traduites en FR/EN/NL pour l'écran Statistiques.

L'activation de l'assistant par canal se réglait dans chaque onglet
d'application, alors que le champ vit sur ApplicationInstance et se résout
par (InstanceId, AppType). Le réglage passe dans la liste des canaux du
Guide IA, où tous les canaux sont visibles au même endroit ; le paramètre
showAssistant de AppConfigurationLinkScreen devient inutile.

Les notifications de cet écran passaient par ScaffoldMessenger (en bas),
contrairement au reste de l'application qui utilise showNotification
(toastification, topRight).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-14 15:30:33 +02:00

201 lines
6.3 KiB
Dart

import 'package:collection/collection.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:manager_app/Screens/Applications/app_configuration_link_screen.dart';
import 'package:manager_app/app_context.dart';
import 'package:manager_app/Components/message_notification.dart';
import 'package:manager_app/constants.dart';
import 'package:manager_app/Models/managerContext.dart';
import 'package:manager_api_new/api.dart';
import 'package:provider/provider.dart';
class WebInstanceLoader extends StatefulWidget {
const WebInstanceLoader({Key? key}) : super(key: key);
@override
State<WebInstanceLoader> createState() => _WebInstanceLoaderState();
}
class _WebInstanceLoaderState extends State<WebInstanceLoader> {
bool _creating = false;
String? _error;
ApplicationInstanceDTO? _instance;
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) => _init());
}
void _init() {
final appContext = Provider.of<AppContext>(context, listen: false);
final managerCtx = appContext.getContext() as ManagerAppContext;
final existing = managerCtx.instanceDTO?.applicationInstanceDTOs
?.firstWhereOrNull((ai) => ai.appType == AppType.Web);
if (existing != null) {
setState(() => _instance = existing);
}
}
Future<void> _create() async {
final appContext = Provider.of<AppContext>(context, listen: false);
final managerCtx = appContext.getContext() as ManagerAppContext;
final instanceDTO = managerCtx.instanceDTO!;
setState(() {
_creating = true;
_error = null;
});
try {
final newInstance = ApplicationInstanceDTO(
instanceId: instanceDTO.id,
appType: AppType.Web,
languages: ['fr'],
isAssistant: false,
);
final created = await managerCtx.clientAPI!.applicationInstanceApi!
.applicationInstanceCreate(newInstance);
if (created != null) {
instanceDTO.applicationInstanceDTOs = [...?instanceDTO.applicationInstanceDTOs, created];
setState(() => _instance = created);
} else {
setState(() => _error = 'La création a échoué (réponse vide)');
}
} catch (e) {
setState(() => _error = e.toString());
} finally {
setState(() => _creating = false);
}
}
@override
Widget build(BuildContext context) {
if (_instance != null) {
return WebAppScreen(applicationInstanceDTO: _instance!);
}
return Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
'L\'application web n\'est pas encore initialisée.',
style: TextStyle(color: kBodyTextColor),
),
if (_error != null) ...[
const SizedBox(height: 8),
Text(_error!, style: TextStyle(color: kError, fontSize: 12)),
],
const SizedBox(height: 16),
_creating
? const CircularProgressIndicator()
: ElevatedButton(
onPressed: _create,
child: const Text('Initialiser l\'application web'),
),
],
),
);
}
}
class WebAppScreen extends StatelessWidget {
final ApplicationInstanceDTO applicationInstanceDTO;
const WebAppScreen({Key? key, required this.applicationInstanceDTO}) : super(key: key);
@override
Widget build(BuildContext context) {
final appContext = Provider.of<AppContext>(context);
final managerAppContext = appContext.getContext() as ManagerAppContext;
final instanceDTO = managerAppContext.instanceDTO;
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
if (instanceDTO?.webSlug != null || instanceDTO?.publicApiKey != null)
Card(
margin: const EdgeInsets.fromLTRB(16, 8, 16, 8),
color: kWhite,
elevation: 0,
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Accès web', style: TextStyle(fontWeight: FontWeight.w500, fontSize: 21)),
const SizedBox(height: 12),
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: _InfoRow(
label: 'URL visiteurs',
value: 'app.myinfomate.be/${instanceDTO?.webSlug ?? ''}',
),
),
const SizedBox(width: 24),
Expanded(
child: _InfoRow(
label: 'Clé publique API',
value: instanceDTO?.publicApiKey ?? '',
),
),
],
),
],
),
),
),
Expanded(
child: AppConfigurationLinkScreen(
applicationInstanceDTO: applicationInstanceDTO,
configTitle: 'Contenu de l\'application web',
appUpdatedLabel: 'Application web mise à jour',
),
),
],
);
}
}
class _InfoRow extends StatelessWidget {
final String label;
final String value;
const _InfoRow({required this.label, required this.value});
@override
Widget build(BuildContext context) {
return Row(
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(label, style: TextStyle(fontSize: 12, color: kBodyTextColor)),
const SizedBox(height: 2),
Text(
value,
style: TextStyle(fontSize: 13, fontFamily: 'monospace', color: kPrimaryColor),
overflow: TextOverflow.ellipsis,
),
],
),
),
IconButton(
icon: Icon(Icons.copy_outlined, size: 18, color: kPrimaryColor),
tooltip: 'Copier',
onPressed: () {
Clipboard.setData(ClipboardData(text: value));
showNotification(kSuccess, kWhite, 'Copié !', context, null);
},
),
],
);
}
}