From c45bb22971b2975c4eab7be412b84c9a17cbccdb Mon Sep 17 00:00:00 2001 From: Dani B Date: Wed, 28 Jan 2026 09:09:50 -0500 Subject: [PATCH] feat(01-02): create AuthUser data model - AuthUser class wraps Supabase User for clean architecture - Includes fromSupabase() factory constructor for conversion - Provides copyWith() method for immutable updates - Contains essential fields: id, email, created_at, email_verified - Optional fields: display_name, avatar_url, last_sign_in_at - Proper null safety and equality operators implemented --- .../authentication/data/models/auth_user.dart | 110 ++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 lib/features/authentication/data/models/auth_user.dart diff --git a/lib/features/authentication/data/models/auth_user.dart b/lib/features/authentication/data/models/auth_user.dart new file mode 100644 index 0000000..f8afe0a --- /dev/null +++ b/lib/features/authentication/data/models/auth_user.dart @@ -0,0 +1,110 @@ +import 'package:supabase_flutter/supabase_flutter.dart'; + +/// AuthUser data model representing a user in the authentication system. +/// +/// This model provides a clean abstraction over Supabase's User model, +/// following clean architecture principles for the data layer. +class AuthUser { + /// Unique identifier for the user + final String id; + + /// User's email address + final String email; + + /// Timestamp when the user account was created + final DateTime createdAt; + + /// Whether the user's email has been verified + final bool emailVerified; + + /// User's display name (optional) + final String? displayName; + + /// User's avatar URL (optional) + final String? avatarUrl; + + /// Timestamp when the user was last seen + final DateTime? lastSignInAt; + + /// Creates a new AuthUser instance + const AuthUser({ + required this.id, + required this.email, + required this.createdAt, + required this.emailVerified, + this.displayName, + this.avatarUrl, + this.lastSignInAt, + }); + + /// Creates an AuthUser from a Supabase User object + /// + /// [user] - The Supabase User object to convert + /// Returns an AuthUser with mapped fields + factory AuthUser.fromSupabase(User user) { + return AuthUser( + id: user.id, + email: user.email ?? '', + createdAt: user.createdAt ?? DateTime.now(), + emailVerified: user.emailConfirmedAt != null, + displayName: user.userMetadata?['display_name'] as String?, + avatarUrl: user.userMetadata?['avatar_url'] as String?, + lastSignInAt: user.lastSignInAt, + ); + } + + /// Creates a copy of this AuthUser with updated values + /// + /// Allows for immutable updates to user data + AuthUser copyWith({ + String? id, + String? email, + DateTime? createdAt, + bool? emailVerified, + String? displayName, + String? avatarUrl, + DateTime? lastSignInAt, + }) { + return AuthUser( + id: id ?? this.id, + email: email ?? this.email, + createdAt: createdAt ?? this.createdAt, + emailVerified: emailVerified ?? this.emailVerified, + displayName: displayName ?? this.displayName, + avatarUrl: avatarUrl ?? this.avatarUrl, + lastSignInAt: lastSignInAt ?? this.lastSignInAt, + ); + } + + /// Returns a string representation of the user for debugging + @override + String toString() { + return 'AuthUser(id: $id, email: $email, emailVerified: $emailVerified, displayName: $displayName)'; + } + + /// Returns true if the user is considered authenticated + /// + /// A user is authenticated if they have a valid ID and email + bool get isAuthenticated => id.isNotEmpty && email.isNotEmpty; + + /// Returns true if the user's email is verified + bool get isEmailVerified => emailVerified; + + /// Equality operator for comparing AuthUser objects + @override + bool operator ==(Object other) { + if (identical(this, other)) return true; + return other is AuthUser && + other.id == id && + other.email == email && + other.emailVerified == emailVerified; + } + + /// Hash code for AuthUser objects + @override + int get hashCode { + return id.hashCode ^ + email.hashCode ^ + emailVerified.hashCode; + } +} \ No newline at end of file