Add new settings route

This commit is contained in:
Hillel Coren 2020-02-28 16:31:20 +02:00
parent 8d61720eaa
commit 309d49f4a0
13 changed files with 252 additions and 41 deletions

View File

@ -119,6 +119,7 @@ part 'serializers.g.dart';
GatewayEntity, GatewayEntity,
GatewayTokenListResponse, GatewayTokenListResponse,
GatewayTokenItemResponse, GatewayTokenItemResponse,
UserCompanyItemResponse,
]) ])
final Serializers serializers = final Serializers serializers =

View File

@ -141,6 +141,7 @@ Serializers _$serializers = (new Serializers().toBuilder()
..add(TokenEntity.serializer) ..add(TokenEntity.serializer)
..add(UIState.serializer) ..add(UIState.serializer)
..add(UserCompanyEntity.serializer) ..add(UserCompanyEntity.serializer)
..add(UserCompanyItemResponse.serializer)
..add(UserCompanyState.serializer) ..add(UserCompanyState.serializer)
..add(UserEntity.serializer) ..add(UserEntity.serializer)
..add(UserItemResponse.serializer) ..add(UserItemResponse.serializer)

View File

@ -35,6 +35,19 @@ abstract class UserItemResponse
_$userItemResponseSerializer; _$userItemResponseSerializer;
} }
abstract class UserCompanyItemResponse
implements Built<UserCompanyItemResponse, UserCompanyItemResponseBuilder> {
factory UserCompanyItemResponse([void updates(UserCompanyItemResponseBuilder b)]) =
_$UserCompanyItemResponse;
UserCompanyItemResponse._();
UserCompanyEntity get data;
static Serializer<UserCompanyItemResponse> get serializer =>
_$userCompanyItemResponseSerializer;
}
class UserFields { class UserFields {
static const String firstName = 'first_name'; static const String firstName = 'first_name';
static const String lastName = 'last_name'; static const String lastName = 'last_name';

View File

@ -10,6 +10,8 @@ Serializer<UserListResponse> _$userListResponseSerializer =
new _$UserListResponseSerializer(); new _$UserListResponseSerializer();
Serializer<UserItemResponse> _$userItemResponseSerializer = Serializer<UserItemResponse> _$userItemResponseSerializer =
new _$UserItemResponseSerializer(); new _$UserItemResponseSerializer();
Serializer<UserCompanyItemResponse> _$userCompanyItemResponseSerializer =
new _$UserCompanyItemResponseSerializer();
Serializer<UserEntity> _$userEntitySerializer = new _$UserEntitySerializer(); Serializer<UserEntity> _$userEntitySerializer = new _$UserEntitySerializer();
class _$UserListResponseSerializer class _$UserListResponseSerializer
@ -99,6 +101,53 @@ class _$UserItemResponseSerializer
} }
} }
class _$UserCompanyItemResponseSerializer
implements StructuredSerializer<UserCompanyItemResponse> {
@override
final Iterable<Type> types = const [
UserCompanyItemResponse,
_$UserCompanyItemResponse
];
@override
final String wireName = 'UserCompanyItemResponse';
@override
Iterable<Object> serialize(
Serializers serializers, UserCompanyItemResponse object,
{FullType specifiedType = FullType.unspecified}) {
final result = <Object>[
'data',
serializers.serialize(object.data,
specifiedType: const FullType(UserCompanyEntity)),
];
return result;
}
@override
UserCompanyItemResponse deserialize(
Serializers serializers, Iterable<Object> serialized,
{FullType specifiedType = FullType.unspecified}) {
final result = new UserCompanyItemResponseBuilder();
final iterator = serialized.iterator;
while (iterator.moveNext()) {
final key = iterator.current as String;
iterator.moveNext();
final dynamic value = iterator.current;
switch (key) {
case 'data':
result.data.replace(serializers.deserialize(value,
specifiedType: const FullType(UserCompanyEntity))
as UserCompanyEntity);
break;
}
}
return result.build();
}
}
class _$UserEntitySerializer implements StructuredSerializer<UserEntity> { class _$UserEntitySerializer implements StructuredSerializer<UserEntity> {
@override @override
final Iterable<Type> types = const [UserEntity, _$UserEntity]; final Iterable<Type> types = const [UserEntity, _$UserEntity];
@ -475,6 +524,102 @@ class UserItemResponseBuilder
} }
} }
class _$UserCompanyItemResponse extends UserCompanyItemResponse {
@override
final UserCompanyEntity data;
factory _$UserCompanyItemResponse(
[void Function(UserCompanyItemResponseBuilder) updates]) =>
(new UserCompanyItemResponseBuilder()..update(updates)).build();
_$UserCompanyItemResponse._({this.data}) : super._() {
if (data == null) {
throw new BuiltValueNullFieldError('UserCompanyItemResponse', 'data');
}
}
@override
UserCompanyItemResponse rebuild(
void Function(UserCompanyItemResponseBuilder) updates) =>
(toBuilder()..update(updates)).build();
@override
UserCompanyItemResponseBuilder toBuilder() =>
new UserCompanyItemResponseBuilder()..replace(this);
@override
bool operator ==(Object other) {
if (identical(other, this)) return true;
return other is UserCompanyItemResponse && data == other.data;
}
@override
int get hashCode {
return $jf($jc(0, data.hashCode));
}
@override
String toString() {
return (newBuiltValueToStringHelper('UserCompanyItemResponse')
..add('data', data))
.toString();
}
}
class UserCompanyItemResponseBuilder
implements
Builder<UserCompanyItemResponse, UserCompanyItemResponseBuilder> {
_$UserCompanyItemResponse _$v;
UserCompanyEntityBuilder _data;
UserCompanyEntityBuilder get data =>
_$this._data ??= new UserCompanyEntityBuilder();
set data(UserCompanyEntityBuilder data) => _$this._data = data;
UserCompanyItemResponseBuilder();
UserCompanyItemResponseBuilder get _$this {
if (_$v != null) {
_data = _$v.data?.toBuilder();
_$v = null;
}
return this;
}
@override
void replace(UserCompanyItemResponse other) {
if (other == null) {
throw new ArgumentError.notNull('other');
}
_$v = other as _$UserCompanyItemResponse;
}
@override
void update(void Function(UserCompanyItemResponseBuilder) updates) {
if (updates != null) updates(this);
}
@override
_$UserCompanyItemResponse build() {
_$UserCompanyItemResponse _$result;
try {
_$result = _$v ?? new _$UserCompanyItemResponse._(data: data.build());
} catch (_) {
String _$failedField;
try {
_$failedField = 'data';
data.build();
} catch (e) {
throw new BuiltValueNestedFieldError(
'UserCompanyItemResponse', _$failedField, e.toString());
}
rethrow;
}
replace(_$result);
return _$result;
}
}
class _$UserEntity extends UserEntity { class _$UserEntity extends UserEntity {
@override @override
final String firstName; final String firstName;

View File

@ -30,7 +30,7 @@ class SettingsRepository {
return companyResponse.data; return companyResponse.data;
} }
Future<UserEntity> saveUser( Future<UserEntity> saveAuthUser(
Credentials credentials, UserEntity user, String password) async { Credentials credentials, UserEntity user, String password) async {
final data = serializers.serializeWith(UserEntity.serializer, user); final data = serializers.serializeWith(UserEntity.serializer, user);
dynamic response; dynamic response;
@ -44,7 +44,25 @@ class SettingsRepository {
); );
final UserItemResponse userResponse = final UserItemResponse userResponse =
serializers.deserializeWith(UserItemResponse.serializer, response); serializers.deserializeWith(UserItemResponse.serializer, response);
return userResponse.data;
}
Future<UserCompanyEntity> saveUserSettings(
Credentials credentials, UserEntity user) async {
final data = serializers.serializeWith(UserEntity.serializer, user);
dynamic response;
final url = credentials.url + '/company_users/${user.id}';
response = await webClient.put(
url,
credentials.token,
data: json.encode(data),
);
final UserCompanyItemResponse userResponse =
serializers.deserializeWith(UserCompanyItemResponse.serializer, response);
return userResponse.data; return userResponse.data;
} }

View File

@ -81,10 +81,14 @@ Reducer<UserCompanyEntity> userCompanyEntityReducer = combineReducers([
); );
} }
}), }),
TypedReducer<UserCompanyEntity, SaveUserSettingsSuccess>( TypedReducer<UserCompanyEntity, SaveAuthUserSuccess>((userCompany, action) =>
(userCompany, action) => userCompany.rebuild((b) => b userCompany.rebuild((b) => b
..user.replace(action.user) ..user.replace(action.user)
..settings.replace(action.user.userCompany.settings))), ..settings.replace(action.user.userCompany.settings))),
TypedReducer<UserCompanyEntity, SaveUserSettingsSuccess>(
(userCompany, action) => userCompany.rebuild((b) => b
..user.userCompany.settings.replace(userCompany.settings)
..settings.replace(action.userCompany.settings))),
]); ]);
UserCompanyEntity loadCompanySuccessReducer( UserCompanyEntity loadCompanySuccessReducer(

View File

@ -4,7 +4,7 @@ import 'package:invoiceninja_flutter/redux/reports/reports_state.dart';
import 'package:invoiceninja_flutter/redux/settings/settings_actions.dart'; import 'package:invoiceninja_flutter/redux/settings/settings_actions.dart';
ReportsUIState reportsUIReducer(ReportsUIState state, dynamic action) { ReportsUIState reportsUIReducer(ReportsUIState state, dynamic action) {
if (action is SaveUserSettingsSuccess) { if (action is SaveAuthUserSuccess) {
return state.rebuild((b) => b return state.rebuild((b) => b
..group = '' ..group = ''
..subgroup = '' ..subgroup = ''

View File

@ -61,6 +61,28 @@ class SaveUserSettingsRequest implements StartSaving {
SaveUserSettingsRequest({ SaveUserSettingsRequest({
@required this.completer, @required this.completer,
@required this.user, @required this.user,
});
final Completer completer;
final UserEntity user;
}
class SaveUserSettingsSuccess implements StopSaving, PersistData, PersistUI {
SaveUserSettingsSuccess(this.userCompany);
final UserCompanyEntity userCompany;
}
class SaveUserSettingsFailure implements StopSaving {
SaveUserSettingsFailure(this.error);
final Object error;
}
class SaveAuthUserRequest implements StartSaving {
SaveAuthUserRequest({
@required this.completer,
@required this.user,
this.password, this.password,
}); });
@ -69,14 +91,14 @@ class SaveUserSettingsRequest implements StartSaving {
final String password; final String password;
} }
class SaveUserSettingsSuccess implements StopSaving, PersistData, PersistUI { class SaveAuthUserSuccess implements StopSaving, PersistData, PersistUI {
SaveUserSettingsSuccess(this.user); SaveAuthUserSuccess(this.user);
final UserEntity user; final UserEntity user;
} }
class SaveUserSettingsFailure implements StopSaving { class SaveAuthUserFailure implements StopSaving {
SaveUserSettingsFailure(this.error); SaveAuthUserFailure(this.error);
final Object error; final Object error;
} }

View File

@ -22,13 +22,15 @@ List<Middleware<AppState>> createStoreSettingsMiddleware([
]) { ]) {
final viewSettings = _viewSettings(); final viewSettings = _viewSettings();
final saveCompany = _saveCompany(repository); final saveCompany = _saveCompany(repository);
final saveUser = _saveUser(repository); final saveAuthUser = _saveAuthUser(repository);
final saveSettings = _saveSettings(repository);
final uploadLogo = _uploadLogo(repository); final uploadLogo = _uploadLogo(repository);
return [ return [
TypedMiddleware<AppState, ViewSettings>(viewSettings), TypedMiddleware<AppState, ViewSettings>(viewSettings),
TypedMiddleware<AppState, SaveCompanyRequest>(saveCompany), TypedMiddleware<AppState, SaveCompanyRequest>(saveCompany),
TypedMiddleware<AppState, SaveUserSettingsRequest>(saveUser), TypedMiddleware<AppState, SaveAuthUserRequest>(saveAuthUser),
TypedMiddleware<AppState, SaveUserSettingsRequest>(saveSettings),
TypedMiddleware<AppState, UploadLogoRequest>(uploadLogo), TypedMiddleware<AppState, UploadLogoRequest>(uploadLogo),
]; ];
} }
@ -84,15 +86,34 @@ Middleware<AppState> _saveCompany(SettingsRepository settingsRepository) {
}; };
} }
Middleware<AppState> _saveUser(SettingsRepository settingsRepository) { Middleware<AppState> _saveAuthUser(SettingsRepository settingsRepository) {
return (Store<AppState> store, dynamic dynamicAction, NextDispatcher next) {
final action = dynamicAction as SaveAuthUserRequest;
settingsRepository
.saveAuthUser(store.state.credentials, action.user, action.password)
.then((user) {
store.dispatch(SaveAuthUserSuccess(user));
store.dispatch(UserVerifiedPassword());
action.completer.complete();
}).catchError((Object error) {
print(error);
store.dispatch(SaveAuthUserFailure(error));
action.completer.completeError(error);
});
next(action);
};
}
Middleware<AppState> _saveSettings(SettingsRepository settingsRepository) {
return (Store<AppState> store, dynamic dynamicAction, NextDispatcher next) { return (Store<AppState> store, dynamic dynamicAction, NextDispatcher next) {
final action = dynamicAction as SaveUserSettingsRequest; final action = dynamicAction as SaveUserSettingsRequest;
settingsRepository settingsRepository
.saveUser(store.state.credentials, action.user, action.password) .saveUserSettings(store.state.credentials, action.user)
.then((user) { .then((userCompany) {
store.dispatch(SaveUserSettingsSuccess(user)); store.dispatch(SaveUserSettingsSuccess(userCompany));
store.dispatch(UserVerifiedPassword());
action.completer.complete(); action.completer.complete();
}).catchError((Object error) { }).catchError((Object error) {
print(error); print(error);

View File

@ -261,7 +261,7 @@ Reducer<SettingsUIState> settingsUIReducer = combineReducers([
..origClient.replace(action.client) ..origClient.replace(action.client)
..isChanged = false); ..isChanged = false);
}), }),
TypedReducer<SettingsUIState, prefix0.SaveUserSettingsSuccess>( TypedReducer<SettingsUIState, prefix0.SaveAuthUserSuccess>(
(state, action) { (state, action) {
return state.rebuild((b) => b return state.rebuild((b) => b
..user.replace(action.user) ..user.replace(action.user)

View File

@ -172,7 +172,7 @@ Reducer<SettingsUIState> settingsUIReducer = combineReducers([
..origClient.replace(action.client) ..origClient.replace(action.client)
..isChanged = false); ..isChanged = false);
}), }),
TypedReducer<SettingsUIState, SaveUserSettingsSuccess>((state, action) { TypedReducer<SettingsUIState, SaveAuthUserSuccess>((state, action) {
return state.rebuild((b) => b return state.rebuild((b) => b
..user.replace(action.user) ..user.replace(action.user)
..origUser.replace(action.user) ..origUser.replace(action.user)

View File

@ -31,7 +31,7 @@ import 'package:redux/redux.dart';
import 'expense_report.dart'; import 'expense_report.dart';
import 'reports_screen.dart'; import 'reports_screen.dart';
import 'package:invoiceninja_flutter/utils/web_stub.dart' import 'package:invoiceninja_flutter/utils/web_stub.dart'
if (dart.library.html) 'package:invoiceninja_flutter/utils/web.dart'; if (dart.library.html) 'package:invoiceninja_flutter/utils/web.dart';
class ReportsScreenBuilder extends StatelessWidget { class ReportsScreenBuilder extends StatelessWidget {
const ReportsScreenBuilder({Key key}) : super(key: key); const ReportsScreenBuilder({Key key}) : super(key: key);
@ -225,26 +225,12 @@ class ReportsScreenVM {
.rebuild((b) => b..userCompany.settings.replace(settings)); .rebuild((b) => b..userCompany.settings.replace(settings));
final completer = snackBarCompleter<Null>( final completer = snackBarCompleter<Null>(
context, AppLocalization.of(context).savedSettings); context, AppLocalization.of(context).savedSettings);
if (state.authState.hasRecentlyEnteredPassword) { store.dispatch(
store.dispatch( SaveUserSettingsRequest(
SaveUserSettingsRequest( completer: completer,
completer: completer, user: user,
user: user, ),
), );
);
} else {
passwordCallback(
context: context,
callback: (password) {
store.dispatch(
SaveUserSettingsRequest(
completer: completer,
user: user,
password: password,
),
);
});
}
}, },
onSettingsChanged: ({ onSettingsChanged: ({
String report, String report,

View File

@ -52,7 +52,7 @@ class UserDetailsVM {
}); });
if (state.authState.hasRecentlyEnteredPassword) { if (state.authState.hasRecentlyEnteredPassword) {
store.dispatch( store.dispatch(
SaveUserSettingsRequest( SaveAuthUserRequest(
completer: completer, completer: completer,
user: state.uiState.settingsUIState.user, user: state.uiState.settingsUIState.user,
), ),
@ -62,7 +62,7 @@ class UserDetailsVM {
context: context, context: context,
callback: (password) { callback: (password) {
store.dispatch( store.dispatch(
SaveUserSettingsRequest( SaveAuthUserRequest(
completer: completer, completer: completer,
user: state.uiState.settingsUIState.user, user: state.uiState.settingsUIState.user,
password: password, password: password,