// lib/pages/team/member_detail_page.dart import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:gifunavi/pages/team/member_controller.dart'; import 'package:gifunavi/pages/team/team_controller.dart'; import 'package:intl/intl.dart'; // この行を追加 import 'package:gifunavi/widgets/custom_date_picker.dart'; // 追加 import 'package:gifunavi/routes/app_pages.dart'; import 'package:gifunavi/model/user.dart'; class MemberDetailPage extends StatefulWidget { const MemberDetailPage({super.key}); @override _MemberDetailPageState createState() => _MemberDetailPageState(); } class _MemberDetailPageState extends State { final MemberController controller = Get.find(); final TeamController teamController = Get.find(); late TextEditingController _firstNameController; late TextEditingController _lastNameController; late TextEditingController _emailController; @override void initState() { super.initState(); _initializeControllers(); WidgetsBinding.instance.addPostFrameCallback((_) { final mode = Get.arguments['mode']; final member = Get.arguments['member']; if (mode == 'edit' && member != null) { controller.setSelectedMember(member); } }); } void _initializeControllers() { _firstNameController = TextEditingController(text: controller.firstname.value); _lastNameController = TextEditingController(text: controller.lastname.value); _emailController = TextEditingController(text: controller.email.value); controller.firstname.listen((value) { if (_firstNameController.text != value) { _firstNameController.value = TextEditingValue( text: value, selection: TextSelection.fromPosition( TextPosition(offset: value.length)), ); } }); controller.lastname.listen((value) { if (_lastNameController.text != value) { _lastNameController.value = TextEditingValue( text: value, selection: TextSelection.fromPosition( TextPosition(offset: value.length)), ); } }); controller.email.listen((value) { if (_emailController.text != value) { _emailController.value = TextEditingValue( text: value, selection: TextSelection.fromPosition( TextPosition(offset: value.length)), ); } }); } Future _handleSaveAndNavigateBack_old() async { bool success = await controller.saveMember(); if (success) { Get.until((route) => Get.currentRoute == AppPages.TEAM_DETAIL); // スナックバーが表示されるのを待つ await Future.delayed(const Duration(seconds: 1)); // 現在のスナックバーを安全に閉じる if (Get.isSnackbarOpen) { await Get.closeCurrentSnackbar(); } // リストページに戻る //Get.until((route) => Get.currentRoute == '/team'); // または、リストページの具体的なルート名がある場合は以下を使用 // Get.offNamed('/team'); } } Future _handleSaveAndNavigateBack() async { if (!controller.validateInputs()) return; try { await controller.saveMember(); await teamController.updateTeamComposition(); Get.until((route) => Get.currentRoute == AppPages.TEAM_DETAIL); await Future.delayed(const Duration(seconds: 1)); if (Get.isSnackbarOpen) { await Get.closeCurrentSnackbar(); } } catch (e) { print('Error saving member: $e'); Get.snackbar('エラー', 'メンバーの保存に失敗しました: ${e.toString()}', snackPosition: SnackPosition.BOTTOM); } } Future _handleDeleteAndNavigateBack() async { final confirmed = await Get.dialog( AlertDialog( title: const Text('確認'), content: const Text('このメンバーを削除してもよろしいですか?'), actions: [ TextButton( child: const Text('キャンセル'), onPressed: () => Get.back(result: false), ), TextButton( child: const Text('削除'), onPressed: () => Get.back(result: true), ), ], ), ); if (confirmed == true) { try { if (controller.member.value != null && controller.member.value!.id != null) { await teamController.removeMember(controller.member.value!.id!); // スナックバーの処理を安全に行う await _safelyCloseSnackbar(); // 画面遷移 Get.until((route) => Get.currentRoute == AppPages.TEAM_DETAIL); } else { Get.snackbar('エラー', 'メンバー情報が不正です', snackPosition: SnackPosition.BOTTOM); } } catch (e) { print('Error deleting member: $e'); Get.snackbar('エラー', 'メンバーの削除に失敗しました: ${e.toString()}', snackPosition: SnackPosition.BOTTOM); } } } Future _safelyCloseSnackbar() async { if (Get.isSnackbarOpen) { try { await Get.closeCurrentSnackbar(); } catch (e) { print('Error closing snackbar: $e'); } } } @override Widget build(BuildContext context) { final mode = Get.arguments['mode'] as String; //final member = Get.arguments['member']; final teamId = Get.arguments['teamId'] as int; /* return MaterialApp( // MaterialApp をここに追加 localizationsDelegates: [ GlobalMaterialLocalizations.delegate, GlobalWidgetsLocalizations.delegate, GlobalCupertinoLocalizations.delegate, ], supportedLocales: [ const Locale('ja', 'JP'), ], home:Scaffold( */ return Scaffold( appBar: AppBar( title: Text(mode == 'new' ? 'メンバー追加' : 'メンバー詳細'), ), body: Obx(() { if (controller.isLoading.value) { return const Center(child: CircularProgressIndicator()); } // TextEditingControllerをObxの中で作成 final emailController = TextEditingController(text: controller.email.value); // カーソル位置を保持 emailController.selection = TextSelection.fromPosition( TextPosition(offset: controller.email.value.length), ); return Column( children: [ Expanded( child: SingleChildScrollView( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ if (mode == 'new') TextFormField( controller: _emailController, onChanged: (value) => controller.updateEmail(value), decoration: const InputDecoration(labelText: 'メールアドレス'), keyboardType: TextInputType.emailAddress, // メールアドレス用のキーボードを表示 autocorrect: false, // 自動修正を無効化 enableSuggestions: false, ) else if (controller.isDummyEmail) const Text('メールアドレス: (メアド無し)') else Text('メールアドレス: ${controller.email.value}'), if (controller.email.value.isEmpty || controller.isDummyEmail || mode == 'edit') ...[ TextFormField( decoration: const InputDecoration(labelText: '姓'), controller: _lastNameController, onChanged: (value) => controller.updateLastName(value), //controller: TextEditingController(text: controller.lastname.value), ), TextFormField( decoration: const InputDecoration(labelText: '名'), controller: _firstNameController, //onChanged: (value) => controller.firstname.value = value, onChanged: (value) => controller.updateFirstName(value), //controller: TextEditingController(text: controller.firstname.value), ), // 生年月日 if (controller.isDummyEmail || !controller.isOver18()) ListTile( title: const Text('生年月日'), subtitle: Text(controller.dateOfBirth.value != null ? '${DateFormat('yyyy年MM月dd日').format(controller.dateOfBirth.value!)} (${controller.getAgeAndGrade()})' : '未設定'), onTap: () async { final date = await showDialog( context: context, builder: (BuildContext context) { return CustomDatePicker( initialDate: controller.dateOfBirth.value ?? DateTime.now(), firstDate: DateTime(1920), lastDate: DateTime.now(), currentDateText: controller.dateOfBirth.value != null ? DateFormat('yyyy/MM/dd').format(controller.dateOfBirth.value!) : '', ); }, ); if (date != null) { controller.dateOfBirth.value = date; } }, ) else const Text('18歳以上'), SwitchListTile( title: const Text('性別'), subtitle: Text(controller.female.value ? '女性' : '男性'), value: controller.female.value, onChanged: (value) => controller.female.value = value, ), ], ]), ), ), Padding( padding: const EdgeInsets.all(16.0), child: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ ElevatedButton( onPressed: _handleDeleteAndNavigateBack, style: ElevatedButton.styleFrom( backgroundColor: Colors.red, foregroundColor: Colors.white, ), child: const Text('削除'), ), if (!controller.isDummyEmail && !controller.isApproved && mode == 'edit') ElevatedButton( onPressed: () => controller.resendInvitation(), style: ElevatedButton.styleFrom( backgroundColor: Colors.white, foregroundColor: Colors.black, ), child: const Text('招待再送信'), ), ElevatedButton( onPressed: _handleSaveAndNavigateBack, style: ElevatedButton.styleFrom( backgroundColor: Colors.green, foregroundColor: Colors.white, ), child: Text(controller.isDummyEmail ? '保存' : (mode == 'new' && !controller.isDummyEmail) ? '保存・招待' : '保存'), ), ], ), ), ], ); }), ); } @override void dispose() { _firstNameController.dispose(); _lastNameController.dispose(); _emailController.dispose(); super.dispose(); } }