// lib/entry/entry_controller.dart import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:gifunavi/model/entry.dart'; import 'package:gifunavi/model/event.dart'; import 'package:gifunavi/model/team.dart'; import 'package:gifunavi/model/category.dart'; import 'package:gifunavi/services/api_service.dart'; import '../index/index_controller.dart'; import 'package:timezone/timezone.dart' as tz; class EntryController extends GetxController { late ApiService _apiService; final entries = [].obs; final events = [].obs; final teams = [].obs; final categories = [].obs; final selectedEvent = Rx(null); final selectedTeam = Rx(null); final selectedCategory = Rx(null); final selectedDate = Rx(null); final currentEntry = Rx(null); final isLoading = true.obs; final activeEvents = [].obs; //有効なイベントリスト @override void onInit() async { super.onInit(); await initializeApiService(); await loadInitialData(); } Future initializeApiService() async { try { _apiService = await Get.putAsync(() => ApiService().init()); } catch (e) { print('Error initializing ApiService: $e'); Get.snackbar('Error', 'Failed to initialize API service'); } } Future loadInitialData() async { try { isLoading.value = true; await Future.wait([ fetchEntries(), fetchEvents(), fetchTeams(), fetchCategories(), ]); updateActiveEvents(); // イベント取得後にアクティブなイベントを更新 if (Get.arguments != null && Get.arguments['entry'] != null) { currentEntry.value = Get.arguments['entry']; initializeEditMode(currentEntry.value!); } else { // 新規作成モードの場合、最初のイベントを選択 if (events.isNotEmpty) { selectedEvent.value = activeEvents.first; selectedDate.value = activeEvents.first.startDatetime; } } } catch(e) { print('Error initializing data: $e'); Get.snackbar('Error', 'Failed to load initial data'); } finally { isLoading.value = false; } } void updateActiveEvents() { final now = tz.TZDateTime.now(tz.getLocation('Asia/Tokyo')); activeEvents.assignAll(events.where((event) => event.deadlineDateTime.isAfter(now))); } void initializeEditMode(Entry entry) { currentEntry.value = entry; selectedEvent.value = entry.event; selectedTeam.value = entry.team; selectedCategory.value = entry.category; selectedDate.value = entry.date; } void updateEvent(Event? value) { selectedEvent.value = value; if (value != null) { // イベント変更時に日付を調整 if (selectedDate.value == null || selectedDate.value!.isBefore(value.startDatetime) || selectedDate.value!.isAfter(value.endDatetime)) { selectedDate.value = value.startDatetime; } } } void updateTeam(Team? value) { selectedTeam.value = value; if (value != null) { selectedCategory.value = value.category; } } //void updateTeam(Team? value) => selectedTeam.value = value; void updateCategory(NewCategory? value) => selectedCategory.value = value; //void updateDate(DateTime value) => selectedDate.value = value; void updateDate(DateTime value) { selectedDate.value = tz.TZDateTime.from(value, tz.getLocation('Asia/Tokyo')); } /* void updateDate(DateTime value){ selectedDate.value = DateFormat('yyyy-MM-dd').format(value!) as DateTime?; } */ void _initializeEntryData() { if (currentEntry.value != null) { selectedEvent.value = currentEntry.value!.event; selectedTeam.value = currentEntry.value!.team; selectedCategory.value = currentEntry.value!.category; selectedDate.value = currentEntry.value!.date; } } Future fetchEntries() async { try { final fetchedEntries = await _apiService.getEntries(); entries.assignAll(fetchedEntries); } catch (e) { print('Error fetching entries: $e'); Get.snackbar('Error', 'Failed to fetch entries'); } } Future fetchEvents() async { try { final fetchedEvents = await _apiService.getEvents(); events.assignAll(fetchedEvents.map((event) { // end_dateの7日前を締め切りとして設定 final deadlineDateTime = event.endDatetime.subtract(const Duration(days: 7)); return Event( id: event.id, eventName: event.eventName, startDatetime: event.startDatetime, endDatetime: event.endDatetime, deadlineDateTime: deadlineDateTime, ); }).toList()); updateActiveEvents(); } catch (e) { print('Error fetching events: $e'); Get.snackbar('Error', 'Failed to fetch events'); } } Future fetchEvents_old() async { try { final fetchedEvents = await _apiService.getEvents(); events.assignAll(fetchedEvents); } catch (e) { print('Error fetching events: $e'); Get.snackbar('Error', 'Failed to fetch events'); } } Future fetchTeams() async { try { final fetchedTeams = await _apiService.getTeams(); teams.assignAll(fetchedTeams); } catch (e) { print('Error fetching teams: $e'); Get.snackbar('Error', 'Failed to fetch team'); } } Future fetchCategories() async { try { final fetchedCategories = await _apiService.getCategories(); categories.assignAll(fetchedCategories); } catch (e) { print('Error fetching categories: $e'); Get.snackbar('Error', 'Failed to fetch categories'); } } Future createEntry() async { if (selectedEvent.value == null || selectedTeam.value == null || selectedCategory.value == null || selectedDate.value == null) { Get.snackbar('Error', 'Please fill all fields'); return; } try { isLoading.value = true; // Get zekken number final updatedCategory = await _apiService.getZekkenNumber(selectedCategory.value!.id); final zekkenNumber = updatedCategory.categoryNumber.toString(); // selectedDate.value に 9時間を加えてJSTのオフセットを適用 final jstDate = selectedDate.value!.add(const Duration(hours: 9)); final newEntry = await _apiService.createEntry( selectedTeam.value!.id, selectedEvent.value!.id, selectedCategory.value!.id, jstDate, // JSTオフセットが適用された日付を使用 zekkenNumber, ); entries.add(newEntry); Get.back(); } catch (e) { print('Error creating entry: $e'); Get.snackbar('Error', '$e'); } finally { isLoading.value = false; } } Future updateEntryAndRefreshMap() async { await updateEntry(); // エントリーが正常に更新された後、マップをリフレッシュ final indexController = Get.find(); final eventCode = currentEntry.value?.event.eventName ?? ''; indexController.reloadMap(eventCode); } bool isEntryEditable(Event event) { return DateTime.now().isBefore(event.deadlineDateTime); } Future updateEntry() async { if (currentEntry.value == null) { Get.snackbar('Error', 'No entry selected for update'); return; } if (!isEntryEditable(currentEntry.value!.event)) { Get.dialog( AlertDialog( title: Text('エントリー変更不可'), content: Text('締め切りを過ぎているため、エントリーの変更はできません。変更が必要な場合は事務局にお問い合わせください。'), actions: [ TextButton( child: Text('OK'), onPressed: () => Get.back(), ), ], ), ); return; } try { isLoading.value = true; final updatedEntry = await _apiService.updateEntry( currentEntry.value!.id, currentEntry.value!.team.id, selectedEvent.value!.id, selectedCategory.value!.id, selectedDate.value!, currentEntry.value!.zekkenNumber, ); final index = entries.indexWhere((entry) => entry.id == updatedEntry.id); if (index != -1) { entries[index] = updatedEntry; } Get.back(); } catch (e) { print('Error updating entry: $e'); Get.snackbar('Error', 'Failed to update entry'); } finally { isLoading.value = false; } } Future updateEntryCategory(int entryId, int newCategoryId) async { try { //await _apiService.updateEntryCategory(entryId, newCategoryId); final updatedEntry = await _apiService.updateEntry( currentEntry.value!.id, currentEntry.value!.team.id, selectedEvent.value!.id, newCategoryId, currentEntry.value!.date!, currentEntry.value!.zekkenNumber, ); await fetchEntries(); } catch (e) { print('Error updating entry category: $e'); Get.snackbar('エラー', 'エントリーのカテゴリ更新に失敗しました'); } } Future deleteEntry() async { if (currentEntry.value == null) { Get.snackbar('Error', 'No entry selected for deletion'); return; } try { isLoading.value = true; await _apiService.deleteEntry(currentEntry.value!.id); entries.removeWhere((entry) => entry.id == currentEntry.value!.id); Get.back(); } catch (e) { print('Error deleting entry: $e'); Get.snackbar('Error', 'Failed to delete entry'); } finally { isLoading.value = false; } } bool isOwner() { // Implement logic to check if the current user is the owner of the entry return true; // Placeholder } }