Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mobile: Prepare demo app POC with hardcoded data #960

Merged
merged 18 commits into from
Jan 28, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 10 additions & 6 deletions recipients_app/lib/core/cubits/auth/auth_cubit.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,14 @@ class AuthCubit extends Cubit<AuthState> {
if (user != null) {
try {
final recipient = await userRepository.fetchRecipient(user);
final Organization? organization = await _fetchOrganization(recipient);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can always just write
final organization = await ....;
instead of
final Organization? organization = await ....;

Type will be assigned automatically. Just FYI :D


emit(
AuthState(
status: AuthStatus.authenticated,
firebaseUser: user,
recipient: recipient,
organization: organization,
),
);
} on Exception catch (ex, stackTrace) {
Expand Down Expand Up @@ -56,12 +58,7 @@ class AuthCubit extends Cubit<AuthState> {

if (user != null) {
final recipient = await userRepository.fetchRecipient(user);
Organization? organization;

if (recipient?.organizationRef != null) {
organization = await organizationRepository
.fetchOrganization(recipient!.organizationRef!);
}
final Organization? organization = await _fetchOrganization(recipient);

emit(
AuthState(
Expand Down Expand Up @@ -104,4 +101,11 @@ class AuthCubit extends Cubit<AuthState> {
await userRepository.signOut();
emit(const AuthState());
}

Future<Organization?> _fetchOrganization(Recipient? recipient) async {
if (recipient?.organizationRef != null) {
return await organizationRepository.fetchOrganization(recipient!.organizationRef!);
}
return null;
}
}
4 changes: 3 additions & 1 deletion recipients_app/lib/core/cubits/auth/auth_state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,19 +26,21 @@ class AuthState extends Equatable {
});

@override
List<Object?> get props => [status, firebaseUser, recipient, exception];
List<Object?> get props => [status, firebaseUser, recipient, exception, organization];

AuthState copyWith({
AuthStatus? status,
User? firebaseUser,
Recipient? recipient,
Exception? exception,
Organization? organization,
}) {
return AuthState(
status: status ?? this.status,
firebaseUser: firebaseUser ?? this.firebaseUser,
recipient: recipient ?? this.recipient,
exception: exception ?? this.exception,
organization: organization ?? this.organization,
);
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import "dart:async";

import "package:app/core/cubits/auth/auth_cubit.dart";
import "package:app/data/repositories/repositories.dart";
import "package:app/view/widgets/account/dashboard_card.dart";
Expand All @@ -9,16 +11,23 @@ part "dashboard_card_manager_state.dart";
class DashboardCardManagerCubit extends Cubit<DashboardCardManagerState> {
final AuthCubit authCubit;
final CrashReportingRepository crashReportingRepository;
late StreamSubscription<AuthState> authSubscription;

DashboardCardManagerCubit({
required this.authCubit,
required this.crashReportingRepository,
}) : super(const DashboardCardManagerState()) {
authCubit.stream.listen((event) {
authSubscription = authCubit.stream.listen((event) {
fetchCards();
});
}

@override
Future<void> close() async {
authSubscription.cancel();
super.close();
}

Future<void> fetchCards() async {
emit(state.copyWith(status: DashboardCardManagerStatus.loading));
final recipient = authCubit.state.recipient;
Expand All @@ -29,7 +38,6 @@ class DashboardCardManagerCubit extends Cubit<DashboardCardManagerState> {

try {
// TODO: currently payment phone number is used for login, we need to switch that

final paymentPhoneNumber = recipient.mobileMoneyPhone;
final contactPhoneNumber = recipient.communicationMobilePhone;

Expand Down
149 changes: 149 additions & 0 deletions recipients_app/lib/data/datasource/demo/demo_user.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
import "package:firebase_auth/firebase_auth.dart";

class DemoUser implements User {
@override
String? get displayName => "demo user";

@override
String? get email => null;

@override
bool get emailVerified => true;

@override
Future<String?> getIdToken([bool forceRefresh = false]) {
throw UnimplementedError();
}

@override
Future<void> delete() {
throw UnimplementedError();
}

@override
Future<IdTokenResult> getIdTokenResult([bool forceRefresh = false]) {
throw UnimplementedError();
}

@override
bool get isAnonymous => throw UnimplementedError();

@override
Future<UserCredential> linkWithCredential(AuthCredential credential) {
throw UnimplementedError();
}

@override
Future<ConfirmationResult> linkWithPhoneNumber(String phoneNumber, [RecaptchaVerifier? verifier]) {
throw UnimplementedError();
}

@override
Future<UserCredential> linkWithPopup(AuthProvider provider) {
throw UnimplementedError();
}

@override
Future<UserCredential> linkWithProvider(AuthProvider provider) {
throw UnimplementedError();
}

@override
Future<void> linkWithRedirect(AuthProvider provider) {
throw UnimplementedError();
}

@override
UserMetadata get metadata => throw UnimplementedError();

@override
MultiFactor get multiFactor => throw UnimplementedError();

@override
String? get phoneNumber => throw UnimplementedError();

@override
String? get photoURL => throw UnimplementedError();

@override
List<UserInfo> get providerData => throw UnimplementedError();

@override
Future<UserCredential> reauthenticateWithCredential(AuthCredential credential) {
throw UnimplementedError();
}

@override
Future<UserCredential> reauthenticateWithPopup(AuthProvider provider) {
throw UnimplementedError();
}

@override
Future<UserCredential> reauthenticateWithProvider(AuthProvider provider) {
throw UnimplementedError();
}

@override
Future<void> reauthenticateWithRedirect(AuthProvider provider) {
throw UnimplementedError();
}

@override
String? get refreshToken => throw UnimplementedError();

@override
Future<void> reload() {
throw UnimplementedError();
}

@override
Future<void> sendEmailVerification([ActionCodeSettings? actionCodeSettings]) {
throw UnimplementedError();
}

@override
String? get tenantId => throw UnimplementedError();

@override
String get uid => throw UnimplementedError();
KarinBerg marked this conversation as resolved.
Show resolved Hide resolved

@override
Future<User> unlink(String providerId) {
throw UnimplementedError();
}

@override
Future<void> updateDisplayName(String? displayName) {
throw UnimplementedError();
}

@override
Future<void> updateEmail(String newEmail) {
throw UnimplementedError();
}

@override
Future<void> updatePassword(String newPassword) {
throw UnimplementedError();
}

@override
Future<void> updatePhoneNumber(PhoneAuthCredential phoneCredential) {
throw UnimplementedError();
}

@override
Future<void> updatePhotoURL(String? photoURL) {
throw UnimplementedError();
}

@override
Future<void> updateProfile({String? displayName, String? photoURL}) {
throw UnimplementedError();
}

@override
Future<void> verifyBeforeUpdateEmail(String newEmail, [ActionCodeSettings? actionCodeSettings]) {
throw UnimplementedError();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import "package:cloud_firestore/cloud_firestore.dart";

// We are using DocumentReference in repository / data source. That's why we need to get
// no-op implementation for it for demo data source.

// ignore: subtype_of_sealed_class
class NoOpDocumentReference implements DocumentReference<Map<String, dynamic>> {
const NoOpDocumentReference();

@override
CollectionReference<Map<String, dynamic>> collection(String collectionPath) {
throw UnimplementedError();
}

@override
Future<void> delete() {
throw UnimplementedError();
}

@override
FirebaseFirestore get firestore => throw UnimplementedError();

@override
Future<DocumentSnapshot<Map<String, dynamic>>> get([GetOptions? options]) {
throw UnimplementedError();
}

@override
String get id => throw UnimplementedError();

@override
CollectionReference<Map<String, dynamic>> get parent => throw UnimplementedError();

@override
String get path => throw UnimplementedError();

@override
Future<void> set(Map<String, dynamic> data, [SetOptions? options]) {
throw UnimplementedError();
}

@override
Stream<DocumentSnapshot<Map<String, dynamic>>> snapshots(
{bool includeMetadataChanges = false, ListenSource source = ListenSource.defaultSource,}) {
throw UnimplementedError();
}

@override
Future<void> update(Map<Object, Object?> data) {
throw UnimplementedError();
}

@override
DocumentReference<R> withConverter<R>(
{required FromFirestore<R> fromFirestore, required ToFirestore<R> toFirestore,}) {
throw UnimplementedError();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import "package:app/data/datasource/organization_data_source.dart";
import "package:app/data/models/models.dart";
import "package:cloud_firestore/cloud_firestore.dart";

class OrganizationDemoDataSource implements OrganizationDataSource {
final Organization _organization = _generateOrganization();

static Organization _generateOrganization() {
return const Organization(name: "Demo organization", contactName: "Demo manager", contactNumber: "+232 123456789");
}

@override
Future<Organization?> fetchOrganization(DocumentReference<Object?> organizationRef) async {
return _organization;
}
Comment on lines +13 to +15
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add error simulation capabilities

The demo implementation should simulate real-world scenarios, including error cases.

   @override
   Future<Organization?> fetchOrganization(DocumentReference<Object?> organizationRef) async {
+    // Simulate network delay
+    await Future.delayed(const Duration(milliseconds: 500));
+    
+    // Simulate errors for specific refs (optional)
+    if (organizationRef.id == 'error_case') {
+      throw FirebaseException(plugin: 'demo', message: 'Simulated error');
+    }
+    
     return _organization;
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Future<Organization?> fetchOrganization(DocumentReference<Object?> organizationRef) async {
return _organization;
}
Future<Organization?> fetchOrganization(DocumentReference<Object?> organizationRef) async {
// Simulate network delay
await Future.delayed(const Duration(milliseconds: 500));
// Simulate errors for specific refs (optional)
if (organizationRef.id == 'error_case') {
throw FirebaseException(plugin: 'demo', message: 'Simulated error');
}
return _organization;
}

}
Loading
Loading