Files
rog_app/lib/pages/team/team_controller.dart
2024-09-02 21:25:19 +09:00

698 lines
22 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// lib/controllers/team_controller.dart
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:gifunavi/model/team.dart';
import 'package:gifunavi/model/category.dart';
import 'package:gifunavi/model/user.dart';
import 'package:gifunavi/model/entry.dart';
import 'package:gifunavi/services/api_service.dart';
import 'package:gifunavi/widgets/category_change_dialog.dart';
import 'package:gifunavi/routes/app_pages.dart';
import 'package:gifunavi/pages/entry/entry_controller.dart';
import 'package:gifunavi/model/event.dart';
class TeamController extends GetxController {
final ApiService _apiService;
//final EntryController _entryController;
TeamController({
required ApiService apiService,
//required EntryController entryController,
}) : _apiService = apiService;
//_entryController = entryController;
final teams = <Team>[].obs;
final categories = <NewCategory>[].obs;
final RxList<User> teamMembers = <User>[].obs;
final teamEntries = <Entry>[].obs;
final selectedCategory = Rx<NewCategory?>(null);
final selectedTeam = Rx<Team?>(null);
final currentUser = Rx<User?>(null);
final teamName = ''.obs;
final isLoading = false.obs;
final error = RxString('');
@override
void onInit() async {
super.onInit();
try {
//_apiService = Get.find<ApiService>();
//if (!Get.isRegistered<EntryController>()) {
// Get.put(EntryController());
//}
//_entryController = Get.find<EntryController>();
await loadInitialData();
} catch (e) {
error.value = e.toString();
print('Error in TeamController onInit: $e');
}
}
Future<void> loadInitialData() async {
try {
isLoading.value = true;
await Future.wait([
fetchCategories(),
fetchTeams(),
getCurrentUser(),
]);
if (categories.isNotEmpty && selectedCategory.value == null) {
selectedCategory.value = categories.first;
}
} catch (e) {
error.value = e.toString();
} finally {
isLoading.value = false;
}
}
void setSelectedTeam(Team team) {
selectedTeam.value = team;
teamName.value = team.teamName;
if (categories.isNotEmpty) {
selectedCategory.value = categories.firstWhere(
(category) => category.id == team.category.id,
orElse: () => categories.first,
);
} else {
// カテゴリリストが空の場合、teamのカテゴリをそのまま使用
selectedCategory.value = team.category;
}
fetchTeamMembers(team.id);
}
void resetForm() {
selectedTeam.value = null;
teamName.value = '';
if (categories.isNotEmpty) {
selectedCategory.value = categories.first;
} else {
selectedCategory.value = null;
// カテゴリが空の場合、エラーメッセージをセット
error.value = 'カテゴリデータが取得できませんでした。';
} teamMembers.clear();
}
void cleanupForNavigation() {
selectedTeam.value = null;
teamName.value = '';
selectedCategory.value = categories.isNotEmpty ? categories.first : null;
teamMembers.clear();
//teamMembersはクリアしない
// 必要に応じて他のクリーンアップ処理を追加
}
Future<void> fetchTeams() async {
try {
isLoading.value = true;
final fetchedTeams = await _apiService.getTeams();
teams.assignAll(fetchedTeams);
} catch (e) {
error.value = 'チームの取得に失敗しました: $e';
print('Error fetching teams: $e');
} finally {
isLoading.value = false;
}
}
bool checkIfUserHasEntryData(){
if (teams.isEmpty) {
return false;
}else {
return true;
}
}
Future<void> fetchCategories() async {
try {
final fetchedCategories = await _apiService.getCategories();
categories.assignAll(fetchedCategories);
print("Fetched categories: ${categories.length}"); // デバッグ用
} catch (e) {
print('Error fetching categories: $e');
}
}
Future<void> getCurrentUser() async {
try {
final user = await _apiService.getCurrentUser();
currentUser.value = user;
} catch (e) {
print('Error getting current user: $e');
}
}
Future<Team> createTeam(String teamName, int categoryId) async {
final newTeam = await _apiService.createTeam(teamName, categoryId);
// 自分自身をメンバーとして自動登録
await _apiService.createTeamMember(
newTeam.id,
currentUser.value?.email,
currentUser.value!.firstname,
currentUser.value!.lastname,
currentUser.value?.dateOfBirth,
currentUser.value?.female,
);
return newTeam;
}
Future<Team> updateTeam(int teamId, String teamName, int categoryId) async {
// APIサービスを使用してチームを更新
final updatedTeam = await _apiService.updateTeam(teamId, teamName, categoryId);
return updatedTeam;
}
Future<void> deleteTeam(int teamId) async {
bool confirmDelete = 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),
),
],
),
) ?? false;
if (confirmDelete) {
try {
// まず、チームのメンバーを全て削除
await _apiService.deleteAllTeamMembers(teamId);
// その後、チームを削除
await _apiService.deleteTeam(teamId);
// ローカルのチームリストを更新
teams.removeWhere((team) => team.id == teamId);
/*
Get.snackbar(
'成功',
'チームとそのメンバーが削除されました',
backgroundColor: Colors.green,
colorText: Colors.white,
snackPosition: SnackPosition.BOTTOM,
);
*/
// チームリスト画面に戻る
Get.back();
} catch (e) {
print('Error deleting team and members: $e');
Get.snackbar('エラー', 'チームとメンバーの削除に失敗しました');
}
}
}
Future<void> fetchTeamMembers(int teamId) async {
try {
isLoading.value = true;
final members = await _apiService.getTeamMembers(teamId);
teamMembers.assignAll(members);
teamMembers.refresh(); // 明示的に更新を通知
} catch (e) {
error.value = 'メンバーの取得に失敗しました: $e';
print('Error fetching team members: $e');
} finally {
isLoading.value = false;
}
}
Future<void> updateMember(teamId, User member) async {
try {
isLoading.value = true;
await _apiService.updateTeamMember(teamId,member.id, member.firstname, member.lastname, member.dateOfBirth, member.female);
await fetchTeamMembers(selectedTeam.value!.id);
} catch (e) {
error.value = 'メンバーの更新に失敗しました: $e';
print('Error updating member: $e');
} finally {
isLoading.value = false;
}
}
Future<void> deleteMember(int memberId, int teamId) async {
try {
isLoading.value = true;
await _apiService.deleteTeamMember(teamId,memberId);
await fetchTeamMembers(teamId);
} catch (e) {
error.value = 'メンバーの削除に失敗しました: $e';
print('Error deleting member: $e');
} finally {
isLoading.value = false;
}
}
// Future<void> addMember(User member, int teamId) async {
// try {
// isLoading.value = true;
// await _apiService.createTeamMember(teamId, member.email, member.firstname, member.lastname, member.dateOfBirth);
// await fetchTeamMembers(teamId);
// } catch (e) {
// error.value = 'メンバーの追加に失敗しました: $e';
// print('Error adding member: $e');
// } finally {
// isLoading.value = false;
// }
// }
void updateTeamName(String value) {
teamName.value = value;
}
void updateCategory(NewCategory? value) {
if (value != null) {
selectedCategory.value = value;
}
}
//void updateCategory(NewCategory? value) {
// if (value != null) {
// selectedCategory.value = categories.firstWhere(
// (category) => category.id == value.id,
// orElse: () => value,
// );
// }
//}
Future<void> saveTeam() async {
try {
isLoading.value = true;
if (selectedCategory.value == null) {
throw Exception('カテゴリを選択してください');
}
if (selectedTeam.value == null) {
await createTeam(teamName.value, selectedCategory.value!.id);
} else {
await updateTeam(selectedTeam.value!.id, teamName.value, selectedCategory.value!.id);
}
// サーバーから最新のデータを再取得
await fetchTeams();
update(); // UIを強制的に更新
} catch (e) {
error.value = 'チームの保存に失敗しました: $e';
} finally {
isLoading.value = false;
}
}
Future<void> deleteSelectedTeam() async {
if (selectedTeam.value != null) {
await deleteTeam(selectedTeam.value!.id);
selectedTeam.value = null;
}
}
List<NewCategory> getFilteredCategories_old() {
//List<User> teamMembers = getCurrentTeamMembers();
return categories.where((category) {
return isCategoryValid(category, teamMembers);
}).toList();
}
List<NewCategory> getFilteredCategories() {
if (teamMembers.isEmpty && currentUser.value != null) {
// ソロの場合
String baseCategory = currentUser.value!.female ? 'ソロ女子' : 'ソロ男子';
return categories.where((c) => c.categoryName.startsWith(baseCategory)).toList();
} else {
bool hasElementaryOrYounger = teamMembers.any(isElementarySchoolOrYounger);
String baseCategory = hasElementaryOrYounger ? 'ファミリー' : '一般';
return categories.where((c) => c.categoryName.startsWith(baseCategory)).toList();
}
}
bool isElementarySchoolOrYounger(User user) {
final now = DateTime.now();
final age = now.year - user.dateOfBirth!.year;
return age <= 12;
}
bool isCategoryValid(NewCategory category, List<User> teamMembers) {
int maleCount = teamMembers.where((member) => !member.female).length;
int femaleCount = teamMembers.where((member) => member.female).length;
int totalCount = teamMembers.length;
bool isValidGender = category.female ? (femaleCount == totalCount) : true;
bool isValidMemberCount = totalCount == category.numOfMember;
bool isValidFamily = category.family ? areAllMembersFamily(teamMembers) : true;
return isValidGender && isValidMemberCount && isValidFamily;
}
bool areAllMembersFamily(List<User> teamMembers) {
// 家族かどうかを判断するロジック(例: 同じ姓を持つメンバーが2人以上いる場合は家族とみなす
Set<String> familyNames = teamMembers.map((member) => member.lastname).toSet();
return familyNames.length < teamMembers.length;
}
Future<void> updateTeamComposition() async {
NewCategory? oldCategory = selectedCategory.value;
String? oldTime = oldCategory?.time;
// メンバーリストの最新状態を取得
await fetchTeamMembers(selectedTeam.value!.id);
List<NewCategory> eligibleCategories = [];
if (teamMembers.isEmpty || teamMembers.length == 1) {
if (currentUser.value != null) {
String baseCategory = currentUser.value!.female ? 'ソロ女子' : 'ソロ男子';
eligibleCategories = categories.where((c) => c.baseCategory == baseCategory).toList();
}
} else {
bool hasElementaryOrYounger = teamMembers.any(isElementarySchoolOrYounger);
String baseCategory = hasElementaryOrYounger ? 'ファミリー' : '一般';
eligibleCategories = categories.where((c) => c.baseCategory == baseCategory).toList();
}
// 同じ時間のカテゴリを優先的に選択
NewCategory? newCategory = eligibleCategories.firstWhereOrNull((c) => c.time == oldTime);
if (newCategory == null && eligibleCategories.isNotEmpty) {
// 同じ時間のカテゴリがない場合、最初のカテゴリを選択
newCategory = eligibleCategories.first;
// 警告メッセージを表示
Get.dialog(
AlertDialog(
title: Text('カテゴリ変更の通知'),
content: Text('旧カテゴリの時間($oldTime)と一致するカテゴリがないため、${newCategory.time ?? "時間指定なし"}を選択しました。'),
actions: [
TextButton(
child: Text('OK'),
onPressed: () => Get.back(),
),
],
),
);
}
if (newCategory != null && oldCategory != newCategory) {
selectedCategory.value = newCategory;
// チームのカテゴリを更新
if (selectedTeam.value != null) {
try {
final updatedTeam = await updateTeam(selectedTeam.value!.id, selectedTeam.value!.teamName, newCategory.id);
selectedTeam.value = updatedTeam;
// チームリストも更新
final index = teams.indexWhere((team) => team.id == updatedTeam.id);
if (index != -1) {
teams[index] = updatedTeam;
}
// エントリーの締め切りチェック
bool hasClosedEntries = await checkForClosedEntries(selectedTeam.value!.id);
if (hasClosedEntries) {
Get.dialog(
AlertDialog(
title: Text('警告'),
content: Text('締め切りを過ぎたエントリーがあります。カテゴリ変更が必要な場合は事務局にお問い合わせください。'),
actions: [
TextButton(
child: Text('OK'),
onPressed: () => Get.back(),
),
],
),
);
} else {
await checkAndHandleCategoryChange(oldCategory!, newCategory);
}
} catch (e) {
print('Error updating team category: $e');
Get.snackbar('エラー', 'チームのカテゴリ更新に失敗しました');
}
}
}
}
Future<bool> checkForClosedEntries(int teamId) async {
try {
final entries = await _apiService.getEntries();
return entries.any((entry) => !isEntryEditable(entry.event));
} catch (e) {
print('Error checking for closed entries: $e');
return false;
}
}
bool isEntryEditable(Event event) {
return DateTime.now().isBefore(event.deadlineDateTime);
}
Future<void> updateTeamComposition_old() async {
NewCategory? oldCategory = selectedCategory.value;
String? oldTime = oldCategory?.time;
// メンバーリストの最新状態を取得
await fetchTeamMembers(selectedTeam.value!.id);
List<NewCategory> eligibleCategories = [];
if (teamMembers.isEmpty) {
if (currentUser.value != null) {
String baseCategory = currentUser.value!.female ? 'ソロ女子' : 'ソロ男子';
eligibleCategories = categories.where((c) => c.baseCategory == baseCategory).toList();
}
} else {
bool hasElementaryOrYounger = teamMembers.any(isElementarySchoolOrYounger);
String baseCategory = hasElementaryOrYounger ? 'ファミリー' : '一般';
eligibleCategories = categories.where((c) => c.baseCategory == baseCategory).toList();
}
// 同じ時間のカテゴリを優先的に選択
NewCategory? newCategory = eligibleCategories.firstWhereOrNull((c) => c.time == oldTime);
if (newCategory == null && eligibleCategories.isNotEmpty) {
// 同じ時間のカテゴリがない場合、最初のカテゴリを選択
newCategory = eligibleCategories.first;
// 警告メッセージを表示
Get.dialog(
AlertDialog(
title: Text('カテゴリ変更の通知'),
content: Text('旧カテゴリの時間($oldTime)と一致するカテゴリがないため、${newCategory.time ?? "時間指定なし"}を選択しました。'),
actions: [
TextButton(
child: Text('OK'),
onPressed: () => Get.back(),
),
],
),
);
}
if (newCategory != null && oldCategory != newCategory) {
selectedCategory.value = newCategory;
// チームのカテゴリを更新
if (selectedTeam.value != null) {
try {
final updatedTeam = await updateTeam(selectedTeam.value!.id, selectedTeam.value!.teamName, newCategory.id);
selectedTeam.value = updatedTeam;
// チームリストも更新
final index = teams.indexWhere((team) => team.id == updatedTeam.id);
if (index != -1) {
teams[index] = updatedTeam;
}
} catch (e) {
print('Error updating team category: $e');
Get.snackbar('エラー', 'チームのカテゴリ更新に失敗しました');
}
}
await checkAndHandleCategoryChange(oldCategory!, newCategory);
}
}
// メンバーの追加後に呼び出すメソッド
Future<void> addMember(User newMember) async {
try {
await _apiService.createTeamMember(selectedTeam.value!.id, newMember.email, newMember.firstname, newMember.lastname, newMember.dateOfBirth, newMember.female);
await updateTeamComposition();
} catch (e) {
print('Error adding member: $e');
Get.snackbar('エラー', 'メンバーの追加に失敗しました');
}
}
// メンバーの削除後に呼び出すメソッド
Future<void> removeMember(int memberId) async {
try {
await _apiService.deleteTeamMember(selectedTeam.value!.id, memberId);
// selectedTeamからメンバーを削除
if (selectedTeam.value != null) {
selectedTeam.value!.members.removeWhere((member) => member.id == memberId);
selectedTeam.refresh();
}
// メンバー削除後にチーム構成を更新
await updateTeamComposition();
// teamMembersを更新
await fetchTeamMembers(selectedTeam.value!.id);
} catch (e) {
print('Error removing member: $e');
Get.snackbar('エラー', 'メンバーの削除に失敗しました');
}
}
Future<void> checkAndHandleCategoryChange(NewCategory oldCategory, NewCategory newCategory) async {
try {
if (selectedTeam.value == null) {
print('No team selected');
return;
}
// エントリーの存在を確認
bool hasEntries = await checkIfTeamHasEntries(selectedTeam.value!.id);
if (hasEntries) {
bool shouldCreateNewTeam = await Get.dialog<bool>(
CategoryChangeDialog(
oldCategory: oldCategory.categoryName,
newCategory: newCategory.categoryName,
),
) ?? false;
if (shouldCreateNewTeam) {
await createNewTeamWithCurrentMembers();
} else {
await updateEntriesWithNewCategory();
}
}else{
// エントリーが存在しない場合は、カテゴリの更新のみを行う
await updateTeamCategory(newCategory);
}
} catch (e) {
print('Error in checkAndHandleCategoryChange: $e');
Get.snackbar('エラー', 'カテゴリ変更の処理中にエラーが発生しました');
}
}
Future<bool> checkIfTeamHasEntries(int teamId) async {
try {
final entries = await _apiService.getTeamEntries(teamId);
return entries.isNotEmpty;
} catch (e) {
print('Error checking if team has entries: $e');
return false;
}
}
Future<void> updateTeamCategory(NewCategory newCategory) async {
try {
if (selectedTeam.value != null) {
final updatedTeam = await updateTeam(selectedTeam.value!.id, selectedTeam.value!.teamName, newCategory.id);
selectedTeam.value = updatedTeam;
// チームリストも更新
final index = teams.indexWhere((team) => team.id == updatedTeam.id);
if (index != -1) {
teams[index] = updatedTeam;
}
Get.snackbar('成功', 'チームのカテゴリを更新しました');
}
} catch (e) {
print('Error updating team category: $e');
Get.snackbar('エラー', 'チームのカテゴリ更新に失敗しました');
}
}
Future<void> fetchTeamEntries(int teamId) async {
try {
final fetchedEntries = await _apiService.getEntries();
teamEntries.assignAll(fetchedEntries);
} catch (e) {
print('Error fetching team entries: $e');
teamEntries.clear(); // エラーが発生した場合、エントリーリストをクリア
//Get.snackbar('エラー', 'チームのエントリー取得に失敗しました');
}
}
Future<void> createNewTeamWithCurrentMembers() async {
String newTeamName = '${selectedTeam.value!.teamName}_${DateTime.now().millisecondsSinceEpoch}';
try {
Team newTeam = await _apiService.createTeam(newTeamName, selectedCategory.value!.id);
for (var member in teamMembers) {
await _apiService.createTeamMember(
newTeam.id,
member.email,
member.firstname,
member.lastname,
member.dateOfBirth,
member.female,
);
}
Get.offNamed(AppPages.TEAM_DETAIL, arguments: {'mode': 'edit', 'team': newTeam});
} catch (e) {
print('Error creating new team: $e');
Get.snackbar('エラー', '新しいチームの作成に失敗しました');
}
}
Future<void> updateEntriesWithNewCategory() async {
try {
for (var entry in teamEntries) {
//await _apiService.updateEntry(entry.id, selectedCategory.value!.id);
final updatedEntry = await _apiService.updateEntry(
entry.id,
entry.team.id,
entry.event.id,
selectedCategory.value!.id,
entry.date!,
entry.zekkenNumber,
);
}
Get.snackbar('成功', 'エントリーのカテゴリを更新しました');
} catch (e) {
print('Error updating entries: $e');
Get.snackbar('エラー', 'エントリーの更新に失敗しました');
}
}
void updateCurrentUserGender(bool isFemale) {
if (currentUser.value != null) {
currentUser.value!.female = isFemale;
updateTeamComposition();
}
}
}