Initial commit: Flutter app + PHP/MySQL backend on Hostinger
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>
This commit is contained in:
@@ -0,0 +1,123 @@
|
||||
enum UserRole { viewer, player, manager, admin }
|
||||
|
||||
UserRole userRoleFromString(String? raw) {
|
||||
switch (raw) {
|
||||
case 'admin':
|
||||
return UserRole.admin;
|
||||
case 'manager':
|
||||
return UserRole.manager;
|
||||
case 'player':
|
||||
return UserRole.player;
|
||||
case 'viewer':
|
||||
return UserRole.viewer;
|
||||
default:
|
||||
return UserRole.player;
|
||||
}
|
||||
}
|
||||
|
||||
class UserProfile {
|
||||
const UserProfile({
|
||||
required this.uid,
|
||||
required this.email,
|
||||
required this.displayName,
|
||||
required this.role,
|
||||
this.bio = '',
|
||||
this.photoUrl,
|
||||
this.position,
|
||||
this.teamId,
|
||||
required this.createdAt,
|
||||
});
|
||||
|
||||
final String uid;
|
||||
final String email;
|
||||
final String displayName;
|
||||
final UserRole role;
|
||||
final String bio;
|
||||
final String? photoUrl;
|
||||
final String? position;
|
||||
final String? teamId;
|
||||
final DateTime createdAt;
|
||||
|
||||
bool get hasTeam => teamId != null && teamId!.isNotEmpty;
|
||||
|
||||
UserProfile copyWith({
|
||||
String? uid,
|
||||
String? email,
|
||||
String? displayName,
|
||||
UserRole? role,
|
||||
String? bio,
|
||||
String? photoUrl,
|
||||
String? position,
|
||||
String? teamId,
|
||||
DateTime? createdAt,
|
||||
}) {
|
||||
return UserProfile(
|
||||
uid: uid ?? this.uid,
|
||||
email: email ?? this.email,
|
||||
displayName: displayName ?? this.displayName,
|
||||
role: role ?? this.role,
|
||||
bio: bio ?? this.bio,
|
||||
photoUrl: photoUrl ?? this.photoUrl,
|
||||
position: position ?? this.position,
|
||||
teamId: teamId ?? this.teamId,
|
||||
createdAt: createdAt ?? this.createdAt,
|
||||
);
|
||||
}
|
||||
|
||||
UserProfile clearTeam() => copyWith(teamId: null);
|
||||
|
||||
factory UserProfile.fromJson(Map<String, dynamic> data) {
|
||||
return UserProfile(
|
||||
uid: (data['id'] as String?) ?? '',
|
||||
email: (data['email'] as String?) ?? '',
|
||||
displayName: (data['display_name'] as String?) ?? '',
|
||||
role: userRoleFromString(data['role'] as String?),
|
||||
bio: (data['bio'] as String?) ?? '',
|
||||
photoUrl: data['photo_url'] as String?,
|
||||
position: data['position'] as String?,
|
||||
teamId: data['team_id'] as String?,
|
||||
createdAt: _parseDate(data['created_at']) ?? DateTime.now(),
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, Object?> toJson() {
|
||||
return <String, Object?>{
|
||||
'email': email,
|
||||
'display_name': displayName,
|
||||
'role': role.name,
|
||||
'bio': bio,
|
||||
'photo_url': photoUrl,
|
||||
'position': position,
|
||||
'team_id': teamId,
|
||||
};
|
||||
}
|
||||
|
||||
static DateTime? _parseDate(Object? v) {
|
||||
if (v is String && v.isNotEmpty) return DateTime.tryParse(v);
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
if (identical(this, other)) return true;
|
||||
return other is UserProfile &&
|
||||
other.uid == uid &&
|
||||
other.email == email &&
|
||||
other.displayName == displayName &&
|
||||
other.role == role &&
|
||||
other.bio == bio &&
|
||||
other.photoUrl == photoUrl &&
|
||||
other.position == position &&
|
||||
other.teamId == teamId &&
|
||||
other.createdAt == createdAt;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(
|
||||
uid, email, displayName, role, bio, photoUrl, position, teamId, createdAt,
|
||||
);
|
||||
|
||||
@override
|
||||
String toString() =>
|
||||
'UserProfile(uid: $uid, role: ${role.name}, teamId: $teamId)';
|
||||
}
|
||||
Reference in New Issue
Block a user