diff --git a/lib/data/models/entities.dart b/lib/data/models/entities.dart index 403a547b2..602170862 100644 --- a/lib/data/models/entities.dart +++ b/lib/data/models/entities.dart @@ -49,6 +49,8 @@ class CompanyEntity extends Object with _$CompanyEntitySerializerMixin { CompanyEntity(this.id); factory CompanyEntity.fromJson(Map json) => _$CompanyEntityFromJson(json); + + bool isBlank() => this.token == null; } diff --git a/lib/data/repositories/auth_repository.dart b/lib/data/repositories/auth_repository.dart index 5fe848e3e..d9b03001d 100644 --- a/lib/data/repositories/auth_repository.dart +++ b/lib/data/repositories/auth_repository.dart @@ -1,5 +1,6 @@ import 'dart:async'; import 'dart:core'; +import 'dart:convert'; import 'package:meta/meta.dart'; import 'package:invoiceninja/redux/auth/auth_state.dart'; @@ -20,7 +21,7 @@ class AuthRepositoryFlutter { /// Loads products first from File storage. If they don't exist or encounter an /// error, it attempts to load the Products from a Web Client. - Future> login(String email, String password, String url) async { + Future> login(String email, String password, String url) async { final data = await webClient.postList(url + '/login', '', { 'api_secret': 'secret', diff --git a/lib/data/repositories/dashboard_repository.dart b/lib/data/repositories/dashboard_repository.dart index b94df6d46..bb443b403 100644 --- a/lib/data/repositories/dashboard_repository.dart +++ b/lib/data/repositories/dashboard_repository.dart @@ -18,7 +18,7 @@ class DashboardRepositoryFlutter { this.webClient = const WebClient(), }); - Future loadItem(CompanyEntity company, AuthState auth) async { + Future loadItem(CompanyEntity company, AuthState auth) async { final data = await webClient.fetchItem( auth.url + '/dashboard', company.token); diff --git a/lib/data/repositories/product_repository.dart b/lib/data/repositories/product_repository.dart index dcf0508a2..24f59a857 100644 --- a/lib/data/repositories/product_repository.dart +++ b/lib/data/repositories/product_repository.dart @@ -18,7 +18,7 @@ class ProductsRepositoryFlutter { this.webClient = const WebClient(), }); - Future> loadList(CompanyEntity company, AuthState auth) async { + Future> loadList(CompanyEntity company, AuthState auth) async { final products = await webClient.fetchList( auth.url + '/products', company.token); diff --git a/lib/data/web_client.dart b/lib/data/web_client.dart index a83a2bf41..3d984b888 100644 --- a/lib/data/web_client.dart +++ b/lib/data/web_client.dart @@ -49,7 +49,7 @@ class WebClient { } - Future postList(String url, String token, var data) async { + Future> postList(String url, String token, var data) async { final http.Response response = await sendPostRequest(url, token, data); //print(response.body); diff --git a/lib/redux/app/app_reducer.dart b/lib/redux/app/app_reducer.dart index c068ea110..e8c0683c5 100644 --- a/lib/redux/app/app_reducer.dart +++ b/lib/redux/app/app_reducer.dart @@ -24,16 +24,16 @@ AppState appReducer(AppState state, action) { selectedCompanyId: selectedCompanyIdReducer(state.selectedCompanyId, action), isLoading: loadingReducer(state.isLoading, action), auth: authReducer(state.auth, action), - company1: state.selectedCompanyId == 1 - ? companyReducer(state.company1, action) : state.company1, - company2: state.selectedCompanyId == 2 - ? companyReducer(state.company2, action) : state.company2, - company3: state.selectedCompanyId == 3 - ? companyReducer(state.company3, action) : state.company3, - company4: state.selectedCompanyId == 4 - ? companyReducer(state.company4, action) : state.company4, - company5: state.selectedCompanyId == 5 - ? companyReducer(state.company5, action) : state.company5, + companyState1: state.selectedCompanyId == 1 + ? companyReducer(state.companyState1, action) : state.companyState1, + companyState2: state.selectedCompanyId == 2 + ? companyReducer(state.companyState2, action) : state.companyState2, + companyState3: state.selectedCompanyId == 3 + ? companyReducer(state.companyState3, action) : state.companyState3, + companyState4: state.selectedCompanyId == 4 + ? companyReducer(state.companyState4, action) : state.companyState4, + companyState5: state.selectedCompanyId == 5 + ? companyReducer(state.companyState5, action) : state.companyState5, ); } diff --git a/lib/redux/app/app_state.dart b/lib/redux/app/app_state.dart index 618f67961..aa5574892 100644 --- a/lib/redux/app/app_state.dart +++ b/lib/redux/app/app_state.dart @@ -10,27 +10,27 @@ class AppState { final bool isLoading; final AuthState auth; final int selectedCompanyId; - final CompanyState company1; - final CompanyState company2; - final CompanyState company3; - final CompanyState company4; - final CompanyState company5; + final CompanyState companyState1; + final CompanyState companyState2; + final CompanyState companyState3; + final CompanyState companyState4; + final CompanyState companyState5; AppState( {this.isLoading = false, this.selectedCompanyId = 0, AuthState auth, - CompanyState company1, - CompanyState company2, - CompanyState company3, - CompanyState company4, - CompanyState company5,}) : + CompanyState companyState1, + CompanyState companyState2, + CompanyState companyState3, + CompanyState companyState4, + CompanyState companyState5,}) : auth = auth ?? AuthState(), - company1 = company1 ?? CompanyState(), - company2 = company2 ?? CompanyState(), - company3 = company3 ?? CompanyState(), - company4 = company4 ?? CompanyState(), - company5 = company5 ?? CompanyState(); + companyState1 = companyState1 ?? CompanyState(), + companyState2 = companyState2 ?? CompanyState(), + companyState3 = companyState3 ?? CompanyState(), + companyState4 = companyState4 ?? CompanyState(), + companyState5 = companyState5 ?? CompanyState(); factory AppState.loading() => AppState(isLoading: true); @@ -47,21 +47,21 @@ class AppState { String selectedCompany, bool isLoading, AuthState auth, - CompanyState company1, - CompanyState company2, - CompanyState company3, - CompanyState company4, - CompanyState company5, + CompanyState companyState1, + CompanyState companyState2, + CompanyState companyState3, + CompanyState companyState4, + CompanyState companyState5, }) { return AppState( selectedCompanyId : selectedCompany ?? this.selectedCompanyId, isLoading: isLoading ?? this.isLoading, auth: auth ?? this.auth, - company1: company1 ?? this.company1, - company2: company2 ?? this.company2, - company3: company3 ?? this.company3, - company4: company4 ?? this.company4, - company5: company5 ?? this.company5, + companyState1: companyState1 ?? this.companyState1, + companyState2: companyState2 ?? this.companyState2, + companyState3: companyState3 ?? this.companyState3, + companyState4: companyState4 ?? this.companyState4, + companyState5: companyState5 ?? this.companyState5, ); } @@ -70,11 +70,11 @@ class AppState { selectedCompanyId.hashCode ^ isLoading.hashCode ^ auth.hashCode ^ - company1.hashCode ^ - company2.hashCode ^ - company3.hashCode ^ - company4.hashCode ^ - company5.hashCode; + companyState1.hashCode ^ + companyState2.hashCode ^ + companyState3.hashCode ^ + companyState4.hashCode ^ + companyState5.hashCode; @override bool operator == (Object other) => @@ -82,33 +82,33 @@ class AppState { other is AppState && runtimeType == other.runtimeType && selectedCompanyId == other.selectedCompanyId && - company1 == other.company1 && - company2 == other.company2 && - company3 == other.company3 && - company4 == other.company4 && - company5 == other.company5 && + companyState1 == other.companyState1 && + companyState2 == other.companyState2 && + companyState3 == other.companyState3 && + companyState4 == other.companyState4 && + companyState5 == other.companyState5 && auth == other.auth; @override String toString() { - return 'AppState{isLoading: $isLoading, url: ${auth.url}, companyId: ${selectedCompanyId}, company1: ${company1.company.name}, company2: ${company2.company.name}'; + return 'AppState{isLoading: $isLoading, url: ${auth.url}, companyId: ${selectedCompanyId}, company1: ${companyState1.company.name}, company2: ${companyState2.company.name}'; } CompanyState selectedCompanyState() { switch (this.selectedCompanyId) { case 1: - return this.company1; + return this.companyState1; case 2: - return this.company2; + return this.companyState2; case 3: - return this.company3; + return this.companyState3; case 4: - return this.company4; + return this.companyState4; case 5: - return this.company5; + return this.companyState5; } - return this.company1; + return this.companyState1; } CompanyEntity selectedCompany() { diff --git a/lib/redux/auth/auth_middleware.dart b/lib/redux/auth/auth_middleware.dart index 972cd1ed4..8f176b0bd 100644 --- a/lib/redux/auth/auth_middleware.dart +++ b/lib/redux/auth/auth_middleware.dart @@ -50,7 +50,6 @@ Middleware _createLoginRequest(AuthRepositoryFlutter repository) { store.dispatch(SelectCompany(1)); store.dispatch(UserLoginSuccess()); - //store.dispatch(LoadDashboardAction()); Navigator.of(action.context).pushNamed(AppRoutes.dashboard); } @@ -59,14 +58,3 @@ Middleware _createLoginRequest(AuthRepositoryFlutter repository) { next(action); }; } - - -/* -Middleware _createLoginSuccess() { - return (Store store, action, NextDispatcher next) { - - - next(action); - }; -} -*/ \ No newline at end of file diff --git a/lib/redux/company/company_selectors.dart b/lib/redux/company/company_selectors.dart new file mode 100644 index 000000000..793ec71d5 --- /dev/null +++ b/lib/redux/company/company_selectors.dart @@ -0,0 +1,24 @@ +import 'package:invoiceninja/data/models/models.dart'; +import 'package:invoiceninja/redux/app/app_state.dart'; + +List companiesSelector(AppState state) { + List list = []; + + if (! state.companyState1.company.isBlank()) { + list.add(state.companyState1.company); + } + if (! state.companyState2.company.isBlank()) { + list.add(state.companyState2.company); + } + if (! state.companyState3.company.isBlank()) { + list.add(state.companyState3.company); + } + if (! state.companyState4.company.isBlank()) { + list.add(state.companyState4.company); + } + if (! state.companyState5.company.isBlank()) { + list.add(state.companyState5.company); + } + + return list; +} \ No newline at end of file diff --git a/lib/redux/company/company_state.dart b/lib/redux/company/company_state.dart index abd042a1a..0d1fea46b 100644 --- a/lib/redux/company/company_state.dart +++ b/lib/redux/company/company_state.dart @@ -5,7 +5,7 @@ import 'package:invoiceninja/data/models/entities.dart'; @immutable class CompanyState { - CompanyEntity company; + final CompanyEntity company; final ProductState productState; final DashboardState dashboardState; diff --git a/lib/ui/app/custom_drawer.dart b/lib/ui/app/custom_drawer.dart index 3d2ad8a2a..e8846aa7b 100644 --- a/lib/ui/app/custom_drawer.dart +++ b/lib/ui/app/custom_drawer.dart @@ -1,16 +1,50 @@ import 'package:flutter/material.dart'; import 'package:invoiceninja/routes.dart'; +import 'package:invoiceninja/data/models/entities.dart'; class CustomDrawer extends StatelessWidget { final String companyName; + final bool hasMultipleCompanies; + final List companies; CustomDrawer({ Key key, @required this.companyName, + @required this.hasMultipleCompanies, + @required this.companies, }) : super(key: key); @override Widget build(BuildContext context) { + final _singleCompany = Align( + alignment: FractionalOffset.bottomLeft, + child: Text(companyName), + ); + + final _multipleCompanies = Align( + alignment: FractionalOffset.bottomLeft, + child: new DropdownButton( + items: this.companies.map((CompanyEntity company) => + DropdownMenuItem( + value: company.id.toString(), + child: Text(company.id.toString()), + ) + ).toList(), + onChanged: (_) { + + }, + ), + /* + child: DropdownButton( + items: this.companies.map((CompanyEntity company) { + return DropdownMenuItem( + child: Text(company.name), + ); + }), + ), + */ + ); + return Drawer( child: ListView( children: [ @@ -23,7 +57,7 @@ class CustomDrawer extends StatelessWidget { child: Text('Logo'), ), ), - Text(this.companyName), + this.companies.length > 1 ? _multipleCompanies : _singleCompany, ], )), color: Colors.white10, diff --git a/lib/ui/app/custom_drawer_vm.dart b/lib/ui/app/custom_drawer_vm.dart index bc9ed9f10..6ae5f2f01 100644 --- a/lib/ui/app/custom_drawer_vm.dart +++ b/lib/ui/app/custom_drawer_vm.dart @@ -2,11 +2,10 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_redux/flutter_redux.dart'; import 'package:redux/redux.dart'; -import 'package:invoiceninja/redux/dashboard/dashboard_actions.dart'; -import 'package:invoiceninja/data/models/models.dart'; import 'package:invoiceninja/ui/app/custom_drawer.dart'; import 'package:invoiceninja/redux/app/app_state.dart'; -import 'package:invoiceninja/redux/dashboard/dashboard_state.dart'; +import 'package:invoiceninja/redux/company/company_selectors.dart'; +import 'package:invoiceninja/data/models/models.dart'; class CustomDrawerVM extends StatelessWidget { CustomDrawerVM({Key key}) : super(key: key); @@ -18,6 +17,8 @@ class CustomDrawerVM extends StatelessWidget { builder: (context, vm) { return CustomDrawer( companyName: vm.companyName, + hasMultipleCompanies: vm.hasMultipleCompanies, + companies: vm.companies, ); }, ); @@ -26,14 +27,20 @@ class CustomDrawerVM extends StatelessWidget { class _ViewModel { final String companyName; + final bool hasMultipleCompanies; + final List companies; _ViewModel({ @required this.companyName, - }); + @required this.hasMultipleCompanies, + @required this.companies, +}); static _ViewModel fromStore(Store store) { return _ViewModel( companyName: store.state.selectedCompany().name, + hasMultipleCompanies: store.state.companyState2.company.token != null, + companies: companiesSelector(store.state), ); } } diff --git a/lib/ui/client/clients.dart b/lib/ui/client/clients.dart index 990d55273..3d34c7c48 100644 --- a/lib/ui/client/clients.dart +++ b/lib/ui/client/clients.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; import 'package:invoiceninja/keys.dart'; -import 'package:invoiceninja/ui/app/custom_drawer.dart'; +import 'package:invoiceninja/ui/app/custom_drawer_vm.dart'; class ClientList extends StatelessWidget { ClientList() : super(key: NinjaKeys.clientList); @@ -11,7 +11,7 @@ class ClientList extends StatelessWidget { appBar: new AppBar( title: new Text('Clients'), ), - drawer: new CustomDrawer(), + drawer: new CustomDrawerVM(), body: new Center( child: new Column( mainAxisAlignment: MainAxisAlignment.center,