Skip to content

Commit

Permalink
Feature/upgrade segment (#176)
Browse files Browse the repository at this point in the history
* using different segment

* WIP

* WIP

* rename jobs events

* update successCallback on loginRequestCall

* minor

* minor

* revert verify auto login

* Wip

* add auto routes generator & fix login flow

* last fixes

* fixed

Co-authored-by: Tal Beja <bejavu@gmail.com>
  • Loading branch information
bejavu and bejavu authored Mar 5, 2020
1 parent 4737ab5 commit 124e114
Show file tree
Hide file tree
Showing 53 changed files with 756 additions and 390 deletions.
1 change: 1 addition & 0 deletions android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
<meta-data android:name="io.branch.sdk.BranchKey.test" android:value="key_test_laLuH5hCCQKQjv5eM1Kugongssgw79iU" />
<meta-data android:name="io.branch.sdk.TestMode" android:value="false" /> <!-- Set to true to use Branch_Test_Key -->
<meta-data android:name="com.claimsforce.segment.WRITE_KEY" android:value="UdBbfFPkYCntzoFaWyEiwfKRKFLtTz14" />
<meta-data android:name="com.claimsforce.segment.TRACK_APPLICATION_LIFECYCLE_EVENTS" android:value="false" />
<!-- Branch install referrer tracking -->
<receiver android:name="io.branch.referral.InstallListener" android:exported="true">
<intent-filter>
Expand Down
2 changes: 2 additions & 0 deletions ios/Runner/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@
<string>key_live_aaSvQXmuELUQfsYeG4UfWemnqEiq04hr</string>
<key>com.claimsforce.segment.WRITE_KEY</key>
<string>n2yoAnpD1bpDmAXBhUloLYpS1U5f7W09</string>
<key>com.claimsforce.segment.TRACK_APPLICATION_LIFECYCLE_EVENTS</key>
<false/>
<key>io.flutter.embedded_views_preview</key>
<true/>
</dict>
Expand Down
11 changes: 6 additions & 5 deletions lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,22 @@ import 'dart:core';
import 'package:flutter/material.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:flutter_redux/flutter_redux.dart';
// import 'package:flutter_segment/flutter_segment.dart';
import 'package:fusecash/models/app_state.dart';
import 'package:fusecash/redux/state/store.dart';
import 'package:fusecash/screens/routes.dart';
import 'package:fusecash/screens/routes.gr.dart';
import 'package:fusecash/themes/app_theme.dart';
import 'package:fusecash/themes/custom_theme.dart';
import 'package:redux/redux.dart';
import 'package:flutter/foundation.dart';
import 'package:fusecash/generated/i18n.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter/services.dart';
import 'package:sentry/sentry.dart';

void main() async {
String configFile = String.fromEnvironment('CONFIG_FILE', defaultValue: '.env_prod');
print('loading $configFile config file');
await DotEnv().load(configFile);
SentryClient sentry = await AppFactory().getSentry();

SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp
Expand Down Expand Up @@ -88,8 +87,9 @@ class _MyAppState extends State<MyApp> {
store: store,
child: new MaterialApp(
title: 'Fuse Cash',
initialRoute: '/',
routes: getRoutes(),
initialRoute: Router.splashScreen,
navigatorKey: Router.navigator.key,
onGenerateRoute: Router.onGenerateRoute,
theme: CustomTheme.of(context),
localizationsDelegates: [
i18n,
Expand All @@ -100,6 +100,7 @@ class _MyAppState extends State<MyApp> {
supportedLocales: i18n.supportedLocales,
localeResolutionCallback:
i18n.resolution(fallback: new Locale("en", "US")),
// navigatorObservers: [SegmentObserver()],
),
),
),
Expand Down
81 changes: 81 additions & 0 deletions lib/middlewares/auth_middleware.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import 'package:firebase_auth/firebase_auth.dart';
import 'package:fusecash/models/app_state.dart';
import 'package:fusecash/redux/actions/cash_wallet_actions.dart';
import 'package:fusecash/redux/actions/error_actions.dart';
import 'package:fusecash/redux/actions/user_actions.dart';
import 'package:fusecash/redux/state/store.dart';
import 'package:fusecash/screens/routes.gr.dart';
import 'package:fusecash/services.dart';
import 'package:fusecash/utils/phone.dart';
import 'package:redux/redux.dart';
import 'package:firebase_auth_platform_interface/firebase_auth_platform_interface.dart';

List<Middleware<AppState>> createAuthMiddleware() {
final loginRequest = _createLoginRequestMiddleware();
final verifyRequest = _createVerifyPhoneNumberMiddleware();

return [
TypedMiddleware<AppState, LoginRequest>(loginRequest),
TypedMiddleware<AppState, VerifyRequest>(verifyRequest),
];
}

Middleware<AppState> _createLoginRequestMiddleware() {
return (Store store, action, NextDispatcher next) async {
final logger = await AppFactory().getLogger('action');

if (action is LoginRequest) {
try {
String phone = formatPhoneNumber(action.phoneNumber, action.countryCode);
await firebaseAuth.verifyPhoneNumber(
phoneNumber: phone,
codeAutoRetrievalTimeout: action.codeAutoRetrievalTimeout,
codeSent: action.codeSent,
timeout: Duration(minutes: 2),
verificationCompleted: action.verificationCompleted,
verificationFailed: action.verificationFailed
);
store.dispatch(new LoginRequestSuccess(action.countryCode, action.phoneNumber, "", ""));
}
catch (e, s) {
logger.severe('ERROR - LoginRequest $e');
await AppFactory().reportError(e, s);
store.dispatch(new ErrorAction(e));
store.dispatch(segmentTrackCall("ERROR in LoginRequest", properties: new Map.from({ "error": e.toString() })));
}
}
next(action);
};
}

Middleware<AppState> _createVerifyPhoneNumberMiddleware() {
return (Store store, action, NextDispatcher next) async {
final logger = await AppFactory().getLogger('action');
if (action is VerifyRequest) {
try {
PhoneAuthCredential credential = store.state.userState.credentials;
if (credential == null) {
credential = PhoneAuthProvider.getCredential(
verificationId: action.verificationId,
smsCode: action.verificationCode,
);
}
final FirebaseUser user = (await firebaseAuth.signInWithCredential(credential)).user;
final FirebaseUser currentUser = await firebaseAuth.currentUser();
assert(user.uid == currentUser.uid);
String accountAddress = store.state.userState.accountAddress;
IdTokenResult token = await user.getIdToken();
String jwtToken = await api.login(token.token, accountAddress);
store.dispatch(new LoginVerifySuccess(jwtToken));
Router.navigator.pushReplacementNamed(Router.userNameScreen);
}
catch (e, s) {
logger.severe('ERROR - Verification failed $e');
await AppFactory().reportError(e, s);
store.dispatch(new ErrorAction(e));
store.dispatch(segmentTrackCall("ERROR in VerifyRequest", properties: new Map.from({ "error": e.toString() })));
}
}
next(action);
};
}
4 changes: 2 additions & 2 deletions lib/models/jobs/backup_job.dart
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ class BackupJob extends Job {
this.status = 'FAILED';
String failReason = fetchedData['failReason'];
store.dispatch(transactionFailed(arguments['backupBonus']));
store.dispatch(segmentTrackCall('Wallet: BackupJob FAILED - $failReason'));
store.dispatch(segmentTrackCall('Wallet: job failed', properties: new Map<String, dynamic>.from({ 'id': id, 'failReason': failReason, 'name': name })));
return;
}

Expand All @@ -62,7 +62,7 @@ class BackupJob extends Job {
if (data['status'] == 'SUCCEEDED') {
this.status = 'DONE';
store.dispatch(backupSuccessCall(data['txHash'], arguments['backupBonus']));
store.dispatch(segmentTrackCall('Wallet: SUCCEEDED job $id $name'));
store.dispatch(segmentTrackCall('Wallet: job succeeded', properties: new Map<String, dynamic>.from({ 'id': id, 'name': name })));
return;
} else if (status == 'FAILED') {
this.status = 'FAILED';
Expand Down
6 changes: 3 additions & 3 deletions lib/models/jobs/base.dart
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,13 @@ abstract class Job {
{this.id,
this.jobType,
this.name,
status,
arguments,
this.status,
this.arguments,
this.isFunderJob,
this.data,
this.lastFinishedAt,
this.timeStart,
isReported}) {
this.isReported}) {
this.arguments = argumentsFromJson(arguments);
}

Expand Down
4 changes: 2 additions & 2 deletions lib/models/jobs/invite_bonus_job.dart
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ class InviteBonusJob extends Job {
this.status = 'FAILED';
String failReason = fetchedData['failReason'];
store.dispatch(transactionFailed(arguments['inviteBonus']));
store.dispatch(segmentTrackCall('Wallet: InviteBonusJob FAILED - $failReason'));
store.dispatch(segmentTrackCall('Wallet: job failed', properties: new Map<String, dynamic>.from({ 'id': id, 'failReason': failReason, 'name': name })));
return;
}

Expand All @@ -66,7 +66,7 @@ class InviteBonusJob extends Job {
if (responseStatus == 'SUCCEEDED') {
this.status = 'DONE';
store.dispatch(inviteBonusSuccessCall(data['txHash'], arguments['inviteBonus']));
store.dispatch(segmentTrackCall('Wallet: SUCCEEDED job $id $name'));
store.dispatch(segmentTrackCall('Wallet: job succeeded', properties: new Map<String, dynamic>.from({ 'id': id, 'name': name })));
logger.info('InviteBonusJob SUCCEEDED');
return;
} else if (responseStatus == 'FAILED') {
Expand Down
4 changes: 2 additions & 2 deletions lib/models/jobs/invite_job.dart
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ class InviteJob extends Job {
this.status = 'FAILED';
String failReason = fetchedData['failReason'];
store.dispatch(transactionFailed(arguments['inviteTransfer']));
store.dispatch(segmentTrackCall('Wallet: InviteJob FAILED - $failReason'));
store.dispatch(segmentTrackCall('Wallet: job failed', properties: new Map<String, dynamic>.from({ 'id': id, 'failReason': failReason, 'name': name })));
return;
}

Expand All @@ -69,7 +69,7 @@ class InviteJob extends Job {
arguments['inviteTransfer'],
arguments['sendSuccessCallback'],
arguments['sendFailureCallback']));
store.dispatch(segmentTrackCall('Wallet: SUCCEEDED job $id $name'));
store.dispatch(segmentTrackCall('Wallet: job succeeded', properties: new Map<String, dynamic>.from({ 'id': id, 'name': name })));
}

@override
Expand Down
2 changes: 1 addition & 1 deletion lib/models/jobs/join_bonus_job.dart
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ class JoinBonusJob extends Job {
if (responseStatus == 'SUCCEEDED') {
this.status = 'DONE';
store.dispatch(joinBonusSuccessCall(data['txHash'], arguments['joinBonus']));
store.dispatch(segmentTrackCall('Wallet: SUCCEEDED job $id $name'));
store.dispatch(segmentTrackCall('Wallet: job succeeded', properties: new Map<String, dynamic>.from({ 'id': id, 'name': name })));
logger.info('JoinBonusJob SUCCEEDED');
return;
} else if (responseStatus == 'FAILED') {
Expand Down
4 changes: 2 additions & 2 deletions lib/models/jobs/join_community_job.dart
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ class JoinCommunityJob extends Job {
this.status = 'FAILED';
String failReason = fetchedData['failReason'];
store.dispatch(transactionFailed(arguments['transfer']));
store.dispatch(segmentTrackCall('Wallet: JoinCommunityJob FAILED - $failReason'));
store.dispatch(segmentTrackCall('Wallet: job failed', properties: new Map<String, dynamic>.from({ 'id': id, 'failReason': failReason, 'name': name })));
return;
}

Expand All @@ -61,7 +61,7 @@ class JoinCommunityJob extends Job {
}
this.status = 'DONE';
store.dispatch(joinCommunitySuccessCall(job, fetchedData, arguments['transfer'], arguments['community']));
store.dispatch(segmentTrackCall('Wallet: SUCCEEDED job $id $name'));
store.dispatch(segmentTrackCall('Wallet: job succeeded', properties: new Map<String, dynamic>.from({ 'id': id, 'name': name })));
}

@override
Expand Down
4 changes: 2 additions & 2 deletions lib/models/jobs/transfer_job.dart
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ class TransferJob extends Job {
this.status = 'FAILED';
String failReason = fetchedData['failReason'];
store.dispatch(transactionFailed(arguments['transfer']));
store.dispatch(segmentTrackCall('Wallet: TransferJob FAILED - $failReason'));
store.dispatch(segmentTrackCall('Wallet: job failed', properties: new Map<String, dynamic>.from({ 'id': id, 'failReason': failReason, 'name': name })));
return;
}

Expand All @@ -64,7 +64,7 @@ class TransferJob extends Job {
}
this.status = 'DONE';
store.dispatch(sendTokenSuccessCall(job, arguments['transfer']));
store.dispatch(segmentTrackCall('Wallet: SUCCEEDED job $id $name'));
store.dispatch(segmentTrackCall('Wallet: job succeeded', properties: new Map<String, dynamic>.from({ 'id': id, 'name': name })));
}

@override
Expand Down
51 changes: 45 additions & 6 deletions lib/models/views/onboard.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import 'package:equatable/equatable.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_auth_platform_interface/firebase_auth_platform_interface.dart';
import 'package:flutter/material.dart';
import 'package:fusecash/redux/actions/error_actions.dart';
import 'package:fusecash/screens/routes.gr.dart';
import 'package:fusecash/screens/signup/verify.dart';
import 'package:fusecash/services.dart';
import 'package:redux/redux.dart';
import 'package:fusecash/models/app_state.dart';
import 'package:fusecash/redux/actions/user_actions.dart';
Expand All @@ -15,8 +20,8 @@ class OnboardViewModel extends Equatable {
final PhoneAuthCredential credentials;
final bool loginRequestSuccess;
final bool loginVerifySuccess;
final Function(String, String, VoidCallback, VoidCallback) signUp;
final Function(String, String, String, String, String, VoidCallback, VoidCallback) verify;
final Function(String, String) signUp;
final Function(String, String, GlobalKey) verify;
final Function(String) setPincode;
final Function(String) setDisplayName;

Expand All @@ -37,6 +42,29 @@ class OnboardViewModel extends Equatable {
});

static OnboardViewModel fromStore(Store<AppState> store) {
final PhoneVerificationCompleted verificationCompleted = (AuthCredential credentials) async {
print('Got credentials: $credentials');
AuthResult authResult = await firebaseAuth.signInWithCredential(credentials);
print(authResult);
store.dispatch(new SetCredentials(credentials));
Router.navigator.pushNamed(Router.verifyScreen, arguments: VerifyScreenArguments(verificationId: ''));
};

final PhoneVerificationFailed verificationFailed = (AuthException authException) {
print('Phone number verification failed. Code: ${authException.code}. Message: ${authException.message}');
store.dispatch(SetLoginErrorMessage(authException.message));
store.dispatch(new ErrorAction('Could not login $authException'));
};

final PhoneCodeSent codeSent = (String verificationId, [int forceResendingToken]) async {
print("PhoneCodeSent " + verificationId);
Router.navigator.pushNamed(Router.verifyScreen, arguments: VerifyScreenArguments(verificationId: verificationId));
};

final PhoneCodeAutoRetrievalTimeout codeAutoRetrievalTimeout = (String verificationId) {
print("PhoneCodeAutoRetrievalTimeout " + verificationId);
Router.navigator.pushNamed(Router.verifyScreen, arguments: VerifyScreenArguments(verificationId: verificationId));
};
return OnboardViewModel(
countryCode: store.state.userState.countryCode,
phoneNumber: store.state.userState.phoneNumber,
Expand All @@ -47,11 +75,22 @@ class OnboardViewModel extends Equatable {
credentials: store.state.userState.credentials,
loginErrorMessage: store.state.userState.loginErrorMessage,
verifyErrorMessage: store.state.userState.verifyErrorMessage,
signUp: (countryCode, phoneNumber, successCallback, failCallback) {
store.dispatch(loginRequestCall(countryCode, phoneNumber, successCallback, failCallback));
signUp: (String countryCode, String phoneNumber) {
store.dispatch(LoginRequest(
countryCode: countryCode,
phoneNumber: phoneNumber,
codeSent: codeSent,
codeAutoRetrievalTimeout: codeAutoRetrievalTimeout,
verificationCompleted: verificationCompleted,
verificationFailed: verificationFailed
));
},
verify: (countryCode, phoneNumber, verificationCode, accountAddress, verificationId, successCallback, failCallback) {
store.dispatch(loginVerifyCall(countryCode, phoneNumber, verificationCode, accountAddress, verificationId, successCallback, failCallback));
verify: (verificationCode, verificationId, key) {
store.dispatch(VerifyRequest(
verificationCode: verificationCode,
verificationId: verificationId,
key: key
));
},
setPincode: (pincode) {
store.dispatch(setPincodeCall(pincode));
Expand Down
1 change: 0 additions & 1 deletion lib/models/views/send_amount.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import 'package:fusecash/models/app_state.dart';
import 'package:fusecash/models/community.dart';
import 'package:fusecash/models/token.dart';
import 'package:fusecash/redux/actions/cash_wallet_actions.dart';
import 'package:fusecash/utils/phone.dart';
import 'package:redux/redux.dart';

class SendAmountViewModel {
Expand Down
3 changes: 2 additions & 1 deletion lib/redux/actions/cash_wallet_actions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -441,7 +441,8 @@ ThunkAction createAccountWalletCall(String accountAddress) {
return;
}
List<Job> jobs = store.state.cashWalletState.communities[store.state.cashWalletState.communityAddress].jobs;
if (jobs.any((other) {return other.jobType == "createWallet";})) {
bool hasCreateWallet = jobs.any((job) => job.jobType == 'createWallet');
if (hasCreateWallet) {
store.dispatch(new CreateAccountWalletRequest(accountAddress));
return;
}
Expand Down
Loading

0 comments on commit 124e114

Please sign in to comment.