class Participant { final String id; final String eventId; final String memberId; final String? name; final String? email; final String? phoneNumber; final String? status; // 'registered', 'confirmed', 'cancelled', 'attended' final DateTime? registeredAt; final DateTime? confirmedAt; final DateTime? cancelledAt; final DateTime? attendedAt; final bool isPaid; final double? paidAmount; final String? notes; final DateTime? createdAt; final DateTime? updatedAt; String? memberType; // 회원 유형 필드 추가: '정회원', '준회원', '게스트' 등 final String? gender; // 성별 (서버 Member.gender에서 유추) final int? handicap; // 핸디캡 (서버 Member.handicap에서 유추) final double? average; // 백엔드에서 제공하는 동적 에버리지(옵션) Participant({ required this.id, required this.eventId, required this.memberId, this.name, this.email, this.phoneNumber, this.status, this.registeredAt, this.confirmedAt, this.cancelledAt, this.attendedAt, this.isPaid = false, this.paidAmount, this.notes, this.createdAt, this.updatedAt, this.gender, this.handicap, this.average, }); Participant copyWith({ String? id, String? eventId, String? memberId, String? name, String? email, String? phoneNumber, String? status, DateTime? registeredAt, DateTime? confirmedAt, DateTime? cancelledAt, DateTime? attendedAt, bool? isPaid, double? paidAmount, String? notes, DateTime? createdAt, DateTime? updatedAt, String? gender, int? handicap, double? average, String? memberType, }) { return Participant( id: id ?? this.id, eventId: eventId ?? this.eventId, memberId: memberId ?? this.memberId, name: name ?? this.name, email: email ?? this.email, phoneNumber: phoneNumber ?? this.phoneNumber, status: status ?? this.status, registeredAt: registeredAt ?? this.registeredAt, confirmedAt: confirmedAt ?? this.confirmedAt, cancelledAt: cancelledAt ?? this.cancelledAt, attendedAt: attendedAt ?? this.attendedAt, isPaid: isPaid ?? this.isPaid, paidAmount: paidAmount ?? this.paidAmount, notes: notes ?? this.notes, createdAt: createdAt ?? this.createdAt, updatedAt: updatedAt ?? this.updatedAt, gender: gender ?? this.gender, handicap: handicap ?? this.handicap, average: average ?? this.average, // preserve mutable memberType even though not in ctor params order earlier )..memberType = memberType ?? this.memberType; } // JSON 데이터로부터 Participant 객체 생성 factory Participant.fromJson(Map json) { final p = Participant( id: json['id']?.toString() ?? '', eventId: json['eventId']?.toString() ?? '', memberId: json['memberId']?.toString() ?? '', // 서버 응답에 Member가 중첩되는 경우 보정 name: (json['name'] ?? json['Member']?['name'])?.toString(), email: (json['email'] ?? json['Member']?['email'])?.toString(), phoneNumber: (json['phoneNumber'] ?? json['phone'] ?? json['Member']?['phone'])?.toString(), status: json['status']?.toString(), registeredAt: json['registeredAt'] != null ? DateTime.parse(json['registeredAt'].toString()) : null, confirmedAt: json['confirmedAt'] != null ? DateTime.parse(json['confirmedAt'].toString()) : null, cancelledAt: json['cancelledAt'] != null ? DateTime.parse(json['cancelledAt'].toString()) : null, attendedAt: json['attendedAt'] != null ? DateTime.parse(json['attendedAt'].toString()) : null, // 서버는 paymentStatus('paid'|'unpaid')를 줄 수 있으므로 이를 isPaid로 변환 isPaid: json['isPaid'] ?? (json['paymentStatus']?.toString().toLowerCase() == 'paid'), paidAmount: json['paidAmount'] != null ? double.tryParse(json['paidAmount'].toString()) : null, notes: (json['notes'] ?? json['comment'])?.toString(), createdAt: json['createdAt'] != null ? DateTime.parse(json['createdAt'].toString()) : null, updatedAt: json['updatedAt'] != null ? DateTime.parse(json['updatedAt'].toString()) : null, gender: (json['gender'] ?? json['Member']?['gender'])?.toString(), handicap: () { final val = json['handicap'] ?? json['Member']?['handicap']; if (val == null) return null; if (val is num) return val.toInt(); return int.tryParse(val.toString()); }(), average: () { final val = json['average'] ?? json['Member']?['average']; if (val == null) return null; if (val is num) return val.toDouble(); return double.tryParse(val.toString()); }(), ); // 회원 유형은 원시 enum 값을 유지하고, 표시 단계에서 매핑 final rawType = (json['memberType'] ?? json['Member']?['memberType'])?.toString(); if (rawType != null && rawType.isNotEmpty) { p.memberType = rawType; } return p; } // Participant 객체를 JSON으로 변환 Map toJson() { return { 'id': id, 'eventId': eventId, 'memberId': memberId, 'name': name, 'email': email, 'phoneNumber': phoneNumber, 'status': status, 'registeredAt': registeredAt?.toIso8601String(), 'confirmedAt': confirmedAt?.toIso8601String(), 'cancelledAt': cancelledAt?.toIso8601String(), 'attendedAt': attendedAt?.toIso8601String(), 'isPaid': isPaid, 'paidAmount': paidAmount, 'notes': notes, 'comment': notes, 'createdAt': createdAt?.toIso8601String(), 'updatedAt': updatedAt?.toIso8601String(), 'gender': gender, 'handicap': handicap, 'average': average, }; } }