diff --git a/lib/app/constant.dart b/lib/app/constant.dart index fc50c03..7e4a67c 100644 --- a/lib/app/constant.dart +++ b/lib/app/constant.dart @@ -262,11 +262,11 @@ class Constant { prt = "https://"; } - // baseUrl = "$protocol//devbandungraya.aplikasi.web.id/one-api/one_mitra/"; - // ipAddress = "devbandungraya.aplikasi.web.id"; - // protocol = protocol; - baseUrl = "$protocol//$text/one-api/one_mitra/"; - ipAddress = text; + baseUrl = "$protocol//devbandungraya.aplikasi.web.id/one-api/one_mitra/"; + ipAddress = "devbandungraya.aplikasi.web.id"; + protocol = protocol; + // baseUrl = "$protocol//$text/one-api/one_mitra/"; + // ipAddress = text; print(baseUrl); } } diff --git a/lib/model/aliases_model.dart b/lib/model/aliases_model.dart new file mode 100644 index 0000000..7f58824 --- /dev/null +++ b/lib/model/aliases_model.dart @@ -0,0 +1,44 @@ +class AliasesModel { + String? userAliasesID; + String? userAliasesUserID; + String? userAliasesTargetIP; + String? userAliasesTargetUserID; + String? userAliasesTargetUsername; + String? userAliasesTargetUrl; + String? userAliasesTargetRegionalID; + String? userAliasesTargetRegionalName; + + AliasesModel( + {this.userAliasesID, + this.userAliasesUserID, + this.userAliasesTargetIP, + this.userAliasesTargetUserID, + this.userAliasesTargetUsername, + this.userAliasesTargetUrl, + this.userAliasesTargetRegionalID, + this.userAliasesTargetRegionalName}); + + AliasesModel.fromJson(Map json) { + userAliasesID = json['userAliasesID']; + userAliasesUserID = json['userAliasesUserID']; + userAliasesTargetIP = json['userAliasesTargetIP']; + userAliasesTargetUserID = json['userAliasesTargetUserID']; + userAliasesTargetUsername = json['userAliasesTargetUsername']; + userAliasesTargetUrl = json['userAliasesTargetUrl']; + userAliasesTargetRegionalID = json['userAliasesTargetRegionalID']; + userAliasesTargetRegionalName = json['userAliasesTargetRegionalName']; + } + + Map toJson() { + final Map data = {}; + data['userAliasesID'] = userAliasesID; + data['userAliasesUserID'] = userAliasesUserID; + data['userAliasesTargetIP'] = userAliasesTargetIP; + data['userAliasesTargetUserID'] = userAliasesTargetUserID; + data['userAliasesTargetUsername'] = userAliasesTargetUsername; + data['userAliasesTargetUrl'] = userAliasesTargetUrl; + data['userAliasesTargetRegionalID'] = userAliasesTargetRegionalID; + data['userAliasesTargetRegionalName'] = userAliasesTargetRegionalName; + return data; + } +} diff --git a/lib/provider/aliases_provider.dart b/lib/provider/aliases_provider.dart new file mode 100644 index 0000000..d6f4993 --- /dev/null +++ b/lib/provider/aliases_provider.dart @@ -0,0 +1,59 @@ +import 'package:equatable/equatable.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'dio_provider.dart'; +import '../repository/aliases_repository.dart'; +import '../repository/base_repository.dart'; +import '../model/aliases_model.dart'; + + +abstract class AliasesState extends Equatable { + final DateTime date; + const AliasesState(this.date); + @override + List get props => [date]; +} + +class AliasesStateInit extends AliasesState { + AliasesStateInit() : super(DateTime.now()); +} + +class AliasesStateLoading extends AliasesState { + AliasesStateLoading() : super(DateTime.now()); +} + +class AliasesStateError extends AliasesState { + final String? message; + AliasesStateError({ + required this.message, + }) : super(DateTime.now()); +} + +class AliasesStateDone extends AliasesState { + final List model; + AliasesStateDone({ + required this.model, + }) : super(DateTime.now()); +} + +class AliasesNotifier extends StateNotifier { + final Ref ref; + AliasesNotifier({ + required this.ref, + }) : super(AliasesStateInit()); + + void getAliases({required String token}) async { + try { + state = AliasesStateLoading(); + final resp = await AliasesRepository(dio: ref.read(dioProvider)).getAliases(token: token); + state = AliasesStateDone(model: resp); + } catch (e) { + if (e is BaseRepositoryException) { + state = AliasesStateError(message: e.message ?? ""); + } else { + state = AliasesStateError(message: e.toString()); + } + } + } +} + +final aliasesDataProvider = StateNotifierProvider((ref) => AliasesNotifier(ref: ref)); \ No newline at end of file diff --git a/lib/provider/pindah_branch_provider.dart b/lib/provider/pindah_branch_provider.dart new file mode 100644 index 0000000..a3f23a3 --- /dev/null +++ b/lib/provider/pindah_branch_provider.dart @@ -0,0 +1,62 @@ +import 'package:equatable/equatable.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'dio_provider.dart'; +import '../repository/aliases_repository.dart'; +import '../repository/base_repository.dart'; + +abstract class ReqCabangState extends Equatable { + final DateTime date; + const ReqCabangState(this.date); + @override + List get props => [date]; +} + +class ReqCabangStateInit extends ReqCabangState { + ReqCabangStateInit() : super(DateTime.now()); +} + +class ReqCabangStateLoading extends ReqCabangState { + ReqCabangStateLoading() : super(DateTime.now()); +} + +class ReqCabangStateError extends ReqCabangState { + final String? message; + ReqCabangStateError({ + required this.message, + }) : super(DateTime.now()); +} + +class ReqCabangStateDone extends ReqCabangState { + final String model; + ReqCabangStateDone({ + required this.model, + }) : super(DateTime.now()); +} + +class ReqCabangNotifier extends StateNotifier { + final Ref ref; + ReqCabangNotifier({ + required this.ref, + }) : super(ReqCabangStateInit()); + + void requestTokenCabang({ + required String token, + required String userID, + required String username, + required String targetUrl + }) async { + try { + state = ReqCabangStateLoading(); + final resp = await AliasesRepository(dio: ref.read(dioProvider)).requestToken(token: token, userID: userID, username: username, targetUrl: targetUrl); + state = ReqCabangStateDone(model: resp); + } catch (e) { + if (e is BaseRepositoryException) { + state = ReqCabangStateError(message: e.message ?? ""); + } else { + state = ReqCabangStateError(message: e.toString()); + } + } + } +} + +final reqCabangTokenProvider = StateNotifierProvider((ref) => ReqCabangNotifier(ref: ref)); \ No newline at end of file diff --git a/lib/repository/aliases_repository.dart b/lib/repository/aliases_repository.dart new file mode 100644 index 0000000..fd26ef8 --- /dev/null +++ b/lib/repository/aliases_repository.dart @@ -0,0 +1,49 @@ + +import '../app/constant.dart'; +import '../model/aliases_model.dart'; +import 'base_repository.dart'; + +class AliasesRepository extends BaseRepository { + AliasesRepository({required super.dio}); + + Future> getAliases({required String token}) async { + final param = {"token": token}; + final service = "${Constant.baseUrl}authchange/getuseraliases"; + final resp = await post(param: param, service: service); + + var aliases = []; + + if (resp['status'] == 'OK') { + resp['data'].forEach((v) { + aliases.add(AliasesModel.fromJson(v)); + }); + } else { + + } + + return aliases; + } + + Future requestToken({ + required String token, + required String userID, + required String username, + required String targetUrl, + }) async { + final param = { + "token": token, + "userID": userID, + "username": username, + "targetUrl": targetUrl + }; + + final service = "${Constant.baseUrl}authchange/request_mitra_token"; + final resp = await post(param: param, service: service); + + if (resp['status'] == "OK") { + return resp['data']; + } else { + return resp['message']; + } + } +} \ No newline at end of file diff --git a/lib/screen/login/login_box.dart b/lib/screen/login/login_box.dart index 0781061..b53d3be 100644 --- a/lib/screen/login/login_box.dart +++ b/lib/screen/login/login_box.dart @@ -1,5 +1,7 @@ import 'dart:convert'; +import 'dart:html' as html; +import 'package:dart_jsonwebtoken/dart_jsonwebtoken.dart'; import 'package:eva_icons_flutter/eva_icons_flutter.dart'; import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; @@ -36,14 +38,28 @@ class LoginBox extends HookConsumerWidget { final regionalLoading = useState(false); final isLoading = useState(false); final errorMsg = useState(""); + getPref() async { final SharedPreferences prefs = await SharedPreferences.getInstance(); - final String? getData = prefs.getString(Constant.tokenName); - print(getData); - if (getData != null) { - ref.read(authProvider.notifier).state = - AuthModel.fromJson(jsonDecode(getData)); + final Uri currentUrl = Uri.parse(html.window.location.href); + final String? token = currentUrl.queryParameters['token']; + + if (token != null) { + final jwt = JWT.decode(token); + final payload = jwt.payload; + AuthModel user = AuthModel.fromJson(payload); + user.token = token; + ref.read(authProvider.notifier).state = user; Navigator.pushNamed(context, homeRoute); + + } else { + final String? getData = prefs.getString(Constant.tokenName); + print(getData); + if (getData != null) { + ref.read(authProvider.notifier).state = + AuthModel.fromJson(jsonDecode(getData)); + Navigator.pushNamed(context, homeRoute); + } } } diff --git a/lib/screen/login/login_screen.dart b/lib/screen/login/login_screen.dart index e8f8a95..0ef54aa 100644 --- a/lib/screen/login/login_screen.dart +++ b/lib/screen/login/login_screen.dart @@ -1,10 +1,11 @@ import 'package:flutter/material.dart'; -import 'package:mitra_corporate/screen/login/login_box.dart'; - +import 'login_box.dart'; import '../../app/constant.dart'; class LoginScreen extends StatelessWidget { const LoginScreen({super.key}); + + @override Widget build(BuildContext context) { return Material( diff --git a/lib/widgets/header.dart b/lib/widgets/header.dart index 49819a2..9c19228 100644 --- a/lib/widgets/header.dart +++ b/lib/widgets/header.dart @@ -4,7 +4,10 @@ import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:intl/date_symbol_data_local.dart'; import 'package:intl/intl.dart'; +import 'package:mitra_corporate/model/aliases_model.dart'; +import 'package:mitra_corporate/provider/aliases_provider.dart'; import 'package:mitra_corporate/provider/menu_provider.dart'; +import 'package:mitra_corporate/provider/pindah_branch_provider.dart'; import 'package:mitra_corporate/widgets/custom_text_field.dart'; import 'package:loading_animation_widget/loading_animation_widget.dart'; import 'package:shared_preferences/shared_preferences.dart'; @@ -14,6 +17,7 @@ import '../app/route.dart'; import '../provider/auth_provider.dart'; import '../screen/login/change_password_provider.dart'; import '../screen/login/logout_provider.dart'; +import 'dart:html' as html; import 'custom_snackbar_widget.dart'; class Header extends HookConsumerWidget { @@ -27,6 +31,8 @@ class Header extends HookConsumerWidget { final isExpand = ref.watch(sideBarExpandProvider); final auth = ref.watch(authProvider); final date = useState(""); + final listAliases = useState>(List.empty()); + ref.listen(logoutProvider, (prev, next) async { if (next is LogoutStateLoading) { } else if (next is LogoutStateError) { @@ -41,6 +47,13 @@ class Header extends HookConsumerWidget { } } }); + + fetchAliases() async { + String token = auth?.token ?? "0"; + + ref.read(aliasesDataProvider.notifier).getAliases(token: token); + } + useEffect(() { WidgetsBinding.instance.addPostFrameCallback((timeStamp) async { DateTime now = DateTime.now(); @@ -48,9 +61,45 @@ class Header extends HookConsumerWidget { date.value = DateFormat('EEEE, d MMMM yyyy', "id").format(now); print(DateFormat('EEEE, d MMMM yyyy', "id").format(now)); }); + fetchAliases(); }); return () {}; }, []); + + ref.listen(aliasesDataProvider, (pref, next) { + if (next is AliasesStateInit) { + + } else if (next is AliasesStateLoading) { + + } else if (next is AliasesStateError) { + SanckbarWidget(context, next.message ?? "", snackbarType.error); + } else if (next is AliasesStateDone) { + listAliases.value = next.model; + } + }); + + void openNewTab(String url) { + html.window.open(url, '_blank'); + } + + moveBranch(String userID, String username, String targetUrl) { + String token = auth?.token ?? "0"; + ref.read(reqCabangTokenProvider.notifier).requestTokenCabang(token: token, userID: userID, username: username, targetUrl: targetUrl); + } + + ref.listen(reqCabangTokenProvider, (prev, next) { + if (next is ReqCabangStateInit) { + + } else if (next is ReqCabangStateLoading) { + + } else if (next is ReqCabangStateError) { + SanckbarWidget(context, next.message ?? "", snackbarType.error); + } else if (next is ReqCabangStateDone) { + var url = next.model; + openNewTab("http://${url}"); + } + }); + return Container( color: Colors.white, alignment: Alignment.center, @@ -185,6 +234,27 @@ class Header extends HookConsumerWidget { style: Constant.body3_400(context: context), ), ), + ...listAliases.value.isEmpty + ? [] + : listAliases.value.map((alias) { + return MenuItemButton( + leadingIcon: Icon( + EvaIcons.globe2Outline, + color: Constant.primaryRed, + ), + child: Text( + alias.userAliasesTargetRegionalName ?? '', + style: Constant.body3_400(context: context), + ), + onPressed: () { + moveBranch( + alias.userAliasesTargetUserID ?? "", + alias.userAliasesTargetUsername ?? "", + alias.userAliasesTargetIP ?? "" + ); + }, + ); + }).toList(), Container( margin: EdgeInsets.only(top: 10, bottom: 10), child: Center( diff --git a/pubspec.lock b/pubspec.lock index 46f5a40..666a1c3 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1,6 +1,14 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: + adaptive_number: + dependency: transitive + description: + name: adaptive_number + sha256: "3a567544e9b5c9c803006f51140ad544aedc79604fd4f3f2c1380003f97c1d77" + url: "https://pub.dev" + source: hosted + version: "1.0.0" age_calculator: dependency: "direct main" description: @@ -81,6 +89,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.18.0" + convert: + dependency: transitive + description: + name: convert + sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68 + url: "https://pub.dev" + source: hosted + version: "3.1.2" crypto: dependency: transitive description: @@ -97,6 +113,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.0" + dart_jsonwebtoken: + dependency: "direct main" + description: + name: dart_jsonwebtoken + sha256: "866787dc17afaef46a9ea7dd33eefe60c6d82084b4a36d70e8e788d091cd04ef" + url: "https://pub.dev" + source: hosted + version: "2.14.2" data_table_2: dependency: "direct main" description: @@ -145,6 +169,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.0" + ed25519_edwards: + dependency: transitive + description: + name: ed25519_edwards + sha256: "6ce0112d131327ec6d42beede1e5dfd526069b18ad45dcf654f15074ad9276cd" + url: "https://pub.dev" + source: hosted + version: "0.3.1" equatable: dependency: "direct main" description: @@ -405,6 +437,14 @@ packages: url: "https://pub.dev" source: hosted version: "6.3.1" + js: + dependency: transitive + description: + name: js + sha256: c1b2e9b5ea78c45e1a0788d29606ba27dc5f71f019f32ca5140f61ef071838cf + url: "https://pub.dev" + source: hosted + version: "0.7.1" just_the_tooltip: dependency: "direct main" description: @@ -629,6 +669,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.10.2+1" + pointycastle: + dependency: transitive + description: + name: pointycastle + sha256: "4be0097fcf3fd3e8449e53730c631200ebc7b88016acecab2b0da2f0149222fe" + url: "https://pub.dev" + source: hosted + version: "3.9.1" riverpod: dependency: transitive description: @@ -910,10 +958,10 @@ packages: dependency: transitive description: name: vm_service - sha256: f652077d0bdf60abe4c1f6377448e8655008eef28f128bc023f7b5e8dfeb48fc + sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d" url: "https://pub.dev" source: hosted - version: "14.2.4" + version: "14.2.5" web: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index f0751e8..b3530b8 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -46,6 +46,7 @@ dependencies: # Use with the CupertinoIcons class for iOS style icons. eva_icons_flutter: ^3.1.0 url_launcher: ^6.1.11 + dart_jsonwebtoken: ^2.14.2 dev_dependencies: flutter_test: