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 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 toJson() { return { '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)'; }