// lib/pages/team/team_detail_page.dart import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:gifunavi/pages/team/team_controller.dart'; import 'package:gifunavi/routes/app_pages.dart'; import 'package:gifunavi/model/team.dart'; import 'package:gifunavi/model/category.dart'; class TeamDetailPage extends StatefulWidget { const TeamDetailPage({super.key}); @override _TeamDetailPageState createState() => _TeamDetailPageState(); } class _TeamDetailPageState extends State { late TeamController controller; late TextEditingController _teamNameController = TextEditingController(); final RxString mode = ''.obs; final Rx team = Rx(null); Worker? _teamNameWorker; @override void initState() { super.initState(); controller = Get.find(); _teamNameController = TextEditingController(); WidgetsBinding.instance.addPostFrameCallback((_) { _initializeData(); }); } void _initializeData() { final args = Get.arguments; if (args != null && args is Map) { mode.value = args['mode'] as String? ?? ''; team.value = args['team'] as Team?; if (mode.value == 'edit' && team.value != null) { controller.setSelectedTeam(team.value!); controller.fetchTeamMembers(team.value!.id); // メンバーを取得 } else { controller.resetForm(); } } else { // 引数がない場合は新規作成モードとして扱う mode.value = 'new'; controller.resetForm(); } _teamNameController.text = controller.teamName.value; // Use ever instead of direct listener _teamNameWorker = ever(controller.teamName, (String value) { if (_teamNameController.text != value) { _teamNameController.text = value; } }); } @override void dispose() { _teamNameWorker?.dispose(); _teamNameController.dispose(); //controller.resetForm(); // Reset the form when leaving the page super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text( Get.arguments['mode'] == 'new' ? '新規チーム作成' : 'チーム詳細'), leading: IconButton( icon: const Icon(Icons.arrow_back), onPressed: () { controller.cleanupForNavigation(); Get.back(); }, ), actions: [ IconButton( icon: const Icon(Icons.save), onPressed: () async { try { await controller.saveTeam(); Get.back(); } catch (e) { Get.snackbar('エラー', e.toString(), snackPosition: SnackPosition.BOTTOM); } }, ), Obx(() { if (mode.value == 'edit') { return IconButton( icon: const Icon(Icons.delete), onPressed: () async { try { await controller.deleteSelectedTeam(); Get.back(); } catch (e) { Get.snackbar('エラー', e.toString(), snackPosition: SnackPosition.BOTTOM); } }, ); } else { return const SizedBox.shrink(); } }), ], ), body: Obx(() { if (controller.isLoading.value) { return const Center(child: CircularProgressIndicator()); } final filteredCategories = controller.getFilteredCategories(); // 選択されているカテゴリが表示リストに含まれていない場合、最初の項目を選択する if (controller.selectedCategory.value == null || !filteredCategories.contains(controller.selectedCategory.value)) { controller.updateCategory(filteredCategories.isNotEmpty ? filteredCategories.first : null); } // 選択されているカテゴリが表示リストに含まれていない場合、最初の項目を選択する if (controller.selectedCategory.value == null || !filteredCategories.contains(controller.selectedCategory.value)) { controller.updateCategory(filteredCategories.isNotEmpty ? filteredCategories.first : null); } return SingleChildScrollView( child: Padding( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Obx(() => TextFormField( decoration: const InputDecoration(labelText: 'チーム名'), controller: TextEditingController(text: controller .selectedTeam.value?.teamName ?? ''), onChanged: (value) => controller.updateTeamName(value), ), ), const SizedBox(height: 16), if (filteredCategories.isEmpty) const Text('カテゴリデータを読み込めませんでした。', style: TextStyle(color: Colors.red)) else Obx(() => DropdownButtonFormField( decoration: const InputDecoration( labelText: 'カテゴリ'), value: controller.selectedCategory.value, items: filteredCategories.map((category) => DropdownMenuItem( value: category, child: Text(category.categoryName), )).toList(), onChanged: (value) => controller.updateCategory(value), ), ), if (filteredCategories.isEmpty && controller.categories.isNotEmpty) Padding( padding: const EdgeInsets.only(top: 8.0), child: Text( '注意: チーム構成に適さないカテゴリーも表示されています。', style: TextStyle(color: Colors.orange[700], fontSize: 12), ), ), Padding( padding: const EdgeInsets.symmetric(vertical: 16), child: Text('所有者: ${controller.currentUser.value?.email ?? "未設定"}'), ), if (mode.value == 'edit') ...[ const SizedBox(height: 24), const Text('メンバーリスト', style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold)), const SizedBox(height: 8), Obx(() { final teamMembers = controller.teamMembers; return ListView.builder( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), itemCount: teamMembers.length, itemBuilder: (context, index) { final member = teamMembers[index]; final isDummyEmail = member.email?.startsWith( 'dummy_') ?? false; final isCurrentUser = member.email == controller.currentUser.value?.email; final displayName = isDummyEmail ? '${member.lastname} ${member.firstname}' : member.isActive ? '${member.lastname} ${member.firstname}' : member.email?.split('@')[0] ?? ''; //(未承認)'; return ListTile( title: Text( '$displayName${isCurrentUser ? ' (自分)' : ''}'), subtitle: isDummyEmail ? const Text('Email未設定') : null, onTap: isCurrentUser ? null : () async { final result = await Get.toNamed( AppPages.MEMBER_DETAIL, arguments: { 'mode': 'edit', 'member': member, 'teamId': controller.selectedTeam.value?.id }, ); await controller.fetchTeamMembers( controller.selectedTeam.value!.id); }, ); }, ); }), const SizedBox(height: 16), ElevatedButton( child: const Text('新しいメンバーを追加'), onPressed: () async { final result = await Get.toNamed( AppPages.MEMBER_DETAIL, arguments: { 'mode': 'new', 'teamId': controller.selectedTeam.value?.id }, ); if (result == true && controller.selectedTeam.value != null) { await controller.fetchTeamMembers(controller.selectedTeam.value!.id); controller.teamMembers.refresh(); // 明示的に更新を通知 } }, ), ], ], ), ), ); }), ); } }