Yulian vor 1 Monat
Ursprung
Commit
c06ab20812

+ 2 - 1
assets/lang/ar.json

@@ -332,5 +332,6 @@
   "endSessionDesc": "عذراً، يبدو أنك لم تستخدم التطبيق لفترة. لأمانك، يرجى تسجيل الدخول مرة أخرى قبل المتابعة.",
   "invalidParentTicket": "رقم المرجع غير صالح.",
   "failedLoad": "فشل تحميل التطبيق.",
-  "tap2retry": "اضغط لإعادة المحاولة."
+  "tap2retry": "اضغط لإعادة المحاولة.",
+  "chat": "محادثة"
 }

+ 2 - 1
assets/lang/de.json

@@ -332,5 +332,6 @@
   "endSessionDesc": "Oh, Entschuldigung. Es sieht so aus, als hätten Sie die App eine Weile nicht benutzt. Bitte melden Sie sich erneut an, um fortzufahren.",
   "invalidParentTicket": "Ungültige Referenznummer.",
   "failedLoad": "App konnte nicht geladen werden.",
-  "tap2retry": "Tippen, um es erneut zu versuchen."
+  "tap2retry": "Tippen, um es erneut zu versuchen.",
+  "chat": "Gespräch"
 }

+ 2 - 1
assets/lang/en.json

@@ -332,5 +332,6 @@
    "endSessionDesc": "Oops, sorry. We have not see you for along time. It\\'s kindly your session has expired. Please re-login to continue using application.",
    "invalidParentTicket": "Invalid parent ticket.",
    "failedLoad": "Failed to load Application.",
-   "tap2retry": "Tap to retry."
+   "tap2retry": "Tap to retry.",
+   "chat": "Chat"
 }

+ 2 - 1
assets/lang/fr.json

@@ -332,5 +332,6 @@
   "endSessionDesc": "Oh, désolé. Il semble que vous n'ayez pas utilisé l'application depuis un moment. Pour des raisons de sécurité, veuillez vous reconnecter avant de continuer.",
   "invalidParentTicket": "Numéro de référence invalide.",
   "failedLoad": "Échec du chargement de l'application.",
-  "tap2retry": "Appuyez pour réessayer."
+  "tap2retry": "Appuyez pour réessayer.",
+  "chat": "Conversation"
 }

+ 2 - 1
assets/lang/hi.json

@@ -332,5 +332,6 @@
   "endSessionDesc": "ओह, क्षमा करें। ऐसा लगता है कि आपने ऐप का लंबे समय से उपयोग नहीं किया है। कृपया आगे बढ़ने से पहले फिर से लॉगिन करें।",
   "invalidParentTicket": "अमान्य संदर्भ संख्या।",
   "failedLoad": "ऐप लोड करने में विफल।",
-  "tap2retry": "पुनः प्रयास करने के लिए टैप करें।"
+  "tap2retry": "पुनः प्रयास करने के लिए टैप करें।",
+  "chat": "बातचीत"
 }

+ 2 - 1
assets/lang/id.json

@@ -332,5 +332,6 @@
    "endSessionDesc": "Oh, maaf. Sepertinya kamu sudah lama tidak menggunakan aplikasi. Biar aman silakan login ulang sebelum lanjut.",
    "invalidParentTicket": "Nomor referensi tidak valid.",
    "failedLoad": "Gagal memuat aplikasi.",
-   "tap2retry": "Ketuk untuk mencoba kembali."
+   "tap2retry": "Ketuk untuk mencoba kembali.",
+   "chat": "Percakapan"
 }

+ 2 - 1
assets/lang/ja.json

@@ -330,5 +330,6 @@
    "requestReference": "リクエストリファレンス",
    "invalidParentTicket": "親チケットが無効です。",
    "failedLoad": "アプリケーションのロードに失敗しました。",
-   "tap2retry": "タップして再試行します。"
+   "tap2retry": "タップして再試行します。",
+   "chat": "会話"
 }

+ 2 - 1
assets/lang/ko.json

@@ -330,5 +330,6 @@
    "requestReference": "참조 요청",
    "invalidParentTicket": "부모 티켓이 유효하지 않습니다.",
    "failedLoad": "애플리케이션을 로드하지 못했습니다.",
-   "tap2retry": "다시 시도하려면 탭하세요."
+   "tap2retry": "다시 시도하려면 탭하세요.",
+   "chat": "대화"
 }

+ 2 - 1
assets/lang/nl.json

@@ -332,5 +332,6 @@
   "endSessionDesc": "Oeps, het lijkt erop dat je de app al een tijdje niet hebt gebruikt. Log opnieuw in om verder te gaan.",
   "invalidParentTicket": "Ongeldig referentienummer.",
   "failedLoad": "App kon niet worden geladen.",
-  "tap2retry": "Tik om opnieuw te proberen."
+  "tap2retry": "Tik om opnieuw te proberen.",
+  "chat": "Gesprek"
 }

+ 2 - 1
assets/lang/zh.json

@@ -330,5 +330,6 @@
    "requestReference": "请求参考",
    "invalidParentTicket": "父母票无效。",
    "failedLoad": "无法加载应用程序。",
-   "tap2retry": "点击重试。"
+   "tap2retry": "点击重试。",
+   "chat": "对话"
 }

+ 1 - 1
lib/app_router.dart

@@ -105,7 +105,7 @@ class AppRouter extends RootStackRouter {
             var ver = await U.reloadLicense();
             await _sharedPreferencesManager.putInt(SharedPreferencesManager.version, ver['version']);
           } catch (e) {
-            print('error sini 2: ${e.toString()}');
+            print('Error get2: ${e.toString()}');
             await _sharedPreferencesManager.clearKey(SharedPreferencesManager.keyBaseUrl);
             await _sharedPreferencesManager.clearKey(SharedPreferencesManager.keyAccessCode);
             await _sharedPreferencesManager.clearKey(SharedPreferencesManager.keySerialCode);

+ 2 - 2
lib/main.dart

@@ -161,7 +161,7 @@ class _HomeGuardPageState extends State<HomeGuardPage> {
   @override
   Widget build(BuildContext context) {
     eventBus.on().listen((event) {
-      print("eventBus => ${event.toString()}");
+      // print("eventBus => ${event.toString()}");
       if(event.toString() == 'logout') {
         // token.logout();
         context.navigateToPath('/end-session');
@@ -196,7 +196,7 @@ class NotificationClass {
       // print(token);
       if (token != null) {
         _apiAuthProvider.postDataNoAuth('/api/notifications/received/$token/$mid').then((value) =>
-            print('sukses kirim confirm')
+            print('Send confirm succes!')
         );
       }
 

+ 3 - 3
lib/src/api/api_auth_provider.dart

@@ -185,7 +185,7 @@ class ApiAuthProvider {
         }
       } else if (error.response!.statusCode! >= 500) {
         if (secondCheck) {
-          print('secondCheck');
+          // print('secondCheck');
           handlingError(context, 2); //error connection
         } else {
           await Future.delayed(Duration(milliseconds: 200));
@@ -196,7 +196,7 @@ class ApiAuthProvider {
         handlingError(context, 3); //error auth
       } else {
         if (secondCheck) {
-          print('secondCheck');
+          // print('secondCheck');
           handlingError(context, 2); //error connection
         } else {
           await Future.delayed(Duration(milliseconds: 200));
@@ -242,7 +242,7 @@ class ApiAuthProvider {
       } else {
         if(!isOpen){
           if (secondCheck) {
-            print('secondCheck');
+            // print('secondCheck');
             handlingError(context, 2); //error connection
           } else {
             return getData(path, params, context, secondCheck: true);

+ 19 - 18
lib/src/layouts/auth/login.dart

@@ -14,6 +14,7 @@ import 'package:telnow_mobile_new/src/injector/injector.dart';
 import 'package:telnow_mobile_new/src/layouts/components/template.dart';
 import 'package:telnow_mobile_new/src/model/login/login_body.dart';
 import 'package:telnow_mobile_new/src/storage/sharedpreferences/shared_preferences_manager.dart';
+import 'package:telnow_mobile_new/src/utils/C.dart';
 import 'package:telnow_mobile_new/src/utils/U.dart';
 import 'package:telnow_mobile_new/src/utils/cache_manager.dart';
 import 'package:toggle_switch/toggle_switch.dart';
@@ -47,6 +48,7 @@ class _LoginPageState extends State<LoginPage> {
   @override
   void initState() {
     try{imageUrl = apiAuthProvider.baseUrl + U.decodeBase64Url(Uri.decodeComponent(U.getAccessCode()!))+'/assets/background/tn';}catch(e){}
+    U.getServerVersion();
     getCompanyName();
     // TODO: implement initState
     super.initState();
@@ -54,17 +56,16 @@ class _LoginPageState extends State<LoginPage> {
 
   getCompanyName() async {
     var lics = await U.reloadLicense();
-    if (lics != null && mounted) {
-      setState(() {
-        companyName = lics['companyName']??'';
-        serialNumber = lics['serialNumber']??'';
-        companyLogo = lics['logo']??'';
-        if(U.newServerVersion(1754624839)){
-          lang = lics['_validLang'] ?? [];
-        } else if(1698720817 <= lics['serverVersion']){
-          lang = lics['languages'] != null ? lics['languages'].split(',') : [];
-        }
-      });
+    if (lics != null) {
+      companyName = lics['companyName']??'';
+      serialNumber = lics['serialNumber']??'';
+      companyLogo = lics['logo']??'';
+      if(U.isCompatibleWith(VersionKey.multiBahasa)){
+        lang = lics['_validLang'] ?? [];
+      } else if(1698720817 <= lics['serverVersion']){
+        lang = lics['languages'] != null ? lics['languages'].split(',') : [];
+      }
+      if(mounted) setState(() {});
     }
   }
 
@@ -98,7 +99,7 @@ class _LoginPageState extends State<LoginPage> {
                         // padding: EdgeInsets.symmetric(horizontal: 16),
                         children: [
                           backButton(),
-                          langWdgt()
+                          langWidget()
                         ],
                       ),
                     ),
@@ -196,15 +197,19 @@ class _LoginPageState extends State<LoginPage> {
     );
   }
 
-  Widget langWdgt(){
+  Widget langWidget(){
     return Center(
       child: Container(
         margin: EdgeInsets.only(right: 16),
         child: Align(
           alignment: Alignment.topRight,
-          child: lang.length > 0 ? GestureDetector(
+          child: lang.isNotEmpty ? GestureDetector(
             child: Container(
               width: 65, height: 30, padding: EdgeInsets.symmetric(horizontal: 10),
+              decoration: BoxDecoration(
+                  color: Colors.deepOrange,
+                  borderRadius: BorderRadius.all(Radius.circular(50))
+              ),
               child: Row(
                 mainAxisAlignment: MainAxisAlignment.spaceBetween,
                 children: [
@@ -212,10 +217,6 @@ class _LoginPageState extends State<LoginPage> {
                   Text(context.locale.toString().toUpperCase(), style: TextStyle(color: Colors.white, fontSize: 15, fontWeight: FontWeight.bold))
                 ],
               ),
-              decoration: BoxDecoration(
-                  color: Colors.deepOrange,
-                  borderRadius: BorderRadius.all(Radius.circular(50))
-              ),
             ),
             onTap: () => changeLangLogin(context, lang),
           ) : ToggleSwitch(

+ 7 - 4
lib/src/layouts/components/template.dart

@@ -99,8 +99,11 @@ Widget textHorizontal(String title, String subtitle, {double size = 14, double o
   );
 }
 
-Widget divider({opacity = 0.15}){
-  return Divider(height: 1, thickness: 1, color: textColor.withValues(alpha: opacity));
+Widget divider({opacity = 0.15, EdgeInsetsGeometry padding = const EdgeInsets.only(top: 0)}){
+  return Padding(
+    padding: padding,
+    child: Divider(height: 1, thickness: 1, color: textColor.withValues(alpha: opacity)),
+  );
 }
 
 Widget dashed({double top = 8, double bottom = 8, double left = 0, double right = 0, Color color = textColor, double width = double.infinity}){
@@ -492,7 +495,7 @@ navigateTo(BuildContext context, child){
 }
 
 navigateToThen(BuildContext context, child, act){
-  return Navigator.push(context, PageTransition(type: PageTransitionType.rightToLeft, child: child)).then((v) => act());
+  Navigator.push(context, PageTransition(type: PageTransitionType.rightToLeft, child: child)).then((v) => act());
 }
 
 navigateBack(BuildContext context, {exc = false}){
@@ -529,7 +532,7 @@ void showSuccess(context, message) {
   )..show(context);
 }
 
-String convertDate(date, locale) {
+String convertDate(date, String locale) {
   if (date == "-" || date.isEmpty) {
     return date;
   }

+ 1 - 3
lib/src/layouts/functions/account.dart

@@ -39,7 +39,7 @@ class AccountFunction{
     }
     try{
       var p;
-      if(U.isCompatibleWith(VKey.multiBahasa)){
+      if(U.isCompatibleWith(VersionKey.multiBahasa)){
         p = {'userId': user['userId'], 'language': 'ID', '_language': code.toUpperCase()};
       } else {
         p = {'userId': user['userId'], 'language': code.toUpperCase()};
@@ -47,11 +47,9 @@ class AccountFunction{
       var res = await apiAuthProvider.patchData('/api/informants/' + user['id'].toString(), p, context);
       if (res != null) {
         closeLoading(context);
-        print("locale ====== $locale");
         context.setLocale(Locale(locale));
         notification.startNotification(context, code: code);
         // Navigator.of(context).pop();
-        print("here");
       } else {
         closeLoading(context);
       }

+ 2 - 0
lib/src/layouts/functions/history.dart

@@ -146,6 +146,8 @@ class HistoryFunction{
             }
             Provider.of<HistoryModule>(context, listen: false).addPage();
           }
+          // print("tempData");
+          // print(tempData);
           Provider.of<HistoryModule>(context, listen: false).setMisi(tempData);
 
           if (Provider.of<HistoryModule>(context, listen: false).getMisiLength() >= misi['page']['totalElements']) {

+ 26 - 0
lib/src/layouts/functions/home.dart

@@ -5,6 +5,7 @@ import 'package:telnow_mobile_new/src/injector/injector.dart';
 import 'package:telnow_mobile_new/src/layouts/components/template.dart';
 import 'package:telnow_mobile_new/src/storage/sharedpreferences/shared_preferences_manager.dart';
 import 'package:provider/provider.dart';
+import 'package:telnow_mobile_new/src/utils/C.dart';
 import 'package:telnow_mobile_new/src/utils/U.dart';
 import 'package:telnow_mobile_new/src/utils/cache_manager.dart';
 import 'package:telnow_mobile_new/src/utils/provider.dart';
@@ -268,6 +269,18 @@ class HomeFunction{
     }
   }
 
+  getContactCenter(BuildContext context) async {
+    try{
+      var url = "/api/contactCenter/whatsapp" ;
+      var res = await apiAuthProvider.getData(url, null, context);
+      if (res != null) {
+        Provider.of<ServiceModule>(context, listen: false).setContactCenter(res);
+      }
+    }catch(e){
+      Provider.of<ServiceModule>(context, listen: false).setContactCenter('');
+    }
+  }
+
   getUnreadMessages(BuildContext context) async {
     try {
       var res = await apiAuthProvider.getData('/api/messages/search/myMessages', null, context);
@@ -291,6 +304,19 @@ class HomeFunction{
     } catch (e) {
       print(e.toString());
     }
+
+    if(!U.isCompatibleWith(VersionKey.multiBahasa)) return;
+    try{
+      String url = '/api/messages/search/myForum';
+      var res = await apiAuthProvider.getData(url, null, context);
+      if (res != null) {
+        for (int i = 0; i < res.length; i++) {
+          if (res[i]['readStatus'] == 'UNREAD' && res[i]['userId'] != Provider.of<UserModule>(context, listen: false).user()['userId']){
+            Provider.of<ServiceModule>(context, listen: false).setUnreadMessage(true);
+          }
+        }
+      }
+    }catch(e){}
   }
 
   onRefresh(BuildContext context){

+ 32 - 0
lib/src/layouts/functions/message.dart

@@ -1,6 +1,8 @@
 import 'package:easy_localization/easy_localization.dart';
 import 'package:flutter/cupertino.dart';
 import 'package:flutter/foundation.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
 import 'package:provider/provider.dart';
 import 'package:telnow_mobile_new/src/api/api_auth_provider.dart';
 import 'package:telnow_mobile_new/src/api/jwt_token.dart';
@@ -8,9 +10,11 @@ import 'package:telnow_mobile_new/src/layouts/mobile/message_broadcast.dart';
 import 'package:telnow_mobile_new/src/layouts/mobile/message_select.dart';
 import 'package:telnow_mobile_new/src/layouts/components/template.dart';
 import 'package:telnow_mobile_new/src/layouts/web/message_broadcast.dart';
+import 'package:telnow_mobile_new/src/utils/C.dart';
 import 'package:telnow_mobile_new/src/utils/U.dart';
 import 'package:telnow_mobile_new/src/utils/cache_manager.dart';
 import 'package:telnow_mobile_new/src/utils/provider.dart';
+import 'package:url_launcher/url_launcher.dart';
 
 class MessageFunction{
   final ApiAuthProvider apiAuthProvider = ApiAuthProvider();
@@ -25,6 +29,7 @@ class MessageFunction{
   }
 
   getDataMessages(BuildContext context) async {
+    if(U.isCompatibleWith(VersionKey.multiBahasa)) getDataForum(context);
     String url = '/api/messages/search/myMessages';
     var val = await CacheMan.readData(url);
     if (val != null) {
@@ -49,6 +54,33 @@ class MessageFunction{
     }
   }
 
+  getDataForum(BuildContext context) async{
+    String url = '/api/messages/search/myForum';
+    var val = await CacheMan.readData(url);
+    if (val != null){
+      Provider.of<MessageModule>(context,listen: false).setForum(val['data']);
+    }
+
+    var res = await apiAuthProvider.getData(url, null, context);
+    if (res != null) {
+      List tempData = [];
+      for (int i = 0; i < res.length; i++) {
+        tempData.add(res[i]);
+      }
+      CacheMan.writeData(url, tempData);
+      Provider.of<MessageModule>(context, listen: false).setForum(tempData);
+      Provider.of<MessageModule>(context, listen: false).setFirstLoad(true);
+    } else {
+      Provider.of<MessageModule>(context, listen: false).setFirstLoad(true);
+    }
+  }
+
+  setAsRead(context, ticketNo) async {
+    var res = await apiAuthProvider.postData('/api/notifications/readMyForum/$ticketNo', null, null, context);
+    if (res != null) {
+    }
+  }
+
   createMessage(BuildContext context) async{
     String url = '/api/tenants/search/customFind';
     List dataTenant = [];

+ 1 - 1
lib/src/layouts/functions/request.dart

@@ -39,7 +39,7 @@ class RequestFunction{
         String url = '';
 
         if(_keyword != null){
-          String subject = U.langColumn(context, 'subject');
+          String subject = U.realColumn(context.locale, 'subject');
           search = ',{"f":["$subject","LIKE","%$_keyword%"]}';
         }
 

+ 1 - 1
lib/src/layouts/mobile/app_mobile.dart

@@ -143,7 +143,7 @@ class _MobMenuTemplateState extends State<MobMenuTemplate> {
     }
     FirebaseMessaging.onMessage.listen((event) {
       if(event.data['type'] != 'MESSAGE'){
-        if(!context.router.currentUrl.endsWith("history")){
+        if(!context.router.currentUrl.endsWith("history") && mounted){
           setState(() => historyMark = true);
           sharedPreferencesManager.putBool(SharedPreferencesManager.keyHistoryMark, true);
         }

+ 2 - 2
lib/src/layouts/mobile/history_detail.dart

@@ -48,8 +48,8 @@ class _MobHistoryDetailPageState extends State<MobHistoryDetailPage> {
       user = res['user'];
       list = res['list'];
     });
-    print(list['parentTicket']);
-    print(list['_parentTicket']);
+    // print(list);
+    // print(list['_parentTicket']);
   }
 
   @override

+ 57 - 30
lib/src/layouts/mobile/history_forum.dart

@@ -55,6 +55,7 @@ class _MobHistoryForumPageState extends State<MobHistoryForumPage> {
   bool isReverse = false;
   bool openChat = false;
   Uint8List? _image;
+  String locale = 'id';
 
   @override
   void initState() {
@@ -66,6 +67,13 @@ class _MobHistoryForumPageState extends State<MobHistoryForumPage> {
     super.initState();
   }
 
+  @override
+  void didChangeDependencies() {
+    super.didChangeDependencies();
+    locale = context.locale.toString() == 'zh' ? 'zh-cn' : context.locale.toString();
+  }
+
+
   getData() async {
     idChat = U.decodeBase64Url(_sharedPreferencesManager.getString(SharedPreferencesManager.keyAccessCode)!) + '-' + widget.data['ticketNo'];
     if (!kIsWeb) imagePath = await token.getPath() + '/TelNow/Images/';
@@ -73,7 +81,7 @@ class _MobHistoryForumPageState extends State<MobHistoryForumPage> {
     if (res != null) {
       username = res['userId'];
       getMessage();
-      getCollectionData();
+      // getCollectionData();
     }
   }
 
@@ -91,16 +99,15 @@ class _MobHistoryForumPageState extends State<MobHistoryForumPage> {
       if (mymess.containsKey('_embedded')) {
         List data = mymess['_embedded']['myMessages'];
         for (int i = 0; i < data.length; i++) {
-          if (username == data[i]['from']['user']) {
+          if (username == data[i]['from']['user'] && data[i]['senderType'] != 'SERVANT') {
             data[i]['selected'] = false;
-          }
-          else{
+          } else {
             if(U.autoTranslate()){
               data[i]['translate'] = '';
             }
           }
 
-          setState(() => messageData.insert(0, data[i]));
+          messageData.insert(0, data[i]);
           downloadImage(data[i]);
         }
 
@@ -126,40 +133,56 @@ class _MobHistoryForumPageState extends State<MobHistoryForumPage> {
         });
       }
     }
+
+    getCollectionData();
   }
 
-  translateMessage(){
-    var locale = context.locale.toString() == 'zh' ? 'zh-cn' : context.locale.toString();
+  translateMessage() async{
+    var loc = locale == 'zh' ? 'zh-cn' : locale;
     messageData.forEach((element) async{
-      if (username != element['from']['user'] && element['translate'] == '') {
-        var translate = await translator.translate(element['msg']??'', to: locale);
-        setState(() {
+      if (element['senderType'] == 'SERVANT' && element['translate'] == '') { // && username != element['from']['user']
+        try {
+          var translate = await translator.translate(element['msg'] ?? '', to: loc);
           element['translate'] = translate.text;
-        });
+        }catch(e){
+          print("Error translate: ${e.toString()}");
+        }
       }
     });
+    setState(() {});
   }
 
   getCollectionData() {
-    FirebaseFirestore.instance.collection("tmMessages").doc('messages').collection(idChat!).snapshots().listen((querySnapshot) {
-      setState(() {
+    try{
+      FirebaseFirestore.instance.collection("tmMessages").doc('messages').collection(idChat!).snapshots().listen((querySnapshot) {
         querySnapshot.docChanges.forEach((result) async {
           var data = result.doc.data();
           if (result.type == DocumentChangeType.added && isAfterLoad) {
-            if ((username == data!['from']['user'] && messageData.where((element) => element['uniqueId'] == data['uniqueId']).length > 0) || (username != data['from']['user'] && data['readStatus'] == 'DELETED')) {
+            if (
+            (
+                (username == data!['from']['user'] && data!['senderType'] != 'SERVANT') &&
+                    messageData.where((element) => element['uniqueId'] == data['uniqueId']).isNotEmpty
+            ) ||
+                (username != data['from']['user'] && data['readStatus'] == 'DELETED')
+            ) {
               int index = messageData.indexWhere((element) => element['uniqueId'] == data['uniqueId']);
               messageData[index]['read'] = data['read'];
               messageData[index]['readStatus'] = data['readStatus'];
               messageData[index]['imageUrl'] = data['imageUrl'];
             } else {
               if(U.autoTranslate()){
-                var locale = context.locale.toString() == 'zh' ? 'zh-cn' : context.locale.toString();
-                var translate = await translator.translate(data['msg']??'', to: locale);
-                data['translate'] = translate.text;
+                try{
+                  var translate = await translator.translate(data['msg']??'', to: locale);
+                  data['translate'] = translate.text;
+                }catch(e){
+                  print("Error translate: ${e.toString()}");
+                }
+              }
+              bool alreadyExists = messageData.any((element) => element['uniqueId'] == data['uniqueId']);
+              if (!alreadyExists) {
+                messageData.add(data);
               }
-              messageData.add(data);
             }
-
             downloadImage(data);
           } else if (result.type == DocumentChangeType.modified && isAfterLoad) {
             if (messageData.where((element) => element['uniqueId'] == data!['uniqueId']).length > 0) {
@@ -168,10 +191,16 @@ class _MobHistoryForumPageState extends State<MobHistoryForumPage> {
               messageData[index]['readStatus'] = data['readStatus'];
             }
           }
+          if(mounted) setState(() {});
         });
+      });
+    }catch(e){}
+
+    if(mounted) {
+      setState(() {
         isAfterLoad = true;
       });
-    });
+    }
   }
 
   Future<bool> cacheImage(String url, BuildContext context) async {
@@ -292,9 +321,7 @@ class _MobHistoryForumPageState extends State<MobHistoryForumPage> {
             child: Container(
               alignment: Alignment.topCenter,
               width: U.bodyWidth(context),
-              child: messageData.length == 0 && !isAfterLoad ? loadingTemplate(() {
-
-              },) : SingleChildScrollView(
+              child: messageData.length == 0 && !isAfterLoad ? loadingTemplate((){}) : SingleChildScrollView(
                 controller: scrollController,
                 reverse: isReverse,
                 padding: EdgeInsets.fromLTRB(10, 10, 10, 7),
@@ -304,7 +331,7 @@ class _MobHistoryForumPageState extends State<MobHistoryForumPage> {
                     bool isNip = i == 0 ? true : !hideDate ? true : messageData[i]['from']['user'] == messageData[i - 1]['from']['user'] ? false : true;
                     return Column(
                       children: [
-                        !hideDate ? Container(margin: EdgeInsets.only(bottom: 5), child: bubble_chat(Text(convertDate(messageData[i]['datetime'], context.locale.toString()), textAlign: TextAlign.center, style: TextStyle(fontSize: 12)), null, false, false)) : Container(),
+                        !hideDate ? Container(margin: EdgeInsets.only(bottom: 5), child: bubleChat(Text(convertDate(messageData[i]['datetime'], locale), textAlign: TextAlign.center, style: TextStyle(fontSize: 12)), null, false, false)) : Container(),
                         Builder(builder: (context) {
                           var isMe = username == messageData[i]['from']['user'] && messageData[i]['senderType'] == 'INFORMANT';
                           var isImage = messageData[i]['imageUrl'] != null && messageData[i]['imageUrl'] != '' && messageData[i]['readStatus'] != 'DELETED';
@@ -375,7 +402,7 @@ class _MobHistoryForumPageState extends State<MobHistoryForumPage> {
                                         onTap: () => kIsWeb ? navigateTo(context, PhotoPreview('forum'.tr(), messageData[i]['imageUrl'], true)) : File(imagePath! + getImageName(messageData[i]['imageUrl'])).existsSync() ? navigateTo(context, PhotoPreview('forum'.tr(), File(imagePath! + getImageName(messageData[i]['imageUrl'])), false)) : null,
                                       ),
                                     ) : Container(width: 1),
-                                    messageData[i]['readStatus'] == 'DELETED' ? Text('deletedMessage'.tr(), style: TextStyle(fontSize: 14, color: Colors.white70, fontStyle: FontStyle.italic)) : messageData[i]['msg'] != null && messageData[i]['msg'] != '' ? SelectableAutoLinkText(
+                                    messageData[i]['readStatus'] == 'DELETED' ? Text('deletedMessage'.tr(), style: TextStyle(fontSize: 14, fontStyle: FontStyle.italic)) : messageData[i]['msg'] != null && messageData[i]['msg'] != '' ? SelectableAutoLinkText(
                                       messageData[i]['msg'],
                                       style: TextStyle(fontSize: 14, color: Colors.black),
                                       linkStyle: TextStyle(color: Colors.blueAccent),
@@ -406,7 +433,7 @@ class _MobHistoryForumPageState extends State<MobHistoryForumPage> {
                             text: TextSpan(children: [
                               TextSpan(text: DateFormat('HH:mm').format(DateTime.parse(messageData[i]['datetime'])), style: TextStyle(fontSize: 12, color: Colors.black38)),
                               WidgetSpan(
-                                  child: Padding(
+                                  child: !isMe ? SizedBox() : Padding(
                                       padding: const EdgeInsets.only(left: 3),
                                       child: Icon(messageData[i]['read'] == null ? Icons.done : Icons.done_all, color: messageData[i]['read'] != null && messageData[i]['read'] ? Colors.green : Colors.black38, size: 15)
                                   )
@@ -418,7 +445,7 @@ class _MobHistoryForumPageState extends State<MobHistoryForumPage> {
                               flex: 8,
                               child: Column(
                                 children: [
-                                  bubble_chat(widget, timeBubble, isNip, isMe),
+                                  bubleChat(widget, timeBubble, isNip, isMe),
                                   SizedBox(height: 5),
                                 ],
                                 crossAxisAlignment: isMe ? CrossAxisAlignment.end : CrossAxisAlignment.start,
@@ -612,7 +639,7 @@ class _MobHistoryForumPageState extends State<MobHistoryForumPage> {
             ),
           ):U.getInternetStatus()?Center(child: Padding(
             padding: EdgeInsets.symmetric(vertical: 20),
-            child: bubble_chat(Text('chatClosed'.tr(), textAlign: TextAlign.center, style: TextStyle(fontSize: 12)), null, false, false),
+            child: bubleChat(Text('chatClosed'.tr(), textAlign: TextAlign.center, style: TextStyle(fontSize: 12)), null, false, false),
           )):Container()
         ],
       ),
@@ -662,7 +689,7 @@ class _MobHistoryForumPageState extends State<MobHistoryForumPage> {
     }
   }
 
-  Widget bubble_chat(Widget child, Widget? time, bool isNip, bool isMe) {
+  Widget bubleChat(Widget child, Widget? time, bool isNip, bool isMe) {
     bool isDate = false;
     if (time == null) {
       isDate = true;
@@ -670,6 +697,7 @@ class _MobHistoryForumPageState extends State<MobHistoryForumPage> {
     }
     Color color = isMe ? primaryColor.withValues(alpha: 0.3) : isDate ? Color(0xffD5F5FF) : Color(0xffECECEC);
     var clipPath = ClipPath(
+      clipper: isMe ? MyClipper(isNip) : YourClipper(isNip),
       child: ConstrainedBox(
         constraints: BoxConstraints(minWidth: 75),
         child: Container(
@@ -694,7 +722,6 @@ class _MobHistoryForumPageState extends State<MobHistoryForumPage> {
           ),
         ),
       ),
-      clipper: isMe ? MyClipper(isNip) : YourClipper(isNip),
     );
 
     return Padding(padding: EdgeInsets.only(right: isNip && isMe ? 0 : 6, left: isNip && !isMe ? 0 : 6), child: clipPath);

+ 1 - 1
lib/src/layouts/mobile/menu_account.dart

@@ -61,7 +61,7 @@ class _MobAccountPageState extends State<MobAccountPage> {
       dnd = Provider.of<UserModule>(context, listen: false).dndStatus();
       serDis = U.servantDisplay();
       autoTranslate = U.autoTranslate();
-      if(U.isCompatibleWith(VKey.multiBahasa)){
+      if(U.isCompatibleWith(VersionKey.multiBahasa)){
         lang = license['_validLang'] ?? [];
       } else {
         lang = license['languages'] != null ? license['languages'].split(',') : [];

Datei-Diff unterdrückt, da er zu groß ist
+ 6 - 6
lib/src/layouts/mobile/menu_history.dart


+ 19 - 15
lib/src/layouts/mobile/menu_home.dart

@@ -19,6 +19,7 @@ import 'package:telnow_mobile_new/src/layouts/mobile/request_create.dart';
 import 'package:telnow_mobile_new/src/layouts/mobile/request_select.dart';
 import 'package:telnow_mobile_new/src/layouts/components/template.dart';
 import 'package:telnow_mobile_new/src/storage/sharedpreferences/shared_preferences_manager.dart';
+import 'package:telnow_mobile_new/src/utils/C.dart';
 import 'package:telnow_mobile_new/src/utils/U.dart';
 import 'package:telnow_mobile_new/src/utils/cache_manager.dart';
 import 'package:telnow_mobile_new/src/utils/provider.dart';
@@ -54,6 +55,9 @@ class _MobHomePageState extends State<MobHomePage> with WidgetsBindingObserver {
       });
     });
     WidgetsBinding.instance.addObserver(this);
+    if(U.isCompatibleWith(VersionKey.multiBahasa)) {
+      homeFunc.getContactCenter(context);
+    }
     // TODO: implement initState
     super.initState();
   }
@@ -86,25 +90,25 @@ class _MobHomePageState extends State<MobHomePage> with WidgetsBindingObserver {
                       Row(
                         children: [
                           //TODO: tambah pengecekan server version disini
-                          GestureDetector(
-                            onTap: () => launchUrl(Uri.parse('https://wa.me/6285225076787')),
+                          U.isCompatibleWith(VersionKey.multiBahasa) && Provider.of<ServiceModule>(context, listen: false).contactCenter().toString() != ''  ? GestureDetector(
+                            onTap: () => launchUrl(Uri.parse(Provider.of<ServiceModule>(context, listen: false).contactCenter().toString())),
                             child: U.iconsax('phone-number', color: Colors.white, size: 26.0)
-                          ),
+                          ):SizedBox(),
                           SizedBox(width: 8),
                           GestureDetector(
-                            child: Container(
-                              child: Stack(
-                                alignment: Alignment.topRight,
-                                children: [
-                                  U.iconsax('sms-notification', color: Colors.white, size: 32.0),
-                                  Provider.of<ServiceModule>(context).unreadMessage() ? Container(
-                                    width: 8, height: 8, margin: EdgeInsets.only(top: 1.3),
-                                    decoration: BoxDecoration(color: Colors.red, borderRadius: BorderRadius.all(Radius.circular(50))),
-                                  ):Container()
-                                ],
-                              ),
+                            child: Stack(
+                              alignment: Alignment.topRight,
+                              children: [
+                                U.iconsax('sms-notification', color: Colors.white, size: 32.0),
+                                Provider.of<ServiceModule>(context).unreadMessage() ? Container(
+                                  width: 13, height: 13, margin: EdgeInsets.only(top: 1.3),
+                                  decoration: BoxDecoration(color: Colors.red, borderRadius: BorderRadius.all(Radius.circular(50))),
+                                ):Container()
+                              ],
                             ),
-                            onTap: ()=>navigateTo(context, MobMessageListPage(Provider.of<UserModule>(context, listen: false).user())),
+                            onTap: ()=>navigateTo(context, MobMessageListPage(Provider.of<UserModule>(context, listen: false).user())).then((_){
+                              homeFunc.getUnreadMessages(context);
+                            }),
                           )
                         ],
                       )

Datei-Diff unterdrückt, da er zu groß ist
+ 242 - 60
lib/src/layouts/mobile/message_list.dart


+ 28 - 25
lib/src/layouts/web/history_forum.dart

@@ -149,36 +149,39 @@ class _WebHistoryForumPageState extends State<WebHistoryForumPage> {
   }
 
   getCollectionData() {
-    FirebaseFirestore.instance.collection("tmMessages").doc('messages').collection(idChat!).snapshots().listen((querySnapshot) {
-      setState(() {
-        querySnapshot.docChanges.forEach((result) async {
-          var data = result.doc.data();
-          if (result.type == DocumentChangeType.added && isAfterLoad) {
-            if ((username == data!['from']['user'] && messageData.where((element) => element['uniqueId'] == data['uniqueId']).length > 0) || (username != data['from']['user'] && data['readStatus'] == 'DELETED')) {
-              int index = messageData.indexWhere((element) => element['uniqueId'] == data['uniqueId']);
-              messageData[index]['read'] = data['read'];
-              messageData[index]['readStatus'] = data['readStatus'];
-              messageData[index]['imageUrl'] = data['imageUrl'];
-            } else {
-              if(U.autoTranslate()){
-                var locale = context.locale.toString() == 'zh' ? 'zh-cn' : context.locale.toString();
-                var translate = await translator.translate(data['msg']??'', to: locale);
-                data['translate'] = translate.text;
+    try{
+      FirebaseFirestore.instance.collection("tmMessages").doc('messages').collection(idChat!).snapshots().listen((querySnapshot) {
+        setState(() {
+          querySnapshot.docChanges.forEach((result) async {
+            var data = result.doc.data();
+            if (result.type == DocumentChangeType.added && isAfterLoad) {
+              if ((username == data!['from']['user'] && messageData.where((element) => element['uniqueId'] == data['uniqueId']).length > 0) || (username != data['from']['user'] && data['readStatus'] == 'DELETED')) {
+                int index = messageData.indexWhere((element) => element['uniqueId'] == data['uniqueId']);
+                messageData[index]['read'] = data['read'];
+                messageData[index]['readStatus'] = data['readStatus'];
+                messageData[index]['imageUrl'] = data['imageUrl'];
+              } else {
+                if(U.autoTranslate()){
+                  var locale = context.locale.toString() == 'zh' ? 'zh-cn' : context.locale.toString();
+                  var translate = await translator.translate(data['msg']??'', to: locale);
+                  data['translate'] = translate.text;
+                }
+                messageData.add(data);
               }
-              messageData.add(data);
-            }
 
-          } else if (result.type == DocumentChangeType.modified && isAfterLoad) {
-            if (messageData.where((element) => element['uniqueId'] == data!['uniqueId']).length > 0) {
-              int index = messageData.indexWhere((element) => element['uniqueId'] == data!['uniqueId']);
-              messageData[index]['read'] = data!['read'];
-              messageData[index]['readStatus'] = data['readStatus'];
+            } else if (result.type == DocumentChangeType.modified && isAfterLoad) {
+              if (messageData.where((element) => element['uniqueId'] == data!['uniqueId']).length > 0) {
+                int index = messageData.indexWhere((element) => element['uniqueId'] == data!['uniqueId']);
+                messageData[index]['read'] = data!['read'];
+                messageData[index]['readStatus'] = data['readStatus'];
+              }
             }
-          }
+          });
         });
-        isAfterLoad = true;
       });
-    });
+    }catch(e){}
+
+    isAfterLoad = true;
   }
 
   deleteCollection() {

+ 1 - 2
lib/src/layouts/web/menu_account.dart

@@ -40,7 +40,6 @@ class _WebAccountPageState extends State<WebAccountPage> {
     accFunc.getUser(context);
     setToggle();
     checkPermission(0);
-print("load ulang akun web");
     // TODO: implement initState
     super.initState();
   }
@@ -61,7 +60,7 @@ print("load ulang akun web");
       dnd = Provider.of<UserModule>(context, listen: false).dndStatus();
       serDis = U.servantDisplay();
       autoTranslate = U.autoTranslate();
-      if(U.isCompatibleWith(VKey.multiBahasa)){
+      if(U.isCompatibleWith(VersionKey.multiBahasa)){
         lang = license['_validLang'] ?? [];
       } else {
         lang = license['languages'] != null ? license['languages'].split(',') : [];

+ 3 - 3
lib/src/layouts/web/menu_history.dart

@@ -318,6 +318,7 @@ class _WebHistoryPageState extends State<WebHistoryPage> with TickerProviderStat
                                 renderRequested(Provider.of<HistoryModule>(context).dataMisi()[i]),
                                 Row(
                                   mainAxisAlignment: MainAxisAlignment.spaceBetween,
+                                  crossAxisAlignment: CrossAxisAlignment.center ,
                                   children: [
                                     Text('location'.tr()+': '+Provider.of<HistoryModule>(context).dataMisi()[i]['ipphoneExtLocation'], style: TextStyle(color: textColor, fontSize: 14), overflow: TextOverflow.ellipsis),
                                     Provider.of<HistoryModule>(context).dataMisi()[i]['_activeHoldRequest'] != null ? Container(
@@ -331,9 +332,8 @@ class _WebHistoryPageState extends State<WebHistoryPage> with TickerProviderStat
                                           Text(Provider.of<HistoryModule>(context).dataMisi()[i]['_activeHoldRequest']['description'], style: TextStyle(color: textColor, fontSize: 14))
                                         ],
                                       ),
-                                    ) : !Provider.of<HistoryModule>(context).dataMisi()[i]['autoResponse'] && Provider.of<HistoryModule>(context).dataMisi()[i]['_hasForum'] && Provider.of<HistoryModule>(context).dataMisi()[i]['_forumMsg'] != null ? Container(
-                                      width: double.infinity,
-                                      margin: EdgeInsets.only(top: 16),
+                                    ) : Provider.of<HistoryModule>(context).dataMisi()[i]['_hasForum'] && Provider.of<HistoryModule>(context).dataMisi()[i]['_forumMsg'] != null ? ConstrainedBox(
+                                      constraints: BoxConstraints(minWidth: 10),
                                       child: Row(
                                         children: [
                                           FadeTransition(opacity: _animationController, child: U.iconsax('messages-3', color: primaryColor)),

+ 17 - 1
lib/src/layouts/web/menu_home.dart

@@ -22,6 +22,8 @@ import 'package:telnow_mobile_new/src/utils/cache_manager.dart';
 import 'package:telnow_mobile_new/src/utils/provider.dart';
 import 'package:url_launcher/url_launcher.dart';
 
+import '../../utils/C.dart';
+
 class WebHomePage extends StatefulWidget {
   const WebHomePage({super.key});
 
@@ -49,6 +51,9 @@ class _WebHomePageState extends State<WebHomePage> {
         }
       });
     });
+    if(U.isCompatibleWith(VersionKey.multiBahasa)) {
+      homeFunc.getContactCenter(context);
+    }
     // TODO: implement initState
     super.initState();
   }
@@ -95,6 +100,15 @@ class _WebHomePageState extends State<WebHomePage> {
                             ),
                           ),
                           SizedBox(width: 30),
+                          U.isCompatibleWith(VersionKey.multiBahasa) && Provider.of<ServiceModule>(context, listen: false).contactCenter().toString() != ''  ? Container(
+                            padding: EdgeInsets.all(8),
+                            decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.all(Radius.circular(50))),
+                            child: GestureDetector(
+                                onTap: () => launchUrl(Uri.parse(Provider.of<ServiceModule>(context, listen: false).contactCenter().toString())),
+                                child: U.iconsax('phone-number', color: primaryColor, size: 26.0)
+                            ),
+                          ):SizedBox(),
+                          SizedBox(width: 10),
                           GestureDetector(
                             child: Container(
                               padding: EdgeInsets.all(8),
@@ -110,7 +124,9 @@ class _WebHomePageState extends State<WebHomePage> {
                                 ],
                               ),
                             ),
-                            onTap: ()=>navigateTo(context, WebMessageListPage(Provider.of<UserModule>(context, listen: false).user())),
+                            onTap: ()=>navigateTo(context, WebMessageListPage(Provider.of<UserModule>(context, listen: false).user())).then((_){
+                              homeFunc.getUnreadMessages(context);
+                            }),
                           ),
                           SizedBox(width: 10),
                           GestureDetector(

Datei-Diff unterdrückt, da er zu groß ist
+ 924 - 274
lib/src/layouts/web/message_list.dart


+ 1 - 1
lib/src/utils/C.dart

@@ -1,4 +1,4 @@
-enum VKey {
+enum VersionKey {
   none,
   multiBahasa
 }

+ 21 - 3
lib/src/utils/U.dart

@@ -94,7 +94,7 @@ class U {
       RefreshTokenBody? refreshTokenBody = RefreshTokenBody('refresh_token', refreshToken);
       refreshAuth(refreshTokenBody);
     } else {
-      print(JwtDecoder.getRemainingTime(_sharedPreferencesManager.getString(SharedPreferencesManager.keyAccessToken)!));
+      // print(JwtDecoder.getRemainingTime(_sharedPreferencesManager.getString(SharedPreferencesManager.keyAccessToken)!));
     }
     // return _lockAuth.synchronized(() async {
     //   print("wait refresh token OK");
@@ -349,8 +349,8 @@ class U {
     return version <= _serverVersion;
   }
 
-  static isCompatibleWith(VKey key){
-    return C.get(key.toString()) <= _serverVersion;
+  static isCompatibleWith(VersionKey key){
+    return C.get(key.name.toString()) <= _serverVersion;
   }
 
   static int retServerVersion(){
@@ -522,6 +522,24 @@ class U {
     return code == 'id' ? text : '$prefix$text${code[0].toUpperCase()}${code.substring(1).toLowerCase()}';
   }
 
+  static String realColumn(Locale loc, String text){
+    var lc = loc.toString();
+    if(lc == 'id' || lc == 'en'){
+      if(lc == 'id') {
+        return text;
+      } else {
+        return "${text}En";
+      }
+    } else {
+      try {
+        var i = validLang.indexOf(loc.toString()) - 1;
+        return text = text + i.toString();
+      } catch (e) {
+        return text;
+      }
+    }
+  }
+
   static bool hidePayload = false;
   static void setHidePayload(value) {
     hidePayload = value;

+ 32 - 0
lib/src/utils/provider.dart

@@ -152,6 +152,7 @@ class ServiceModule with ChangeNotifier {
   static List? _reqGroup;
   static List _offer = [];
   static List _banner = [];
+  static String _contactCenter = '';
 
   String scoopeName() => _scoopeName;
   dynamic scoopeValue() => _scoopeValue;
@@ -171,12 +172,18 @@ class ServiceModule with ChangeNotifier {
   List? reqGroup() => _reqGroup;
   List specialOffer() => _offer;
   List banner() => _banner;
+  String contactCenter() => _contactCenter;
 
   void setInitialized(value) {
     _initialized = value;
     notifyListeners();
   }
 
+  void setContactCenter(value) {
+    _contactCenter = value;
+    notifyListeners();
+  }
+
   void setScoopeName(value) {
     _scoopeName = value;
     notifyListeners();
@@ -516,10 +523,16 @@ class MessageModule with ChangeNotifier{
   Map<String, dynamic> _user = {};
   List _data = [];
   bool _firstLoad = false;
+  bool _isAfterLoad = false;
+  List _forum = [];
+  int _selectedTab = 0;
 
   Map<String, dynamic> user() => _user;
   List data() => _data;
   bool firstLoad() => _firstLoad;
+  bool isAfterLoad() => _isAfterLoad;
+  List forum() => _forum;
+  int activeTab() => _selectedTab;
 
   void setUser(value) {
     _user = value;
@@ -536,9 +549,28 @@ class MessageModule with ChangeNotifier{
     notifyListeners();
   }
 
+  void setAfterLoad(value) {
+    _isAfterLoad = value;
+    notifyListeners();
+  }
+
   void reset(){
     _user = {};
     _data = [];
     _firstLoad = false;
+    _isAfterLoad = false;
+    _forum = [];
+    _selectedTab = 0;
+  }
+
+  void setForum(val){
+    _forum = val;
+    notifyListeners();
+  }
+
+  void setActiveTab(val){
+    // print("setActiveTab($val)");
+    _selectedTab = val;
+    notifyListeners();
   }
 }