Files
bowlingManager/mobile/lib/screens/club/participant_form_screen.dart
T
2025-08-09 03:09:17 +09:00

309 lines
11 KiB
Dart

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:intl/intl.dart';
import '../../models/participant_model.dart';
import '../../services/event_service.dart';
import '../../widgets/loading_indicator.dart';
class ParticipantFormScreen extends StatefulWidget {
final String eventId;
final Participant? participant; // null이면 새 참가자 추가, 아니면 참가자 수정
const ParticipantFormScreen({
Key? key,
required this.eventId,
this.participant,
}) : super(key: key);
@override
State<ParticipantFormScreen> createState() => _ParticipantFormScreenState();
}
class _ParticipantFormScreenState extends State<ParticipantFormScreen> {
final _formKey = GlobalKey<FormState>();
bool _isLoading = false;
// 폼 필드 컨트롤러
final _nameController = TextEditingController();
final _emailController = TextEditingController();
final _phoneNumberController = TextEditingController();
final _notesController = TextEditingController();
final _paidAmountController = TextEditingController();
// 참가자 데이터
String? _status;
bool _isPaid = false;
// 참가자 상태 옵션
final List<String> _statusOptions = ['등록됨', '확인됨', '취소됨', '참석함'];
@override
void initState() {
super.initState();
// 수정 모드인 경우 기존 데이터 로드
if (widget.participant != null) {
_nameController.text = widget.participant!.name ?? '';
_emailController.text = widget.participant!.email ?? '';
_phoneNumberController.text = widget.participant!.phoneNumber ?? '';
_notesController.text = widget.participant!.notes ?? '';
_paidAmountController.text = widget.participant!.paidAmount?.toString() ?? '';
_status = widget.participant!.status;
_isPaid = widget.participant!.isPaid;
} else {
// 새 참가자 추가 시 기본값 설정
_status = _statusOptions[0];
_isPaid = false;
}
}
@override
void dispose() {
_nameController.dispose();
_emailController.dispose();
_phoneNumberController.dispose();
_notesController.dispose();
_paidAmountController.dispose();
super.dispose();
}
// 참가자 저장
Future<void> _saveParticipant() async {
if (!_formKey.currentState!.validate()) {
return;
}
setState(() {
_isLoading = true;
});
try {
final eventService = Provider.of<EventService>(context, listen: false);
// 참가자 데이터 준비
final participantData = {
'eventId': widget.eventId,
'name': _nameController.text.trim(),
'email': _emailController.text.trim().isEmpty ? null : _emailController.text.trim(),
'phoneNumber': _phoneNumberController.text.trim().isEmpty ? null : _phoneNumberController.text.trim(),
'status': _status,
'isPaid': _isPaid,
'paidAmount': _paidAmountController.text.isEmpty ? null : double.parse(_paidAmountController.text),
'notes': _notesController.text.trim().isEmpty ? null : _notesController.text.trim(),
};
if (widget.participant == null) {
// 새 참가자 추가
await eventService.addParticipant(widget.eventId, participantData);
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('참가자가 추가되었습니다')),
);
}
} else {
// 기존 참가자 수정
await eventService.updateParticipant(widget.eventId, widget.participant!.id, participantData);
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('참가자 정보가 수정되었습니다')),
);
}
}
if (mounted) {
Navigator.of(context).pop(true); // 성공 결과와 함께 이전 화면으로 돌아가기
}
} catch (e) {
if (mounted) {
setState(() {
_isLoading = false;
});
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('참가자 저장에 실패했습니다: $e')),
);
}
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.participant == null ? '참가자 추가' : '참가자 수정'),
actions: [
IconButton(
icon: const Icon(Icons.save),
onPressed: _saveParticipant,
),
],
),
body: _isLoading
? const LoadingIndicator()
: SingleChildScrollView(
padding: const EdgeInsets.all(16.0),
child: Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 기본 정보 섹션
_buildSectionTitle('기본 정보'),
// 이름
TextFormField(
controller: _nameController,
decoration: const InputDecoration(
labelText: '이름 *',
hintText: '참가자 이름을 입력하세요',
),
validator: (value) {
if (value == null || value.trim().isEmpty) {
return '참가자 이름을 입력해주세요';
}
return null;
},
),
const SizedBox(height: 16),
// 이메일
TextFormField(
controller: _emailController,
decoration: const InputDecoration(
labelText: '이메일',
hintText: '참가자 이메일을 입력하세요',
),
keyboardType: TextInputType.emailAddress,
validator: (value) {
if (value != null && value.isNotEmpty) {
// 간단한 이메일 형식 검증
if (!value.contains('@') || !value.contains('.')) {
return '유효한 이메일 주소를 입력해주세요';
}
}
return null;
},
),
const SizedBox(height: 16),
// 전화번호
TextFormField(
controller: _phoneNumberController,
decoration: const InputDecoration(
labelText: '전화번호',
hintText: '참가자 전화번호를 입력하세요',
),
keyboardType: TextInputType.phone,
),
const SizedBox(height: 24),
// 상태 섹션
_buildSectionTitle('상태 정보'),
// 참가자 상태
DropdownButtonFormField<String>(
value: _status,
decoration: const InputDecoration(
labelText: '참가자 상태',
),
items: _statusOptions.map((status) {
return DropdownMenuItem(
value: status,
child: Text(status),
);
}).toList(),
onChanged: (value) {
setState(() {
_status = value;
});
},
),
const SizedBox(height: 16),
// 결제 여부
SwitchListTile(
title: const Text('결제 완료'),
value: _isPaid,
onChanged: (value) {
setState(() {
_isPaid = value;
});
},
),
// 결제 금액
TextFormField(
controller: _paidAmountController,
decoration: const InputDecoration(
labelText: '결제 금액',
hintText: '결제 금액을 입력하세요',
suffixText: '원',
),
keyboardType: TextInputType.number,
validator: (value) {
if (value != null && value.isNotEmpty) {
if (double.tryParse(value) == null) {
return '숫자를 입력해주세요';
}
}
return null;
},
),
const SizedBox(height: 24),
// 메모 섹션
_buildSectionTitle('추가 정보'),
// 메모
TextFormField(
controller: _notesController,
decoration: const InputDecoration(
labelText: '메모',
hintText: '참가자에 대한 메모를 입력하세요',
),
maxLines: 3,
),
const SizedBox(height: 32),
// 저장 버튼
SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: _saveParticipant,
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(vertical: 16),
),
child: Text(
widget.participant == null ? '참가자 추가' : '참가자 정보 수정',
style: const TextStyle(fontSize: 16),
),
),
),
],
),
),
),
);
}
// 섹션 제목 위젯
Widget _buildSectionTitle(String title) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
const Divider(),
const SizedBox(height: 8),
],
);
}
}