b239ae3e5f
Replaces Firebase with a self-hosted PHP/MySQL API served from winded.prymsolutions.com. Includes full backend (schema, auth, events, teams, brackets, suggestions, stats, media, file upload) and updated Flutter repositories and domain models. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
109 lines
2.8 KiB
Dart
109 lines
2.8 KiB
Dart
enum SuggestionStatus { pending, reviewed, implemented }
|
|
|
|
class Suggestion {
|
|
const Suggestion({
|
|
required this.id,
|
|
required this.text,
|
|
required this.isAnonymous,
|
|
required this.submittedAt,
|
|
required this.status,
|
|
this.userId,
|
|
this.displayName,
|
|
});
|
|
|
|
final String id;
|
|
final String text;
|
|
final bool isAnonymous;
|
|
final String? userId;
|
|
final String? displayName;
|
|
final DateTime submittedAt;
|
|
final SuggestionStatus status;
|
|
|
|
Suggestion copyWith({
|
|
String? id,
|
|
String? text,
|
|
bool? isAnonymous,
|
|
String? userId,
|
|
String? displayName,
|
|
DateTime? submittedAt,
|
|
SuggestionStatus? status,
|
|
}) {
|
|
return Suggestion(
|
|
id: id ?? this.id,
|
|
text: text ?? this.text,
|
|
isAnonymous: isAnonymous ?? this.isAnonymous,
|
|
userId: userId ?? this.userId,
|
|
displayName: displayName ?? this.displayName,
|
|
submittedAt: submittedAt ?? this.submittedAt,
|
|
status: status ?? this.status,
|
|
);
|
|
}
|
|
|
|
factory Suggestion.fromJson(Map<String, dynamic> data) {
|
|
return Suggestion(
|
|
id: (data['id'] as String?) ?? '',
|
|
text: (data['text'] as String?) ?? '',
|
|
isAnonymous: _parseBool(data['is_anonymous']),
|
|
userId: data['user_id'] as String?,
|
|
displayName: data['display_name'] as String?,
|
|
submittedAt: _parseDate(data['submitted_at']) ?? DateTime.now(),
|
|
status: _parseStatus(data['status'] as String?),
|
|
);
|
|
}
|
|
|
|
Map<String, Object?> toJson() {
|
|
return <String, Object?>{
|
|
'text': text,
|
|
'is_anonymous': isAnonymous,
|
|
'user_id': isAnonymous ? null : userId,
|
|
'display_name': isAnonymous ? null : displayName,
|
|
'status': status.name,
|
|
};
|
|
}
|
|
|
|
static DateTime? _parseDate(Object? v) {
|
|
if (v is String && v.isNotEmpty) return DateTime.tryParse(v);
|
|
return null;
|
|
}
|
|
|
|
static bool _parseBool(Object? v) {
|
|
if (v is bool) return v;
|
|
if (v is int) return v != 0;
|
|
if (v is String) return v == '1' || v.toLowerCase() == 'true';
|
|
return false;
|
|
}
|
|
|
|
static SuggestionStatus _parseStatus(String? raw) {
|
|
switch (raw) {
|
|
case 'reviewed':
|
|
return SuggestionStatus.reviewed;
|
|
case 'implemented':
|
|
return SuggestionStatus.implemented;
|
|
default:
|
|
return SuggestionStatus.pending;
|
|
}
|
|
}
|
|
|
|
@override
|
|
bool operator ==(Object other) {
|
|
if (identical(this, other)) return true;
|
|
return other is Suggestion &&
|
|
other.id == id &&
|
|
other.text == text &&
|
|
other.isAnonymous == isAnonymous &&
|
|
other.userId == userId &&
|
|
other.displayName == displayName &&
|
|
other.submittedAt == submittedAt &&
|
|
other.status == status;
|
|
}
|
|
|
|
@override
|
|
int get hashCode => Object.hash(
|
|
id, text, isAnonymous, userId, displayName, submittedAt, status,
|
|
);
|
|
|
|
@override
|
|
String toString() =>
|
|
'Suggestion(id: $id, status: ${status.name}, anonymous: $isAnonymous)';
|
|
}
|