Handle invalid credentails

This commit is contained in:
unknown 2018-05-24 06:04:06 -07:00
parent 9e5e260eb1
commit 5b255b1745
6 changed files with 138 additions and 80 deletions

View File

@ -2,15 +2,30 @@ import 'package:json_annotation/json_annotation.dart';
part 'entities.g.dart';
@JsonSerializable()
class ErrorResponse extends Object with _$ErrorResponseSerializerMixin {
final String message;
ErrorResponse(
this.message,
);
factory ErrorResponse.fromJson(Map<String, dynamic> json) => _$ErrorResponseFromJson(json);
}
@JsonSerializable()
class BaseListResponse extends Object with _$BaseListResponseSerializerMixin {
//final String message;
@JsonKey(name: "data")
final List<dynamic> data;
final ErrorResponse error;
BaseListResponse(
this.data,
this.error,
);
factory BaseListResponse.fromJson(Map<String, dynamic> json) => _$BaseListResponseFromJson(json);
@ -22,9 +37,11 @@ class BaseItemResponse extends Object with _$BaseItemResponseSerializerMixin {
@JsonKey(name: "data")
final dynamic data;
final ErrorResponse error;
BaseItemResponse(
this.data,
this.error,
);
factory BaseItemResponse.fromJson(Map<String, dynamic> json) => _$BaseItemResponseFromJson(json);

View File

@ -6,20 +6,42 @@ part of 'entities.dart';
// Generator: JsonSerializableGenerator
// **************************************************************************
ErrorResponse _$ErrorResponseFromJson(Map<String, dynamic> json) =>
new ErrorResponse(json['message'] as String);
abstract class _$ErrorResponseSerializerMixin {
String get message;
Map<String, dynamic> toJson() => <String, dynamic>{'message': message};
}
BaseListResponse _$BaseListResponseFromJson(Map<String, dynamic> json) =>
new BaseListResponse(json['data'] as List);
new BaseListResponse(
json['data'] as List,
json['error'] == null
? null
: new ErrorResponse.fromJson(
json['error'] as Map<String, dynamic>));
abstract class _$BaseListResponseSerializerMixin {
List<dynamic> get data;
Map<String, dynamic> toJson() => <String, dynamic>{'data': data};
ErrorResponse get error;
Map<String, dynamic> toJson() =>
<String, dynamic>{'data': data, 'error': error};
}
BaseItemResponse _$BaseItemResponseFromJson(Map<String, dynamic> json) =>
new BaseItemResponse(json['data']);
new BaseItemResponse(
json['data'],
json['error'] == null
? null
: new ErrorResponse.fromJson(
json['error'] as Map<String, dynamic>));
abstract class _$BaseItemResponseSerializerMixin {
dynamic get data;
Map<String, dynamic> toJson() => <String, dynamic>{'data': data};
ErrorResponse get error;
Map<String, dynamic> toJson() =>
<String, dynamic>{'data': data, 'error': error};
}
CompanyEntity _$CompanyEntityFromJson(Map<String, dynamic> json) =>

View File

@ -35,26 +35,35 @@ class WebClient {
Future<dynamic> fetchItem(String url, String token) async {
final http.Response response = await sendGetRequest(url, token);
return BaseItemResponse
.fromJson(json.decode(response.body))
.data;
final result = BaseItemResponse.fromJson(json.decode(response.body));
if (result.error.message != null) {
throw(result.error.message);
} else {
return result.data;
}
}
Future<List<dynamic>> fetchList(String url, String token) async {
final http.Response response = await sendGetRequest(url, token);
return BaseListResponse
.fromJson(json.decode(response.body))
.data
.toList();
}
final result = BaseListResponse.fromJson(json.decode(response.body));
if (result.error.message != null) {
throw(result.error.message);
} else {
return result.data.toList();
}
}
Future<List<dynamic>> postList(String url, String token, var data) async {
final http.Response response = await sendPostRequest(url, token, data);
return BaseListResponse
.fromJson(json.decode(response.body))
.data
.toList();
final result = BaseListResponse.fromJson(json.decode(response.body));
if (result.error.message != null) {
throw(result.error.message);
} else {
return result.data.toList();
}
}
}

View File

@ -4,7 +4,7 @@ import 'package:invoiceninja/redux/app/app_state.dart';
import 'package:invoiceninja/data/models/models.dart';
class UserLoginRequest {
final dynamic context;
final BuildContext context;
final String email;
final String password;
final String url;

View File

@ -1,3 +1,4 @@
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:redux/redux.dart';
import 'package:invoiceninja/redux/auth/auth_actions.dart';
@ -53,8 +54,18 @@ Middleware<AppState> _createLoginRequest(AuthRepository repository) {
Navigator.of(action.context).pushNamed(AppRoutes.dashboard);
}
).catchError((error) => store.dispatch(UserLoginFailure(error)));
).catchError((error) {
store.dispatch(UserLoginFailure(null));
final snackBar = new SnackBar(
duration: Duration(seconds: 3),
content: new Text('Error: ' + error.toString()),
);
Scaffold.of(action.context).showSnackBar(snackBar);
});
next(action);
};
}

View File

@ -47,69 +47,68 @@ class _LoginScreenState extends State<LoginScreen> {
@override
Widget build(BuildContext context) {
return StoreConnector<AppState, dynamic>(
converter: (Store<AppState> store) {
return (BuildContext context, String email, String password, String url) {
store.dispatch(UserLoginRequest(context, email, password, url));
};
}, builder: (BuildContext context, loginAction) {
return Scaffold(
return Scaffold(
body: Form(
key: _formKey,
child: ListView(
shrinkWrap: true,
padding: EdgeInsets.only(left: 24.0, right: 24.0, top: 40.0),
children: [
Padding(
padding: EdgeInsets.only(top: 20.0, bottom: 20.0),
child: new Image.asset('assets/images/logo.png', width: 100.0, height: 100.0),
),
TextFormField(
controller: _emailTextController,
decoration: InputDecoration(labelText: 'Email'),
keyboardType: TextInputType.emailAddress,
validator: (val) =>
val.isEmpty ? 'Please enter your email.' : null,
onSaved: (val) => _email = val,
),
TextFormField(
controller: _passwordTextController,
decoration: InputDecoration(labelText: 'Password'),
validator: (val) =>
val.isEmpty ? 'Please enter your password.' : null,
onSaved: (val) => _password = val,
obscureText: true,
),
TextFormField(
controller: _urlTextController,
decoration: InputDecoration(labelText: 'URL'),
validator: (val) =>
val.isEmpty ? 'Please enter your URL.' : null,
onSaved: (val) => _url = val,
),
Padding(
padding: EdgeInsets.only(top: 20.0),
child: Material(
shadowColor: Colors.lightBlueAccent.shade100,
elevation: 5.0,
child: MaterialButton(
minWidth: 200.0,
height: 42.0,
onPressed: () {
_submit();
loginAction(context, _email, _password, _url);
//Navigator.of(context).pushNamed(HomeScreen.tag);
},
color: Colors.lightBlueAccent,
child:
Text('LOGIN', style: TextStyle(color: Colors.white)),
),
key: _formKey,
child:
StoreConnector<AppState, dynamic>(converter: (Store<AppState> store) {
return (BuildContext context, String email, String password,
String url) {
store.dispatch(UserLoginRequest(context, email, password, url));
};
}, builder: (BuildContext context, loginAction) {
return ListView(
shrinkWrap: true,
padding: EdgeInsets.only(left: 24.0, right: 24.0, top: 40.0),
children: [
Padding(
padding: EdgeInsets.only(top: 20.0, bottom: 20.0),
child: new Image.asset('assets/images/logo.png',
width: 100.0, height: 100.0),
),
TextFormField(
controller: _emailTextController,
decoration: InputDecoration(labelText: 'Email'),
keyboardType: TextInputType.emailAddress,
validator: (val) =>
val.isEmpty ? 'Please enter your email.' : null,
onSaved: (val) => _email = val,
),
TextFormField(
controller: _passwordTextController,
decoration: InputDecoration(labelText: 'Password'),
validator: (val) =>
val.isEmpty ? 'Please enter your password.' : null,
onSaved: (val) => _password = val,
obscureText: true,
),
TextFormField(
controller: _urlTextController,
decoration: InputDecoration(labelText: 'URL'),
validator: (val) => val.isEmpty ? 'Please enter your URL.' : null,
onSaved: (val) => _url = val,
),
Padding(
padding: EdgeInsets.only(top: 20.0),
child: Material(
shadowColor: Colors.lightBlueAccent.shade100,
elevation: 5.0,
child: MaterialButton(
minWidth: 200.0,
height: 42.0,
onPressed: () {
_submit();
loginAction(context, _email, _password, _url);
//Navigator.of(context).pushNamed(HomeScreen.tag);
},
color: Colors.lightBlueAccent,
child: Text('LOGIN', style: TextStyle(color: Colors.white)),
),
),
],
),
),
);
});
),
],
);
}),
));
}
}