Track login errors

This commit is contained in:
Hillel Coren 2020-10-04 13:35:48 +03:00
parent 6dcaf9796c
commit 5e56c407f7
16 changed files with 51 additions and 19 deletions

View File

@ -6,7 +6,7 @@ part 'account_model.g.dart';
abstract class AccountEntity abstract class AccountEntity
implements Built<AccountEntity, AccountEntityBuilder> { implements Built<AccountEntity, AccountEntityBuilder> {
factory AccountEntity({String id, AppState state}) { factory AccountEntity(bool reportErrors, {String id, AppState state}) {
return _$AccountEntity._( return _$AccountEntity._(
id: '', id: '',
defaultUrl: '', defaultUrl: '',
@ -14,7 +14,7 @@ abstract class AccountEntity
planExpires: '', planExpires: '',
latestVersion: '', latestVersion: '',
currentVersion: '', currentVersion: '',
reportErrors: false, reportErrors: reportErrors,
); );
} }

View File

@ -760,6 +760,8 @@ abstract class ContactEntity extends Object
String get link; String get link;
String get silentLink => '$link?silent=true';
String get fullName { String get fullName {
return (firstName + ' ' + lastName).trim(); return (firstName + ' ' + lastName).trim();
} }

View File

@ -409,6 +409,7 @@ abstract class CompanyEntity extends Object
); );
bool isModuleEnabled(EntityType entityType) { bool isModuleEnabled(EntityType entityType) {
/*
// TODO remove this // TODO remove this
if ([ if ([
EntityType.project, EntityType.project,
@ -418,6 +419,7 @@ abstract class CompanyEntity extends Object
].contains(entityType)) { ].contains(entityType)) {
return false; return false;
} }
*/
if ((entityType == EntityType.invoice || if ((entityType == EntityType.invoice ||
entityType == EntityType.payment) && entityType == EntityType.payment) &&
@ -572,7 +574,7 @@ abstract class GatewayEntity extends Object
abstract class UserCompanyEntity abstract class UserCompanyEntity
implements Built<UserCompanyEntity, UserCompanyEntityBuilder> { implements Built<UserCompanyEntity, UserCompanyEntityBuilder> {
factory UserCompanyEntity() { factory UserCompanyEntity(bool reportErrors) {
return _$UserCompanyEntity._( return _$UserCompanyEntity._(
isAdmin: false, isAdmin: false,
isOwner: false, isOwner: false,
@ -580,7 +582,7 @@ abstract class UserCompanyEntity
company: CompanyEntity(), company: CompanyEntity(),
user: UserEntity(), user: UserEntity(),
token: TokenEntity(), token: TokenEntity(),
account: AccountEntity(), account: AccountEntity(reportErrors),
notifications: BuiltMap<String, BuiltList<String>>().rebuild((b) => b notifications: BuiltMap<String, BuiltList<String>>().rebuild((b) => b
..[kNotificationChannelEmail] = ..[kNotificationChannelEmail] =
BuiltList<String>(<String>[kNotificationsAll])), BuiltList<String>(<String>[kNotificationsAll])),
@ -632,6 +634,7 @@ abstract class UserCompanyEntity
return true; return true;
} }
/*
// TODO remove this once task/expenses are supported // TODO remove this once task/expenses are supported
if (!Config.DEMO_MODE && if (!Config.DEMO_MODE &&
[ [
@ -642,6 +645,7 @@ abstract class UserCompanyEntity
].contains(entityType)) { ].contains(entityType)) {
return false; return false;
} }
*/
if (isAdmin ?? false) { if (isAdmin ?? false) {
return true; return true;

View File

@ -146,9 +146,18 @@ Future<AppState> _initialState(bool isTesting) async {
} }
*/ */
bool reportErrors = false;
if (kIsWeb) {
reportErrors = WebUtils.getHtmlValue('report-errors') == '1';
if (reportErrors) {
print('Error reporting is enabled');
}
}
return AppState( return AppState(
prefState: prefState, prefState: prefState,
currentRoute: currentRoute, currentRoute: currentRoute,
url: Config.DEMO_MODE ? '' : url, url: Config.DEMO_MODE ? '' : url,
reportErrors: reportErrors,
); );
} }

View File

@ -562,7 +562,7 @@ void createEntityByType(
force: force, force: force,
user: UserEntity( user: UserEntity(
state: state, state: state,
userCompany: UserCompanyEntity(), userCompany: UserCompanyEntity(false),
), ),
)); ));
break; break;

View File

@ -207,7 +207,9 @@ Middleware<AppState> _createLoadState(
companyStates.add(await companyRepositories[i].loadCompanyState(i)); companyStates.add(await companyRepositories[i].loadCompanyState(i));
} }
final AppState appState = AppState(prefState: store.state.prefState) final AppState appState = AppState(
prefState: store.state.prefState,
reportErrors: store.state.account.reportErrors)
.rebuild((b) => b .rebuild((b) => b
..authState.replace(authState) ..authState.replace(authState)
..uiState.replace(uiState) ..uiState.replace(uiState)

View File

@ -33,11 +33,14 @@ import 'package:invoiceninja_flutter/redux/credit/credit_actions.dart';
// We create the State reducer by combining many smaller reducers into one! // We create the State reducer by combining many smaller reducers into one!
AppState appReducer(AppState state, dynamic action) { AppState appReducer(AppState state, dynamic action) {
if (action is UserLogout) { if (action is UserLogout) {
return AppState(prefState: state.prefState).rebuild((b) => b return AppState(
..authState.replace(state.authState.rebuild((b) => b prefState: state.prefState,
..isAuthenticated = false reportErrors: state.account.reportErrors)
..lastEnteredPasswordAt = 0)) .rebuild((b) => b
..isTesting = state.isTesting); ..authState.replace(state.authState.rebuild((b) => b
..isAuthenticated = false
..lastEnteredPasswordAt = 0))
..isTesting = state.isTesting);
} else if (action is LoadStateSuccess) { } else if (action is LoadStateSuccess) {
return action.state.rebuild((b) => b return action.state.rebuild((b) => b
..isLoading = false ..isLoading = false
@ -46,7 +49,7 @@ AppState appReducer(AppState state, dynamic action) {
return state.rebuild((b) => b return state.rebuild((b) => b
..userCompanyStates.replace(BuiltList<UserCompanyState>( ..userCompanyStates.replace(BuiltList<UserCompanyState>(
List<int>.generate(kMaxNumberOfCompanies, (i) => i + 1) List<int>.generate(kMaxNumberOfCompanies, (i) => i + 1)
.map((index) => UserCompanyState()) .map((index) => UserCompanyState(state.account.reportErrors))
.toList()))); .toList())));
} }

View File

@ -77,6 +77,7 @@ part 'app_state.g.dart';
abstract class AppState implements Built<AppState, AppStateBuilder> { abstract class AppState implements Built<AppState, AppStateBuilder> {
factory AppState({ factory AppState({
@required PrefState prefState, @required PrefState prefState,
@required bool reportErrors,
String currentRoute, String currentRoute,
String url, String url,
}) { }) {
@ -89,7 +90,7 @@ abstract class AppState implements Built<AppState, AppStateBuilder> {
staticState: StaticState(), staticState: StaticState(),
userCompanyStates: BuiltList( userCompanyStates: BuiltList(
List<int>.generate(kMaxNumberOfCompanies, (i) => i + 1) List<int>.generate(kMaxNumberOfCompanies, (i) => i + 1)
.map((index) => UserCompanyState()) .map((index) => UserCompanyState(reportErrors))
.toList()), .toList()),
uiState: UIState(currentRoute: currentRoute), uiState: UIState(currentRoute: currentRoute),
prefState: prefState ?? PrefState(), prefState: prefState ?? PrefState(),

View File

@ -88,6 +88,7 @@ Middleware<AppState> _createLoginRequest(AuthRepository repository) {
action.completer.completeError(message); action.completer.completeError(message);
} }
store.dispatch(UserLoginFailure(message)); store.dispatch(UserLoginFailure(message));
throw error;
}); });
next(action); next(action);
@ -115,6 +116,7 @@ Middleware<AppState> _createSignUpRequest(AuthRepository repository) {
action.completer.completeError(message); action.completer.completeError(message);
} }
store.dispatch(UserLoginFailure(message)); store.dispatch(UserLoginFailure(message));
throw error;
}); });
next(action); next(action);
@ -148,6 +150,7 @@ Middleware<AppState> _createOAuthLoginRequest(AuthRepository repository) {
action.completer.completeError(message); action.completer.completeError(message);
} }
store.dispatch(UserLoginFailure(message)); store.dispatch(UserLoginFailure(message));
throw error;
}); });
next(action); next(action);
@ -176,6 +179,7 @@ Middleware<AppState> _createOAuthSignUpRequest(AuthRepository repository) {
action.completer.completeError(message); action.completer.completeError(message);
} }
store.dispatch(UserLoginFailure(message)); store.dispatch(UserLoginFailure(message));
throw error;
}); });
next(action); next(action);
@ -229,6 +233,7 @@ Middleware<AppState> _createRefreshRequest(AuthRepository repository) {
action.completer.completeError(message); action.completer.completeError(message);
} }
store.dispatch(RefreshDataFailure(message)); store.dispatch(RefreshDataFailure(message));
throw error;
}); });
next(action); next(action);

View File

@ -32,7 +32,7 @@ import 'package:invoiceninja_flutter/redux/group/group_reducer.dart';
UserCompanyState companyReducer(UserCompanyState state, dynamic action) { UserCompanyState companyReducer(UserCompanyState state, dynamic action) {
if (action is DeleteCompanySuccess) { if (action is DeleteCompanySuccess) {
return UserCompanyState(); return UserCompanyState(false);
} }
return state.rebuild((b) => b return state.rebuild((b) => b

View File

@ -31,10 +31,10 @@ part 'company_state.g.dart';
abstract class UserCompanyState abstract class UserCompanyState
implements Built<UserCompanyState, UserCompanyStateBuilder> { implements Built<UserCompanyState, UserCompanyStateBuilder> {
factory UserCompanyState() { factory UserCompanyState(bool reportErrors) {
return _$UserCompanyState._( return _$UserCompanyState._(
lastUpdated: 0, lastUpdated: 0,
userCompany: UserCompanyEntity(), userCompany: UserCompanyEntity(reportErrors),
documentState: DocumentState(), documentState: DocumentState(),
productState: ProductState(), productState: ProductState(),
clientState: ClientState(), clientState: ClientState(),

View File

@ -58,7 +58,7 @@ class _ClientViewDetailsState extends State<ClientViewDetails> {
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5)), borderRadius: BorderRadius.circular(5)),
onPressed: () { onPressed: () {
launch('${contact.link}&client_hash=${client.clientHash}', launch('${contact.silentLink}&client_hash=${client.clientHash}',
forceWebView: false, forceSafariVC: false); forceWebView: false, forceSafariVC: false);
}, },
)), )),

View File

@ -11,6 +11,9 @@ class WebUtils {
static String get browserUrl => static String get browserUrl =>
formatApiUrl(window.location.href.split('#')[0]); formatApiUrl(window.location.href.split('#')[0]);
static String getHtmlValue(String field) =>
window.document.documentElement.dataset[field];
static Future<String> filePicker() { static Future<String> filePicker() {
final completer = new Completer<String>(); final completer = new Completer<String>();
final InputElement input = document.createElement('input'); final InputElement input = document.createElement('input');

View File

@ -6,6 +6,8 @@ import 'package:redux/redux.dart';
class WebUtils { class WebUtils {
static String get browserUrl => null; static String get browserUrl => null;
static String getHtmlValue(String field) => null;
static Future<String> filePicker() => null; static Future<String> filePicker() => null;
static void downloadTextFile(String filename, String data) {} static void downloadTextFile(String filename, String data) {}

View File

@ -381,7 +381,7 @@ packages:
name: flutter_launcher_icons name: flutter_launcher_icons
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.8.0" version: "0.8.1"
flutter_localizations: flutter_localizations:
dependency: "direct main" dependency: "direct main"
description: flutter description: flutter

View File

@ -1,7 +1,8 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html data-report-errors="1">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="report_errors" content="1">
<title>Invoice Ninja</title> <title>Invoice Ninja</title>
<link rel="manifest" href="manifest.json"> <link rel="manifest" href="manifest.json">
</head> </head>