8 Commits 9e1f99d2b8 ... 6180c15e02

Auteur SHA1 Bericht Datum
  Yulian 6180c15e02 updated rilis 1 maand geleden
  Yulian a4009d2ff2 siap rilis 1 maand geleden
  Yulian 6388617b0b fix: eror di history dan 16kb compatibility play console 1 maand geleden
  Yulian 9197045e72 update statemanagement: history detil masih eror 2 maanden geleden
  Yulian 5c432946cc merapikan kodingan web home 3 maanden geleden
  Yulian 57ed4e4ab3 bersih2 version compatibility 3 maanden geleden
  Yulian e8fba8c01a bereskan pengecekan newversion 3 maanden geleden
  Yulian 970693b824 asset 3 maanden geleden
61 gewijzigde bestanden met toevoegingen van 6409 en 3153 verwijderingen
  1. 9 0
      android/app/build.gradle.kts
  2. 8 1
      assets/lang/ar.json
  3. 8 1
      assets/lang/de.json
  4. 342 335
      assets/lang/en.json
  5. 8 1
      assets/lang/fr.json
  6. 8 1
      assets/lang/hi.json
  7. 342 335
      assets/lang/id.json
  8. 340 333
      assets/lang/ja.json
  9. 340 333
      assets/lang/ko.json
  10. 8 1
      assets/lang/nl.json
  11. 340 333
      assets/lang/zh.json
  12. 24 17
      lib/main.dart
  13. 2 1
      lib/src/api/api_auth_provider.dart
  14. 2 6
      lib/src/api/jwt_token.dart
  15. 129 0
      lib/src/cubit/history_detail_cubit.dart
  16. 179 0
      lib/src/cubit/history_menu_cubit.dart
  17. 235 0
      lib/src/cubit/history_tab_cubit.dart
  18. 86 0
      lib/src/cubit/pickup_asset_cubit.dart
  19. 101 0
      lib/src/cubit/user_data_cubit.dart
  20. 7 18
      lib/src/layouts/auth/login.dart
  21. 1 5
      lib/src/layouts/auth/qr.dart
  22. 302 0
      lib/src/layouts/components/rate_mission.dart
  23. 7 1
      lib/src/layouts/components/responsive.dart
  24. 250 0
      lib/src/layouts/components/widgets.dart
  25. 1 5
      lib/src/layouts/functions/account.dart
  26. 43 2
      lib/src/layouts/functions/detail.dart
  27. 1 1
      lib/src/layouts/functions/history.dart
  28. 3 16
      lib/src/layouts/functions/home.dart
  29. 1 1
      lib/src/layouts/functions/message.dart
  30. 32 38
      lib/src/layouts/functions/request.dart
  31. 2 2
      lib/src/layouts/mobile/banner_detail.dart
  32. 233 80
      lib/src/layouts/mobile/history_detail.dart
  33. 1 5
      lib/src/layouts/mobile/menu_account.dart
  34. 3 3
      lib/src/layouts/mobile/menu_history.dart
  35. 7 33
      lib/src/layouts/mobile/menu_home.dart
  36. 0 1
      lib/src/layouts/mobile/message_chat.dart
  37. 1 8
      lib/src/layouts/mobile/message_list.dart
  38. 219 0
      lib/src/layouts/mobile/pickup_asset.dart
  39. 160 46
      lib/src/layouts/mobile/request_create.dart
  40. 2 2
      lib/src/layouts/web/banner_detail.dart
  41. 901 58
      lib/src/layouts/web/history_detail.dart
  42. 157 0
      lib/src/layouts/web/menu-history/build_filter.dart
  43. 70 0
      lib/src/layouts/web/menu-history/build_tab.dart
  44. 109 0
      lib/src/layouts/web/menu-history/done_container.dart
  45. 318 0
      lib/src/layouts/web/menu-history/history_item_widget.dart
  46. 138 0
      lib/src/layouts/web/menu-history/ongoing_container.dart
  47. 80 76
      lib/src/layouts/web/menu_account.dart
  48. 157 763
      lib/src/layouts/web/menu_history.dart
  49. 135 161
      lib/src/layouts/web/menu_home.dart
  50. 1 16
      lib/src/layouts/web/message_list.dart
  51. 3 2
      lib/src/layouts/web/password.dart
  52. 161 47
      lib/src/layouts/web/request_create.dart
  53. 3 2
      lib/src/layouts/web/request_select.dart
  54. 78 8
      lib/src/layouts/web/request_success.dart
  55. 243 0
      lib/src/repository/history_repository.dart
  56. 2 2
      lib/src/utils/C.dart
  57. 14 20
      lib/src/utils/U.dart
  58. 1 1
      lib/src/utils/dio_logging_interceptors.dart
  59. 10 0
      lib/src/utils/extensions.dart
  60. 34 26
      pubspec.lock
  61. 7 6
      pubspec.yaml

+ 9 - 0
android/app/build.gradle.kts

@@ -113,6 +113,9 @@ android {
         targetSdk = flutter.targetSdkVersion
         versionCode = flutter.versionCode
         versionName = flutter.versionName
+        ndk {
+            abiFilters += listOf("armeabi-v7a", "arm64-v8a")
+        }
     }
 
     signingConfigs {
@@ -132,6 +135,12 @@ android {
             signingConfig = signingConfigs.getByName("release")
         }
     }
+
+    packagingOptions {
+        jniLibs {
+            useLegacyPackaging = false
+        }
+    }
 }
 
 dependencies {

+ 8 - 1
assets/lang/ar.json

@@ -333,5 +333,12 @@
   "invalidParentTicket": "رقم المرجع غير صالح.",
   "failedLoad": "فشل تحميل التطبيق.",
   "tap2retry": "اضغط لإعادة المحاولة.",
-  "chat": "محادثة"
+  "chat": "محادثة",
+  "asset": "الأصل",
+  "selectAsset": "اختر الأصل",
+  "addAsset": "إضافة أصل",
+  "assetList": "قائمة الأصول",
+  "noDataSelected": "لم يتم اختيار أي بيانات.",
+  "noAssetAdded": "لم يتم إضافة أي أصل.",
+  "addLabel": "إضافة"
 }

+ 8 - 1
assets/lang/de.json

@@ -333,5 +333,12 @@
   "invalidParentTicket": "Ungültige Referenznummer.",
   "failedLoad": "App konnte nicht geladen werden.",
   "tap2retry": "Tippen, um es erneut zu versuchen.",
-  "chat": "Gespräch"
+  "chat": "Gespräch",
+  "asset": "Activa",
+  "selectAsset": "Selecteer activa",
+  "addAsset": "Activa toevoegen",
+  "assetList": "Activalijst",
+  "noDataSelected": "Geen gegevens geselecteerd.",
+  "noAssetAdded": "Geen activa toegevoegd.",
+  "addLabel": "Toevoegen"
 }

+ 342 - 335
assets/lang/en.json

@@ -1,337 +1,344 @@
 {
-   "account": "Account",
-   "addNote": "Add note",
-   "addNoteCancel": "Add cancel note",
-   "all": "All",
-   "anyNote": "Note for service staff",
-   "appointment": "Appointment",
-   "attach": "Attach image",
-   "buttonCancel": "Cancel Request",
-   "buttonLogin": "Login",
-   "buttonNo": "NO",
-   "buttonResubmit": "RESEND",
-   "buttonScan": "Scan QR",
-   "buttonSendEmergency": "SEND EMERGENCY",
-   "buttonSendComplaint": "SEND COMPLAINT",
-   "buttonSendRequest": "Send Request",
-   "buttonYes": "YES",
-   "buttonSure": "OF COURSE",
-   "buttonBack": "Back",
-   "canceledBy": "Canceled by",
-   "category": "Category",
-   "scope": "Scope",
-   "changeScope": "Change Scope",
-   "chatClosed": "This conversation has been closed.",
-   "chooseService": "Select service you want",
-   "complaintText": "What's going on? Let's the expert work for you.",
-   "complaint": "Complaint",
-   "defaultLocation": "Default Location",
-   "detail": "Detail",
-   "disatisfied": "Disatisfied",
-   "emergencyText": "Every thing urgent & emergent should take in hurry.",
-   "emergency": "Emergency",
-   "forum": "Forum",
-   "frequentlyText": "What you frequently requested here.",
-   "frequently": "Frequently requested",
-   "frequentlyTitle": "Frequently Requested",
-   "frequentlyTitleText": "The list that you frequently requested",
-   "history": "History",
-   "lessSatisfied": "Not too satisfied",
-   "location": "Location",
-   "logout": "Logout",
-   "menuAccount": "Account",
-   "menuHistory": "History",
-   "menuService": "Service",
-   "menuHome": "Home",
-   "message": "Message",
-   "note": "Note",
-   "passwordEmpty": "Password could not be empty",
-   "password": "Password",
-   "phoneNumber": "Phone Number",
-   "placeholderLocation": "Where are you?",
-   "placeholderNote": "Type note",
-   "rateMission": "Rate this mission",
-   "reallyPleased": "Really pleased",
-   "requestText2": "What are you asking for?",
-   "requestDesc": "When you need help, just tap it.",
-   "requestTitle": "What kind of help do you need?",
-   "request": "Request",
-   "satisfactionAsk": "Are you satisfied?",
-   "satisfied": "Quite satisfied",
-   "scanQr": "Please scan QR code first to start using application.",
-   "serialNumber": "Serial Number",
-   "servantGroup": "Request Group",
-   "servant": "Service Staff",
-   "service": "Service",
-   "specifyAnotherLocation": "I want to specify another location",
-   "specifyLocation": "Define location",
-   "startDoing": "Start",
-   "stateCancel": "Cancel",
-   "stateCanceled": "Canceled",
-   "stateDone": "On Process",
-   "stateFinish": "Finish",
-   "stateQueue": "Queue",
-   "stateRequested": "Requested",
-   "state": "Status",
-   "sure": "Are you sure?",
-   "switch": "Switch",
-   "system": "System",
-   "textCancel": "Cancel",
-   "textHistory": "Request you have made",
-   "textLogout": "Logging out will cause you can't receive notification, made any request, etc. Sure?",
-   "textResubmit": "You will resend this request to the service staff.",
-   "ticketNumber": "Ticket Number",
-   "timeline": "Timeline",
-   "today": "Today",
-   "unrated": "No rating for this mission yet",
-   "userEmpty": "Username could not be empty",
-   "userId": "Username",
-   "version": "Version ",
-   "verySatisfied": "Satisfied",
-   "whatComplain": "What complaint?",
-   "whatHappen": "What's going on?",
-   "whatNext": "Stay calm. What next?",
-   "whatProblem": "What's in trouble?",
-   "writeMessage": "Write message",
-   "yesterday": "Yesterday",
-   "language": "Language",
-   "bahasa": "Indonesia",
-   "english": "English",
-   "japanese": "日本語",
-   "korean": "한국어",
-   "chinese": "中文",
-   "german": "Deutsch",
-   "french": "Français",
-   "hindi": "हिंदी",
-   "arabic": "العربية",
-   "dutch": "Nederlands",
-   "chooseLanguage": "Select Language",
-   "rate": "Rate",
-   "rated": "This mission have been rated.",
-   "rateText": "You're [satisfaction] for this mission.",
-   "settingPassword": "Change Password",
-   "oldPassword": "Old password",
-   "newPassword": "New password",
-   "confirmPassword": "Confirm new password",
-   "buttonSave": "Save New Password",
-   "settingPasswordText": "Manage your password",
-   "autoResponseText": "Your request will be responded by system soon.",
-   "reply": "Reply",
-   "selectPicture": "Select Picture",
-   "fromGallery": "From Gallery",
-   "fromCamera": "From Camera",
-   "sendPicture": "Send Picture",
-   "seeAttachment": "See Attachment",
-   "confirmCancel": "Are you sure want to cancel?",
-   "selectDate": "Select date",
-   "lengthMax": "Maximum length allowed 128 characters.",
-   "locRequired": "Location is required.",
-   "idRequired": "ID is required.",
-   "dateRequired": "Date is required.",
-   "sendLater": "Send Later",
-   "thank": "Thankyou",
-   "pleaseWait": "Please wait",
-   "sendSuccess": "Successfully Sent",
-   "followUp": "the service staff will response soon.",
-   "okGot": "OK, GOT IT",
-   "okWait": "OK, SURE",
-   "errorConnection": "Connection error. Please try again in few minutes.",
-   "noInternet": "No internet access.",
-   "invalidLogin": "Username or Password is wrong.",
-   "invalidPhone": "Phone Number is not valid.",
-   "expAccount": "Account is expired.",
-   "errorServer": "Server error. Please try again in few minutes.",
-   "accessDenied": "Access Denied",
-   "licenseProblem": "Could not run application due problem in the license.",
-   "invalidVersion": "Version does not match",
-   "sugestVersion": "Use application version",
-   "currentVersion": "Current version is",
-   "contactAdmin": "Please contact administrator for further information.",
-   "pressAgain": "Press again to quit.",
-   "notFound": "Data not found.",
-   "notFound2": "What you try to find out is not here!",
-   "noInternetTitle": "No internet connection.",
-   "noInternetDesc": "Please check your internet connection. Even we couldn't ask to Google right now.",
-   "errorConnectTitle": "Could not connect to server.",
-   "errorConnectDesc": "Please contact administrator, you should be able to connect to server.",
-   "errorServerTitle": "Server Error.",
-   "errorServerDesc": "Don't freak out, we are trying to put everything still on the track.",
-   "invalidAccountTitle": "Invalid Account.",
-   "invalidAccountDesc": "Sorry! We couldn't verify your account. Please contact Administrator for further information.",
-   "expAccountTitle": "Expired Account.",
-   "expAccountDesc": "Your account is expired. Or you can contact Administrator if you think it is a mistake.",
-   "inProcess": "Processing",
-   "policy": "Privacy Policy",
-   "info": "Additional Info",
-   "refresh": "Refresh",
-   "messageCamPermission": "Access denied. Please allow TelMessenger to access camera through app permission setting.",
-   "messageInvalidCode": "Invalid code. Please contact system administrator.",
-   "messagePassChanged": "Successfully change password.",
-   "wrongOldPass": "Wrong old password.",
-   "checkNewPass": "Please check your new password.",
-   "cannotEmpty": "Data could not empty.",
-   "deletedMessage": "This message was deleted.",
-   "resend": "Resend",
-   "delete": "Delete",
-   "alreadyUsePass": "New password could not be used, define another one.",
-   "notFoundImg": "Image not found",
-   "notFoundWorktime":  "Worktime did not found. Please contact Administrator.",
-   "seeAll": "See All",
-   "quickAction": "Quick actions",
-   "quickDesc": "Help you move more efficiently.",
-   "times": " times",
-   "search": "Search",
-   "searchAsk": "Search...",
-   "helpHint": "Try to find some help..",
-   "inProgress": " request(s) still in progress.",
-   "currentActiveText": "Your currently active request",
-   "photo": "Photo",
-   "selectRecipient": "Select recipient",
-   "composeMessage": "Compose message",
-   "to": "To",
-   "addAttachment": "Add attachment",
-   "editAttachment": "Change attachment",
-   "unsupportedFile": "Unsupported file format",
-   "pdfFile": "PDF file type",
-   "other": "other",
-   "noMessageText": "No message to preview.",
-   "noDataText": "No preview data available.",
-   "noPIDText": "No access code found.",
-   "noPIDText2": "Get access code from scan QR or link provided by TelMessenger license holder.",
-   "loading": "Loading...",
-   "backToLogin": "Back to login",
-   "deleteHistory": "Delete History Data",
-   "deleteHistoryConfirm": "Are you sure want to delete the data?",
-   "couldnotDelete": "This data could not be deleted.",
-   "allInformants": "All Informants",
-   "welcome": "Welcome",
-   "createNewPassText": "Please create new password before start using application.",
-   "description": "Description",
-   "sorry": "Sorry!",
-   "outOfWorkTime": "Your request is currently out of service staff work time.",
-   "willResponse": "They will response soon on: ",
-   "canNotCancel1": "This report cannot be canceled once it has been done by the Service Staff.",
-   "canNotCancel2": "This report cannot be canceled.",
-   "priorityHigh": "High",
-   "priorityLow": "Low",
-   "priorityNormal": "Normal",
-   "priority": "Priority",
-   "reported": "Reported",
-   "escalationNoteBySystem": "Escalation",
-   "finishAttachment": "Finish Attachment",
-   "pleaseScan": "Please scan QR code",
-   "mustScan": "You must scan QR code to resend.",
-   "changeCodeMsg": "You will be connected with <company_name>. Would you like to continue?",
-   "currentServer": "Current server",
-   "destinationServer": "Destination server",
-   "textContinue": "Continue",
-   "transferNoteBySystem": "Transfer",
-   "activity": "Activity",
-   "image": "Image",
-   "titlePassOld": "Input your old password",
-   "titlePassNew": "Your old password will be replaced with the new one.",
-   "setting": "Setting",
-   "more": "More",
-   "topMenu": "Top Menu",
-   "availableMenu": "Available Menu",
-   "customize": "Customize",
-   "done": "Done",
-   "ongoing": "Ongoing",
-   "maxMenu": "Maximum 7 menu.",
-   "searchIn": "Search in",
-   "yourLocation": "Your Location",
-   "addImage": "Want to add a picture?",
-   "addImageMsg": "You can send us a picture as a clue or something.",
-   "removeImageMsg": "No, it's not necessary. I'd like to remove it.",
-   "sendingOpt": "Sending Option",
-   "sendingOptMsg": "Do you want to send as a scheduled request or immediately?",
-   "scheduled": "Scheduled",
-   "sendNow": "Send Now",
-   "scheduledMsg": "* Scheduled = request will be sent on the time you picked in the note.",
-   "reqSuccessMsg": "Please wait. Your request is being processed.",
-   "noImgAttach": "No image attached.",
-   "btnWait": "Okay, I’ll wait",
-   "rateReq": "Rate Your Request",
-   "reqAgain": "Request Again",
-   "notAvailable": "This menu is not available.",
-   "emptyMenuAlert": "You haven't choose any menu to show.",
-   "redirecting": "Redirecting...",
-   "initializing": "Initializing...",
-   "selectAlert": "Please select one menu at least.",
-   "scopeDesc": "Use this to switch between the scope.",
-   "notFoundKeyword": "Could not found anything which match with keyword ",
-   "findQRcode": "Find QR code nearby you",
-   "isWorking": " is working on your request.",
-   "noteLongAlert": "Please add note less than 128 character.",
-   "reqCodeNotFound": "Invalid request code. Please contact Administrator",
-   "noImage": "No Image Found",
-   "related": "Related Services",
-   "broadcastPermission": "Cant send broadcast message, you have no permission.",
-   "broadcastTenant": "Cant send broadcast message, recipient tenant is not valid.",
-   "reqForOthers": "Yes, I like to help other.",
-   "reqForMySelf": "No, I make request for my self.",
-   "requestedBy": "Requested by",
-   "requestedFor": "Requested for",
-   "typeId": "Please type her/his ID",
-   "idNotMatch": "Failed send request. This request is not allowed for #ID to request.",
-   "idNotFound": "Could not found the ID provided. Please try another ID.",
-   "informantNotRegistered": "You are not registered as receptionist or room attendant.",
-   "link_copied": "Link has been copied to the clipboard.",
-   "do_not_disturb": "Do Not Disturb",
-   "set_dnd_status": "Set DND Status",
-   "active_dnd": "Active",
-   "inactive_dnd": "Inactive",
-   "msg_dnd": "You can deactivate your DND status through Account menu.",
-   "msg_change_active": "Do you want to activate DND status?",
-   "msg_change_inactive": "Do you want to deactivate DND status?",
-   "info_dnd": "DND Status Activated.",
-   "invalid_bridge": "Invalid Bridge URL.",
-   "someone_else": "Want to submit request of someone else?",
-   "askScheduleTime": "When your request should be done?",
-   "scheduleMessage": "Your request supposed to be done on",
-   "scan_qr": "Show My QR",
-   "show_qr": "Show QR",
-   "show_qr_desc": "Show this QR to your friend or collega who need to access the app.",
-   "dismiss": "Dismiss",
-   "not_allow_permission": "Your device is not allowing the app to send you any notification.",
-   "tap_here": "Tap here to allow notification permission.",
-   "doNotDisturb": "Do Not Disturb",
-   "info_label": "Info",
-   "display_menu": "Menu Display",
-   "req_group": "Request Group",
-   "ser_group": "Service Team",
-   "save_rating": "Save Rating",
-   "auto_translate": "Auto Translate",
-   "hold": "Hold",
-   "holdHistory": "Hold History",
-   "pending": "Pending",
-   "pending_info_success": "We found connection issue. Your request is pending. We’ll send it again when you back online.",
-   "pending_info_tiles": "Wait for internet connection to send your request.",
-   "pending_info_detail": "Your request is not sent yet due to connection issue.",
-   "cancel_pending": "Cancel my request instead",
-   "sending": "Sending",
-   "queued": "Queued",
-   "onProgress": "On Progress",
-   "showLess": "Show Less",
-   "customTopMenu": "Customize Top Menu",
-   "limitTopMenu": "Top menu is limited to 7 items only!",
-   "searchButton": "Search",
-   "allInformantsInfo": "All informant will receive your message.",
-   "action": "Action",
-   "whatMakesYou": "What makes you",
-   "letMeWrite": "Let me write it!",
-   "writeHere": "Write here..",
-   "ratingAspect": "Rating Aspect",
-   "sendingRequest": "Sending requests",
-   "changePriority": "Change Priority",
-   "referenceNumber": "Reference Number",
-   "enterTicketNumber": "Enter ticket number",
-   "subject": "Subject",
-   "requestReference": "Request Reference",
-   "endSessionTitle": "Your session has been ended.",
-   "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.",
-   "chat": "Chat"
+  "account": "Account",
+  "addNote": "Add note",
+  "addNoteCancel": "Add cancel note",
+  "all": "All",
+  "anyNote": "Note for service staff",
+  "appointment": "Appointment",
+  "attach": "Attach image",
+  "buttonCancel": "Cancel Request",
+  "buttonLogin": "Login",
+  "buttonNo": "NO",
+  "buttonResubmit": "RESEND",
+  "buttonScan": "Scan QR",
+  "buttonSendEmergency": "SEND EMERGENCY",
+  "buttonSendComplaint": "SEND COMPLAINT",
+  "buttonSendRequest": "Send Request",
+  "buttonYes": "YES",
+  "buttonSure": "OF COURSE",
+  "buttonBack": "Back",
+  "canceledBy": "Canceled by",
+  "category": "Category",
+  "scope": "Scope",
+  "changeScope": "Change Scope",
+  "chatClosed": "This conversation has been closed.",
+  "chooseService": "Select service you want",
+  "complaintText": "What's going on? Let's the expert work for you.",
+  "complaint": "Complaint",
+  "defaultLocation": "Default Location",
+  "detail": "Detail",
+  "disatisfied": "Disatisfied",
+  "emergencyText": "Every thing urgent & emergent should take in hurry.",
+  "emergency": "Emergency",
+  "forum": "Forum",
+  "frequentlyText": "What you frequently requested here.",
+  "frequently": "Frequently requested",
+  "frequentlyTitle": "Frequently Requested",
+  "frequentlyTitleText": "The list that you frequently requested",
+  "history": "History",
+  "lessSatisfied": "Not too satisfied",
+  "location": "Location",
+  "logout": "Logout",
+  "menuAccount": "Account",
+  "menuHistory": "History",
+  "menuService": "Service",
+  "menuHome": "Home",
+  "message": "Message",
+  "note": "Note",
+  "passwordEmpty": "Password could not be empty",
+  "password": "Password",
+  "phoneNumber": "Phone Number",
+  "placeholderLocation": "Where are you?",
+  "placeholderNote": "Type note",
+  "rateMission": "Rate this mission",
+  "reallyPleased": "Really pleased",
+  "requestText2": "What are you asking for?",
+  "requestDesc": "When you need help, just tap it.",
+  "requestTitle": "What kind of help do you need?",
+  "request": "Request",
+  "satisfactionAsk": "Are you satisfied?",
+  "satisfied": "Quite satisfied",
+  "scanQr": "Please scan QR code first to start using application.",
+  "serialNumber": "Serial Number",
+  "servantGroup": "Request Group",
+  "servant": "Service Staff",
+  "service": "Service",
+  "specifyAnotherLocation": "I want to specify another location",
+  "specifyLocation": "Define location",
+  "startDoing": "Start",
+  "stateCancel": "Cancel",
+  "stateCanceled": "Canceled",
+  "stateDone": "On Process",
+  "stateFinish": "Finish",
+  "stateQueue": "Queue",
+  "stateRequested": "Requested",
+  "state": "Status",
+  "sure": "Are you sure?",
+  "switch": "Switch",
+  "system": "System",
+  "textCancel": "Cancel",
+  "textHistory": "Request you have made",
+  "textLogout": "Logging out will cause you can't receive notification, made any request, etc. Sure?",
+  "textResubmit": "You will resend this request to the service staff.",
+  "ticketNumber": "Ticket Number",
+  "timeline": "Timeline",
+  "today": "Today",
+  "unrated": "No rating for this mission yet",
+  "userEmpty": "Username could not be empty",
+  "userId": "Username",
+  "version": "Version ",
+  "verySatisfied": "Satisfied",
+  "whatComplain": "What complaint?",
+  "whatHappen": "What's going on?",
+  "whatNext": "Stay calm. What next?",
+  "whatProblem": "What's in trouble?",
+  "writeMessage": "Write message",
+  "yesterday": "Yesterday",
+  "language": "Language",
+  "bahasa": "Indonesia",
+  "english": "English",
+  "japanese": "日本語",
+  "korean": "한국어",
+  "chinese": "中文",
+  "german": "Deutsch",
+  "french": "Français",
+  "hindi": "हिंदी",
+  "arabic": "العربية",
+  "dutch": "Nederlands",
+  "chooseLanguage": "Select Language",
+  "rate": "Rate",
+  "rated": "This mission have been rated.",
+  "rateText": "You're [satisfaction] for this mission.",
+  "settingPassword": "Change Password",
+  "oldPassword": "Old password",
+  "newPassword": "New password",
+  "confirmPassword": "Confirm new password",
+  "buttonSave": "Save New Password",
+  "settingPasswordText": "Manage your password",
+  "autoResponseText": "Your request will be responded by system soon.",
+  "reply": "Reply",
+  "selectPicture": "Select Picture",
+  "fromGallery": "From Gallery",
+  "fromCamera": "From Camera",
+  "sendPicture": "Send Picture",
+  "seeAttachment": "See Attachment",
+  "confirmCancel": "Are you sure want to cancel?",
+  "selectDate": "Select date",
+  "lengthMax": "Maximum length allowed 128 characters.",
+  "locRequired": "Location is required.",
+  "idRequired": "ID is required.",
+  "dateRequired": "Date is required.",
+  "sendLater": "Send Later",
+  "thank": "Thankyou",
+  "pleaseWait": "Please wait",
+  "sendSuccess": "Successfully Sent",
+  "followUp": "the service staff will response soon.",
+  "okGot": "OK, GOT IT",
+  "okWait": "OK, SURE",
+  "errorConnection": "Connection error. Please try again in few minutes.",
+  "noInternet": "No internet access.",
+  "invalidLogin": "Username or Password is wrong.",
+  "invalidPhone": "Phone Number is not valid.",
+  "expAccount": "Account is expired.",
+  "errorServer": "Server error. Please try again in few minutes.",
+  "accessDenied": "Access Denied",
+  "licenseProblem": "Could not run application due problem in the license.",
+  "invalidVersion": "Version does not match",
+  "sugestVersion": "Use application version",
+  "currentVersion": "Current version is",
+  "contactAdmin": "Please contact administrator for further information.",
+  "pressAgain": "Press again to quit.",
+  "notFound": "Data not found.",
+  "notFound2": "What you try to find out is not here!",
+  "noInternetTitle": "No internet connection.",
+  "noInternetDesc": "Please check your internet connection. Even we couldn't ask to Google right now.",
+  "errorConnectTitle": "Could not connect to server.",
+  "errorConnectDesc": "Please contact administrator, you should be able to connect to server.",
+  "errorServerTitle": "Server Error.",
+  "errorServerDesc": "Don't freak out, we are trying to put everything still on the track.",
+  "invalidAccountTitle": "Invalid Account.",
+  "invalidAccountDesc": "Sorry! We couldn't verify your account. Please contact Administrator for further information.",
+  "expAccountTitle": "Expired Account.",
+  "expAccountDesc": "Your account is expired. Or you can contact Administrator if you think it is a mistake.",
+  "inProcess": "Processing",
+  "policy": "Privacy Policy",
+  "info": "Additional Info",
+  "refresh": "Refresh",
+  "messageCamPermission": "Access denied. Please allow TelMessenger to access camera through app permission setting.",
+  "messageInvalidCode": "Invalid code. Please contact system administrator.",
+  "messagePassChanged": "Successfully change password.",
+  "wrongOldPass": "Wrong old password.",
+  "checkNewPass": "Please check your new password.",
+  "cannotEmpty": "Data could not empty.",
+  "deletedMessage": "This message was deleted.",
+  "resend": "Resend",
+  "delete": "Delete",
+  "alreadyUsePass": "New password could not be used, define another one.",
+  "notFoundImg": "Image not found",
+  "notFoundWorktime":  "Worktime did not found. Please contact Administrator.",
+  "seeAll": "See All",
+  "quickAction": "Quick actions",
+  "quickDesc": "Help you move more efficiently.",
+  "times": " times",
+  "search": "Search",
+  "searchAsk": "Search...",
+  "helpHint": "Try to find some help..",
+  "inProgress": " request(s) still in progress.",
+  "currentActiveText": "Your currently active request",
+  "photo": "Photo",
+  "selectRecipient": "Select recipient",
+  "composeMessage": "Compose message",
+  "to": "To",
+  "addAttachment": "Add attachment",
+  "editAttachment": "Change attachment",
+  "unsupportedFile": "Unsupported file format",
+  "pdfFile": "PDF file type",
+  "other": "other",
+  "noMessageText": "No message to preview.",
+  "noDataText": "No preview data available.",
+  "noPIDText": "No access code found.",
+  "noPIDText2": "Get access code from scan QR or link provided by TelMessenger license holder.",
+  "loading": "Loading...",
+  "backToLogin": "Back to login",
+  "deleteHistory": "Delete History Data",
+  "deleteHistoryConfirm": "Are you sure want to delete the data?",
+  "couldnotDelete": "This data could not be deleted.",
+  "allInformants": "All Informants",
+  "welcome": "Welcome",
+  "createNewPassText": "Please create new password before start using application.",
+  "description": "Description",
+  "sorry": "Sorry!",
+  "outOfWorkTime": "Your request is currently out of service staff work time.",
+  "willResponse": "They will response soon on: ",
+  "canNotCancel1": "This report cannot be canceled once it has been done by the Service Staff.",
+  "canNotCancel2": "This report cannot be canceled.",
+  "priorityHigh": "High",
+  "priorityLow": "Low",
+  "priorityNormal": "Normal",
+  "priority": "Priority",
+  "reported": "Reported",
+  "escalationNoteBySystem": "Escalation",
+  "finishAttachment": "Finish Attachment",
+  "pleaseScan": "Please scan QR code",
+  "mustScan": "You must scan QR code to resend.",
+  "changeCodeMsg": "You will be connected with <company_name>. Would you like to continue?",
+  "currentServer": "Current server",
+  "destinationServer": "Destination server",
+  "textContinue": "Continue",
+  "transferNoteBySystem": "Transfer",
+  "activity": "Activity",
+  "image": "Image",
+  "titlePassOld": "Input your old password",
+  "titlePassNew": "Your old password will be replaced with the new one.",
+  "setting": "Setting",
+  "more": "More",
+  "topMenu": "Top Menu",
+  "availableMenu": "Available Menu",
+  "customize": "Customize",
+  "done": "Done",
+  "ongoing": "Ongoing",
+  "maxMenu": "Maximum 7 menu.",
+  "searchIn": "Search in",
+  "yourLocation": "Your Location",
+  "addImage": "Want to add a picture?",
+  "addImageMsg": "You can send us a picture as a clue or something.",
+  "removeImageMsg": "No, it's not necessary. I'd like to remove it.",
+  "sendingOpt": "Sending Option",
+  "sendingOptMsg": "Do you want to send as a scheduled request or immediately?",
+  "scheduled": "Scheduled",
+  "sendNow": "Send Now",
+  "scheduledMsg": "* Scheduled = request will be sent on the time you picked in the note.",
+  "reqSuccessMsg": "Please wait. Your request is being processed.",
+  "noImgAttach": "No image attached.",
+  "btnWait": "Okay, I’ll wait",
+  "rateReq": "Rate Your Request",
+  "reqAgain": "Request Again",
+  "notAvailable": "This menu is not available.",
+  "emptyMenuAlert": "You haven't choose any menu to show.",
+  "redirecting": "Redirecting...",
+  "initializing": "Initializing...",
+  "selectAlert": "Please select one menu at least.",
+  "scopeDesc": "Use this to switch between the scope.",
+  "notFoundKeyword": "Could not found anything which match with keyword ",
+  "findQRcode": "Find QR code nearby you",
+  "isWorking": " is working on your request.",
+  "noteLongAlert": "Please add note less than 128 character.",
+  "reqCodeNotFound": "Invalid request code. Please contact Administrator",
+  "noImage": "No Image Found",
+  "related": "Related Services",
+  "broadcastPermission": "Cant send broadcast message, you have no permission.",
+  "broadcastTenant": "Cant send broadcast message, recipient tenant is not valid.",
+  "reqForOthers": "Yes, I like to help other.",
+  "reqForMySelf": "No, I make request for my self.",
+  "requestedBy": "Requested by",
+  "requestedFor": "Requested for",
+  "typeId": "Please type her/his ID",
+  "idNotMatch": "Failed send request. This request is not allowed for #ID to request.",
+  "idNotFound": "Could not found the ID provided. Please try another ID.",
+  "informantNotRegistered": "You are not registered as receptionist or room attendant.",
+  "link_copied": "Link has been copied to the clipboard.",
+  "do_not_disturb": "Do Not Disturb",
+  "set_dnd_status": "Set DND Status",
+  "active_dnd": "Active",
+  "inactive_dnd": "Inactive",
+  "msg_dnd": "You can deactivate your DND status through Account menu.",
+  "msg_change_active": "Do you want to activate DND status?",
+  "msg_change_inactive": "Do you want to deactivate DND status?",
+  "info_dnd": "DND Status Activated.",
+  "invalid_bridge": "Invalid Bridge URL.",
+  "someone_else": "Want to submit request of someone else?",
+  "askScheduleTime": "When your request should be done?",
+  "scheduleMessage": "Your request supposed to be done on",
+  "scan_qr": "Show My QR",
+  "show_qr": "Show QR",
+  "show_qr_desc": "Show this QR to your friend or collega who need to access the app.",
+  "dismiss": "Dismiss",
+  "not_allow_permission": "Your device is not allowing the app to send you any notification.",
+  "tap_here": "Tap here to allow notification permission.",
+  "doNotDisturb": "Do Not Disturb",
+  "info_label": "Info",
+  "display_menu": "Menu Display",
+  "req_group": "Request Group",
+  "ser_group": "Service Team",
+  "save_rating": "Save Rating",
+  "auto_translate": "Auto Translate",
+  "hold": "Hold",
+  "holdHistory": "Hold History",
+  "pending": "Pending",
+  "pending_info_success": "We found connection issue. Your request is pending. We’ll send it again when you back online.",
+  "pending_info_tiles": "Wait for internet connection to send your request.",
+  "pending_info_detail": "Your request is not sent yet due to connection issue.",
+  "cancel_pending": "Cancel my request instead",
+  "sending": "Sending",
+  "queued": "Queued",
+  "onProgress": "On Progress",
+  "showLess": "Show Less",
+  "customTopMenu": "Customize Top Menu",
+  "limitTopMenu": "Top menu is limited to 7 items only!",
+  "searchButton": "Search",
+  "allInformantsInfo": "All informant will receive your message.",
+  "action": "Action",
+  "whatMakesYou": "What makes you",
+  "letMeWrite": "Let me write it!",
+  "writeHere": "Write here..",
+  "ratingAspect": "Rating Aspect",
+  "sendingRequest": "Sending requests",
+  "changePriority": "Change Priority",
+  "referenceNumber": "Reference Number",
+  "enterTicketNumber": "Enter ticket number",
+  "subject": "Subject",
+  "requestReference": "Request Reference",
+  "endSessionTitle": "Your session has been ended.",
+  "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.",
+  "chat": "Chat",
+  "asset": "Asset",
+  "selectAsset": "Select Asset",
+  "addAsset": "Add Asset",
+  "assetList": "Asset List",
+  "noDataSelected": "No data selected.",
+  "noAssetAdded": "No asset added.",
+  "addLabel": "Add"
 }

+ 8 - 1
assets/lang/fr.json

@@ -333,5 +333,12 @@
   "invalidParentTicket": "Numéro de référence invalide.",
   "failedLoad": "Échec du chargement de l'application.",
   "tap2retry": "Appuyez pour réessayer.",
-  "chat": "Conversation"
+  "chat": "Conversation",
+  "asset": "Actif",
+  "selectAsset": "Sélectionner un actif",
+  "addAsset": "Ajouter un actif",
+  "assetList": "Liste des actifs",
+  "noDataSelected": "Aucune donnée sélectionnée.",
+  "noAssetAdded": "Aucun actif ajouté.",
+  "addLabel": "Ajouter"
 }

+ 8 - 1
assets/lang/hi.json

@@ -333,5 +333,12 @@
   "invalidParentTicket": "अमान्य संदर्भ संख्या।",
   "failedLoad": "ऐप लोड करने में विफल।",
   "tap2retry": "पुनः प्रयास करने के लिए टैप करें।",
-  "chat": "बातचीत"
+  "chat": "बातचीत",
+  "asset": "संपत्ति",
+  "selectAsset": "संपत्ति चुनें",
+  "addAsset": "संपत्ति जोड़ें",
+  "assetList": "संपत्तियों की सूची",
+  "noDataSelected": "कोई डेटा चयनित नहीं है।",
+  "noAssetAdded": "कोई संपत्ति जोड़ी नहीं गई।",
+  "addLabel": "जोड़ें"
 }

+ 342 - 335
assets/lang/id.json

@@ -1,337 +1,344 @@
 {
-   "account": "Akun",
-   "addNote": "Tambah catatan",
-   "addNoteCancel": "Tambah catatan pembatalan",
-   "all": "Semua",
-   "anyNote": "Ada catatan untuk petugas?",
-   "appointment": "Penunjukan",
-   "attach": "Lampirkan gambar",
-   "buttonCancel": "Batalkan Misi",
-   "buttonLogin": "Masuk",
-   "buttonNo": "GA JADI",
-   "buttonResubmit": "LAPOR ULANG",
-   "buttonScan": "Pindai QR",
-   "buttonSendEmergency": "KIRIM DARURAT",
-   "buttonSendComplaint": "KIRIM KELUHAN",
-   "buttonSendRequest": "Kirim Permintaan",
-   "buttonYes": "IYA",
-   "buttonSure": "IYA, PASTI",
-   "buttonBack": "Kembali",
-   "canceledBy": "Dibatalkan oleh",
-   "category": "Kategori",
-   "scope": "Lingkup",
-   "changeScope": "Ubah Lingkup",
-   "chatClosed": "Percakapan ini sudah ditutup.",
-   "chooseService": "Pilih layanan yang kamu inginkan",
-   "complaintText": "Ada masalah apa? Biarkan ahlinya yang bekerja untukmu.",
-   "complaint": "Keluhan",
-   "defaultLocation": "Lokasi Bawaan",
-   "detail": "Rincian",
-   "disatisfied": "Tidak puas",
-   "emergencyText": "Semua hal genting & mendesak yang harus segera ditangani.",
-   "emergency": "Darurat",
-   "forum": "Forum",
-   "frequentlyText": "Yang sering kamu minta kita kumpulin di sini ya.",
-   "frequently": "Sering diminta",
-   "frequentlyTitle": "Sering Diminta",
-   "frequentlyTitleText": "Pelaporan yang sering diminta",
-   "history": "Riwayat",
-   "lessSatisfied": "Kurang puas",
-   "location": "Lokasi",
-   "logout": "Keluar",
-   "menuAccount": "Akun",
-   "menuHistory": "Riwayat",
-   "menuService": "Layanan",
-   "menuHome": "Beranda",
-   "message": "Pesan",
-   "note": "Catatan",
-   "passwordEmpty": "Kata sandi tidak boleh kosong",
-   "password": "Kata sandi",
-   "phoneNumber": "Nomor Telepon",
-   "placeholderLocation": "Tulis lokasi",
-   "placeholderNote": "Tulis catatan",
-   "rateMission": "Beri penilaian misi ini",
-   "reallyPleased": "Sangat puas",
-   "requestText2": "Apa yang diminta?",
-   "requestDesc": "Jika kamu butuh bantuan, jangan sungkan yaa.",
-   "requestTitle": "Kamu butuh bantuan apa?",
-   "request": "Permintaan",
-   "satisfactionAsk": "Apa kamu puas?",
-   "satisfied": "Cukup puas",
-   "scanQr": "Silahkan pindai QR terlebih dulu untuk memulai menggunakan aplikasi.",
-   "serialNumber": "No. Seri",
-   "servantGroup": "Kel. Laporan",
-   "servant": "Pelaksana",
-   "service": "Layanan",
-   "specifyAnotherLocation": "Saya sedang di lokasi lain",
-   "specifyLocation": "Tentukan Lokasi",
-   "startDoing": "Mulai Dikerjakan",
-   "stateCancel": "Batal",
-   "stateCanceled": "Dibatalkan",
-   "stateDone": "Dikerjakan",
-   "stateFinish": "Selesai",
-   "stateQueue": "Antrian",
-   "stateRequested": "Diminta",
-   "state": "Status",
-   "sure": "Sudah yakin?",
-   "switch": "Pengalihan",
-   "system": "Sistem",
-   "textCancel": "Batal",
-   "textHistory": "Laporan yang telah kamu buat",
-   "textLogout": "Nanti kamu ga bisa lagi menerima pemberitahuan, membuat pelaporan dan kegiatan yang lain. Yakin mau keluar?",
-   "textResubmit": "Kamu akan mengirim ulang laporan ini kepada Petugas.",
-   "ticketNumber": "Nomor Tiket",
-   "timeline": "Linimasa",
-   "today": "Hari ini",
-   "unrated": "Belum ada penilaian untuk misi ini",
-   "userEmpty": "Nama Pengguna tidak boleh kosong",
-   "userId": "Nama Pengguna",
-   "version": "Versi ",
-   "verySatisfied": "Puas",
-   "whatComplain": "Apa keluhannya?",
-   "whatHappen": "Apa yang terjadi?",
-   "whatNext": "Tetap tenang. Apa info selanjutnya?",
-   "whatProblem": "Apa yang bermasalah?",
-   "writeMessage": "Tulis pesan",
-   "yesterday": "Kemarin",
-   "language": "Bahasa",
-   "bahasa": "Indonesia",
-   "english": "English",
-   "japanese": "日本語",
-   "korean": "한국어",
-   "chinese": "中文",
-   "german": "Deutsch",
-   "french": "Français",
-   "hindi": "हिंदी",
-   "arabic": "العربية",
-   "dutch": "Nederlands",
-   "chooseLanguage": "Pilih Bahasa",
-   "rate": "Penilaian",
-   "rated": "Penilaian sudah diberikan.",
-   "rateText": "Kamu [satisfaction] terhadap misi ini.",
-   "settingPassword": "Ubah Kata Sandi",
-   "oldPassword": "Kata sandi lama",
-   "newPassword": "Kata sandi baru",
-   "confirmPassword": "Konfirmasi sandi baru",
-   "buttonSave": "Simpan Sandi Baru",
-   "settingPasswordText": "Atur kata sandi kamu disini",
-   "autoResponseText": "Permintaan kamu akan ditanggapi segera oleh sistem.",
-   "reply": "Balasan",
-   "selectPicture": "Pilih Media",
-   "fromGallery": "Dari Galeri",
-   "fromCamera": "Ambil Foto",
-   "sendPicture": "Kirim Gambar",
-   "seeAttachment": "Lihat Lampiran",
-   "confirmCancel": "Yakin mau dibatalkan?",
-   "selectDate": "Pilih tanggal",
-   "lengthMax": "Panjang catatan maksimal 128 karakter.",
-   "locRequired": "Lokasi tidak boleh kosong.",
-   "idRequired": "ID tidak boleh kosong.",
-   "dateRequired": "Tanggal tidak boleh kosong.",
-   "sendLater": "Kirim Nanti",
-   "thank": "Terimakasih",
-   "pleaseWait": "Mohon ditunggu",
-   "sendSuccess": "Berhasil Dikirim",
-   "followUp": "petugas akan segera menindaklanjuti.",
-   "okGot": "OK, MENGERTI",
-   "okWait": "OK, DITUNGGU",
-   "errorConnection": "Kesalahan koneksi. Coba beberapa saat lagi.",
-   "noInternet": "Yaah, internetnya mati.",
-   "invalidLogin": "Nama Pengguna atau Kata Sandi salah.",
-   "invalidPhone": "Nomor Telepon tidak terdaftar.",
-   "expAccount": "Akun sudah kedaluwarsa.",
-   "errorServer": "Terjadi kesalahan pada server. Coba beberapa saat lagi.",
-   "accessDenied": "Akses Ditolak",
-   "licenseProblem": "Aplikasi tidak dapat digunakan karena bermasalah dengan lisensi.",
-   "invalidVersion": "Versi Aplikasi Tidak Sesuai",
-   "sugestVersion": "Gunakan aplikasi dengan versi",
-   "currentVersion": "Versi aplikasi terpasang adalah",
-   "contactAdmin": "Silahkan menghubungi Administrator untuk keterangan lebih lanjut.",
-   "pressAgain": "Tekan lagi untuk keluar.",
-   "notFound": "Data tidak ditemukan.",
-   "notFound2": "Apa yang kamu cari tidak ada di sini..!",
-   "noInternetTitle": "Tidak ada sambungan internet.",
-   "noInternetDesc": "Periksa dulu sambungan internetmu. Nanti kita lanjutin lagi!",
-   "errorConnectTitle": "Gagal menyambungkan ke server.",
-   "errorConnectDesc": "Tanya ke administrator, harusnya kamu udah bisa nyambung ke server.",
-   "errorServerTitle": "Sedang ada masalah di server.",
-   "errorServerDesc": "Jangan panik, kami sedang berusaha keras agar semua aman terkendali.",
-   "invalidAccountTitle": "Akun tidak terdaftar.",
-   "invalidAccountDesc": "Upps! Akun kamu ga bisa diverifikasi. Coba deh tanyakan ke Administrator.",
-   "expAccountTitle": "Akun sudah kedaluwarsa.",
-   "expAccountDesc": "Kamu ga bisa masuk ke aplikasi karena akunmu sudah kedaluwarsa. Kalau menurutmu ini adalah kesalahan, langsung saja hubungi administrator ya.",
-   "inProcess": "Sedang diproses",
-   "policy": "Kebijakan Privasi",
-   "info": "Info Tambahan",
-   "refresh": "Muat Ulang",
-   "messageCamPermission": "Akses kamera ditolak. Izinkan TelMessenger mengakses kamera melalui menu pengaturan.",
-   "messageInvalidCode": "Kode tidak valid. Silahkan hubungi administrator.",
-   "messagePassChanged": "Kata sandi berhasil diubah.",
-   "wrongOldPass": "Kata sandi lama salah.",
-   "checkNewPass": "Periksa kembali kata sandi baru.",
-   "cannotEmpty": "Data tidak boleh kosong.",
-   "deletedMessage": "Pesan ini telah dihapus.",
-   "resend": "Kirim Ulang",
-   "delete": "Hapus",
-   "alreadyUsePass": "Kata sandi tidak dapat digunakan, coba yang lain.",
-   "notFoundImg": "Gambar tidak ditemukan",
-   "notFoundWorktime":  "Jam kerja tidak ditemukan. Silahkan hubungi Administrator.",
-   "seeAll": "Lihat Semua",
-   "quickAction": "Aksi cepat",
-   "quickDesc": "Biar permintaan kamu lebih cepat.",
-   "times": " kali",
-   "search": "Pencarian",
-   "searchAsk": "Cari...",
-   "helpHint": "Coba tulis masalahmu..",
-   "inProgress": " permintaan kamu sedang diproses.",
-   "currentActiveText": "Laporanmu yg masih diproses",
-   "photo": "Gambar",
-   "selectRecipient": "Pilih penerima",
-   "composeMessage": "Buat pesan",
-   "to": "Kepada",
-   "addAttachment": "Tambah lampiran",
-   "editAttachment": "Ubah lampiran",
-   "unsupportedFile": "Format file tidak didukung",
-   "pdfFile": "File PDF",
-   "other": "lainnya",
-   "noMessageText": "Tidak ada pesan yg ditampilkan.",
-   "noDataText": "Tidak ada data untuk ditampilkan.",
-   "noPIDText": "Tidak ada kode akses ditemukan.",
-   "noPIDText2": "Dapatkan kode akses dari pindai QR atau melalui tautan yang disediakan oleh pemegang lisensi TelMessenger.",
-   "loading": "Sedang memuat...",
-   "backToLogin": "Kembali ke halaman login",
-   "deleteHistory": "Hapus Data Riwayat",
-   "deleteHistoryConfirm": "Yakin ingin menghapus data ini?",
-   "couldnotDelete": "Data ini tidak bisa dihapus.",
-   "allInformants": "Semua Pelapor",
-   "welcome": "Selamat Datang",
-   "createNewPassText": "Silakan membuat kata sandi baru sebelum mulai menggunakan aplikasi.",
-   "description": "Keterangan",
-   "sorry": "Maaf ya..!",
-   "outOfWorkTime": "Laporanmu saat ini di luar jam kerja Pelaksana.",
-   "willResponse": "Mereka akan kembali lagi pada: ",
-   "canNotCancel1": "Laporan ini tidak dapat dibatalkan saat sudah dikerjakan oleh Pelaksana.",
-   "canNotCancel2": "Laporan ini tidak dapat dibatalkan.",
-   "priorityHigh": "Tinggi",
-   "priorityLow": "Rendah",
-   "priorityNormal": "Normal",
-   "priority": "Prioritas",
-   "reported": "Dilaporkan",
-   "escalationNoteBySystem": "Penunjukan",
-   "finishAttachment": "Lampiran Penyelesaian",
-   "pleaseScan": "Silakan pindai kode QR",
-   "mustScan": "Kamu harus pindai kode QR untuk lapor ulang.",
-   "changeCodeMsg": "Anda akan terhubung dengan <company_name>. Apakah ingin tetap melanjutkan?",
-   "currentServer": "Server saat ini",
-   "destinationServer": "Server tujuan",
-   "textContinue": "Lanjutkan",
-   "transferNoteBySystem": "Pengalihan",
-   "activity": "Aktifitas",
-   "image": "Gambar",
-   "titlePassOld": "Masukkan kata sandi lama Anda",
-   "titlePassNew": "Password lama Anda akan diganti dengan yang baru.",
-   "setting": "Pengaturan",
-   "more": "Lainnya",
-   "topMenu": "Menu Utama",
-   "availableMenu": "Menu Tersedia",
-   "customize": "Sesuaikan",
-   "done": "Selesai",
-   "ongoing": "Berlangsung",
-   "maxMenu": "Maksimal 7 menu.",
-   "searchIn": "Cari di",
-   "yourLocation": "Lokasi Anda",
-   "addImage": "Ingin menambahkan gambar?",
-   "addImageMsg": "Anda dapat mengirimkan gambar sebagai petunjuk untuk Pelaksana.",
-   "removeImageMsg": "Saya rasa tidak perlu. Hapus saja gambarnya.",
-   "sendingOpt": "Opsi Pengiriman",
-   "sendingOptMsg": "Apakah Anda ingin mengirim sebagai permintaan terjadwal atau segera?",
-   "scheduled": "Jadwalkan",
-   "sendNow": "Kirim Sekarang",
-   "scheduledMsg": "* Jadwalkan = request akan dikirim pada waktu yang kamu pilih di note.",
-   "reqSuccessMsg": "Mohon tunggu. Permintaan Anda sedang diproses.",
-   "noImgAttach": "Tidak ada gambar yang dilampirkan.",
-   "btnWait": "Oke, saya akan menunggu",
-   "rateReq": "Nilai Permintaan Anda",
-   "reqAgain": "Minta Lagi",
-   "notAvailable": "Menu ini belum tersedia.",
-   "emptyMenuAlert": "Belum ada menu yang dipilih nih.",
-   "redirecting": "Memuat...",
-   "initializing": "Memproses...",
-   "selectAlert": "Silakan pilih menu terlebih dahulu.",
-   "scopeDesc": "Gunakan ini untuk mengganti lingkup Anda.",
-   "notFoundKeyword": "Tidak ditemukan data yang sesuai dengan kata pencarian ",
-   "findQRcode": "Temukan kode QR di sekitar Anda",
-   "isWorking": " sedang mengerjakan permintaan Anda.",
-   "noteLongAlert": "Anda hanya boleh menambahkan catatan maksimal 128 karakter.",
-   "reqCodeNotFound": "Kode laporan tidak valid. Silakan menghubungi Administrator",
-   "noImage": "Tidak Ada Gambar",
-   "related": "Layanan Terkait",
-   "broadcastPermission": "Tidak dapat mengirim pesan, Anda tidak memiliki izin.",
-   "broadcastTenant": "Tidak dapat mengirim pesan, Tenant penerima tidak valid.",
-   "reqForOthers": "Tentu, saya suka membantu orang lain.",
-   "reqForMySelf": "Tidak, permintaan ini untuk saya sendiri.",
-   "requestedBy": "Diminta oleh",
-   "requestedFor": "Diminta untuk",
-   "typeId": "Tuliskan ID orang tersebut",
-   "idNotMatch": "Permintaan pengiriman gagal. Permintaan ini tidak diizinkan untuk diminta oleh #ID.",
-   "idNotFound": "Tidak dapat menemukan ID yang diberikan. Silakan coba ID lain.",
-   "informantNotRegistered": "Anda tidak terdaftar sebagai resepsionis atau petugas kamar.",
-   "link_copied": "Link telah disalin ke clipboard.",
-   "do_not_disturb": "Jangan Ganggu",
-   "set_dnd_status": "Tetapkan Status DND",
-   "active_dnd": "Aktif",
-   "inactive_dnd": "Tidak Aktif",
-   "msg_dnd": "Anda dapat menonaktifkan status DND anda melalui menu Akun.",
-   "msg_change_active": "Apakah anda ingin mengaktifkan status DND?",
-   "msg_change_inactive": "Apakah anda ingin menonaktifkan status DND?",
-   "info_dnd": "Status DND Diaktifkan.",
-   "invalid_bridge": "Bridge URL tidak valid.",
-   "someone_else": "Ingin mengajukan permintaan mewakili orang lain?",
-   "askScheduleTime": "Kapan permintaanmu seharusnya dikerjakan?",
-   "scheduleMessage": "Permintaanmu akan dikerjakan nanti pada",
-   "scan_qr": "Tampilkan QR Saya",
-   "show_qr": "Tampilkan QR",
-   "show_qr_desc": "Tunjukkan QR ini kepada teman atau kolega Anda yang perlu mengakses aplikasi.",
-   "dismiss": "Lewati",
-   "not_allow_permission": "Perangkatmu tidak mengizinkan aplikasi untuk menerima pemberitahuan.",
-   "tap_here": "Tap disini untuk ke menu pengaturan.",
-   "doNotDisturb": "Do Not Disturb",
-   "info_label": "Info",
-   "display_menu": "Tampilan Menu",
-   "req_group": "Kelompok Laporan",
-   "ser_group": "Kelompok Pelaksana",
-   "save_rating": "Simpan Penilaian",
-   "auto_translate": "Terjemahkan Otomatis",
-   "hold": "Ditangguhkan",
-   "holdHistory": "Riwayat Penangguhan",
-   "pending": "Tertunda",
-   "pending_info_success": "Kami menemukan masalah koneksi. Permintaan Anda sedang menunggu keputusan. Kami akan mengirimkannya lagi saat Anda kembali online.",
-   "pending_info_tiles": "Tunggu koneksi internet untuk mengirim permintaan Anda.",
-   "pending_info_detail": "Permintaan Anda belum terkirim karena masalah koneksi.",
-   "cancel_pending": "Batalkan permintaan saya saja",
-   "sending": "Mengirim",
-   "queued": "Diantrikan",
-   "onProgress": "Dalam Proses",
-   "showLess": "Lebih Sedikit",
-   "customTopMenu": "Sesuaikan Menu Utama",
-   "limitTopMenu": "Menu utama terbatas pada 7 item saja!",
-   "searchButton": "Cari",
-   "allInformantsInfo": "Semua pelapor akan menerima pesan Anda.",
-   "action": "Tindakan",
-   "whatMakesYou": "Apa yang membuatmu",
-   "letMeWrite": "Saya punya pendapat lain!",
-   "writeHere": "Tulis disini..",
-   "ratingAspect": "Aspek Penilaian",
-   "sendingRequest": "Mengirim permintaan",
-   "changePriority": "Ubah Prioritas",
-   "referenceNumber": "Nomor Referensi",
-   "enterTicketNumber": "Masukkan nomor tiket",
-   "subject": "Subyek",
-   "requestReference": "Referensi Permintaan",
-   "endSessionTitle": "Sesi kamu telah habis.",
-   "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.",
-   "chat": "Percakapan"
+  "account": "Akun",
+  "addNote": "Tambah catatan",
+  "addNoteCancel": "Tambah catatan pembatalan",
+  "all": "Semua",
+  "anyNote": "Ada catatan untuk petugas?",
+  "appointment": "Penunjukan",
+  "attach": "Lampirkan gambar",
+  "buttonCancel": "Batalkan Misi",
+  "buttonLogin": "Masuk",
+  "buttonNo": "GA JADI",
+  "buttonResubmit": "LAPOR ULANG",
+  "buttonScan": "Pindai QR",
+  "buttonSendEmergency": "KIRIM DARURAT",
+  "buttonSendComplaint": "KIRIM KELUHAN",
+  "buttonSendRequest": "Kirim Permintaan",
+  "buttonYes": "IYA",
+  "buttonSure": "IYA, PASTI",
+  "buttonBack": "Kembali",
+  "canceledBy": "Dibatalkan oleh",
+  "category": "Kategori",
+  "scope": "Lingkup",
+  "changeScope": "Ubah Lingkup",
+  "chatClosed": "Percakapan ini sudah ditutup.",
+  "chooseService": "Pilih layanan yang kamu inginkan",
+  "complaintText": "Ada masalah apa? Biarkan ahlinya yang bekerja untukmu.",
+  "complaint": "Keluhan",
+  "defaultLocation": "Lokasi Bawaan",
+  "detail": "Rincian",
+  "disatisfied": "Tidak puas",
+  "emergencyText": "Semua hal genting & mendesak yang harus segera ditangani.",
+  "emergency": "Darurat",
+  "forum": "Forum",
+  "frequentlyText": "Yang sering kamu minta kita kumpulin di sini ya.",
+  "frequently": "Sering diminta",
+  "frequentlyTitle": "Sering Diminta",
+  "frequentlyTitleText": "Pelaporan yang sering diminta",
+  "history": "Riwayat",
+  "lessSatisfied": "Kurang puas",
+  "location": "Lokasi",
+  "logout": "Keluar",
+  "menuAccount": "Akun",
+  "menuHistory": "Riwayat",
+  "menuService": "Layanan",
+  "menuHome": "Beranda",
+  "message": "Pesan",
+  "note": "Catatan",
+  "passwordEmpty": "Kata sandi tidak boleh kosong",
+  "password": "Kata sandi",
+  "phoneNumber": "Nomor Telepon",
+  "placeholderLocation": "Tulis lokasi",
+  "placeholderNote": "Tulis catatan",
+  "rateMission": "Beri penilaian misi ini",
+  "reallyPleased": "Sangat puas",
+  "requestText2": "Apa yang diminta?",
+  "requestDesc": "Jika kamu butuh bantuan, jangan sungkan yaa.",
+  "requestTitle": "Kamu butuh bantuan apa?",
+  "request": "Permintaan",
+  "satisfactionAsk": "Apa kamu puas?",
+  "satisfied": "Cukup puas",
+  "scanQr": "Silahkan pindai QR terlebih dulu untuk memulai menggunakan aplikasi.",
+  "serialNumber": "No. Seri",
+  "servantGroup": "Kel. Laporan",
+  "servant": "Pelaksana",
+  "service": "Layanan",
+  "specifyAnotherLocation": "Saya sedang di lokasi lain",
+  "specifyLocation": "Tentukan Lokasi",
+  "startDoing": "Mulai Dikerjakan",
+  "stateCancel": "Batal",
+  "stateCanceled": "Dibatalkan",
+  "stateDone": "Dikerjakan",
+  "stateFinish": "Selesai",
+  "stateQueue": "Antrian",
+  "stateRequested": "Diminta",
+  "state": "Status",
+  "sure": "Sudah yakin?",
+  "switch": "Pengalihan",
+  "system": "Sistem",
+  "textCancel": "Batal",
+  "textHistory": "Laporan yang telah kamu buat",
+  "textLogout": "Nanti kamu ga bisa lagi menerima pemberitahuan, membuat pelaporan dan kegiatan yang lain. Yakin mau keluar?",
+  "textResubmit": "Kamu akan mengirim ulang laporan ini kepada Petugas.",
+  "ticketNumber": "Nomor Tiket",
+  "timeline": "Linimasa",
+  "today": "Hari ini",
+  "unrated": "Belum ada penilaian untuk misi ini",
+  "userEmpty": "Nama Pengguna tidak boleh kosong",
+  "userId": "Nama Pengguna",
+  "version": "Versi ",
+  "verySatisfied": "Puas",
+  "whatComplain": "Apa keluhannya?",
+  "whatHappen": "Apa yang terjadi?",
+  "whatNext": "Tetap tenang. Apa info selanjutnya?",
+  "whatProblem": "Apa yang bermasalah?",
+  "writeMessage": "Tulis pesan",
+  "yesterday": "Kemarin",
+  "language": "Bahasa",
+  "bahasa": "Indonesia",
+  "english": "English",
+  "japanese": "日本語",
+  "korean": "한국어",
+  "chinese": "中文",
+  "german": "Deutsch",
+  "french": "Français",
+  "hindi": "हिंदी",
+  "arabic": "العربية",
+  "dutch": "Nederlands",
+  "chooseLanguage": "Pilih Bahasa",
+  "rate": "Penilaian",
+  "rated": "Penilaian sudah diberikan.",
+  "rateText": "Kamu [satisfaction] terhadap misi ini.",
+  "settingPassword": "Ubah Kata Sandi",
+  "oldPassword": "Kata sandi lama",
+  "newPassword": "Kata sandi baru",
+  "confirmPassword": "Konfirmasi sandi baru",
+  "buttonSave": "Simpan Sandi Baru",
+  "settingPasswordText": "Atur kata sandi kamu disini",
+  "autoResponseText": "Permintaan kamu akan ditanggapi segera oleh sistem.",
+  "reply": "Balasan",
+  "selectPicture": "Pilih Media",
+  "fromGallery": "Dari Galeri",
+  "fromCamera": "Ambil Foto",
+  "sendPicture": "Kirim Gambar",
+  "seeAttachment": "Lihat Lampiran",
+  "confirmCancel": "Yakin mau dibatalkan?",
+  "selectDate": "Pilih tanggal",
+  "lengthMax": "Panjang catatan maksimal 128 karakter.",
+  "locRequired": "Lokasi tidak boleh kosong.",
+  "idRequired": "ID tidak boleh kosong.",
+  "dateRequired": "Tanggal tidak boleh kosong.",
+  "sendLater": "Kirim Nanti",
+  "thank": "Terimakasih",
+  "pleaseWait": "Mohon ditunggu",
+  "sendSuccess": "Berhasil Dikirim",
+  "followUp": "petugas akan segera menindaklanjuti.",
+  "okGot": "OK, MENGERTI",
+  "okWait": "OK, DITUNGGU",
+  "errorConnection": "Kesalahan koneksi. Coba beberapa saat lagi.",
+  "noInternet": "Yaah, internetnya mati.",
+  "invalidLogin": "Nama Pengguna atau Kata Sandi salah.",
+  "invalidPhone": "Nomor Telepon tidak terdaftar.",
+  "expAccount": "Akun sudah kedaluwarsa.",
+  "errorServer": "Terjadi kesalahan pada server. Coba beberapa saat lagi.",
+  "accessDenied": "Akses Ditolak",
+  "licenseProblem": "Aplikasi tidak dapat digunakan karena bermasalah dengan lisensi.",
+  "invalidVersion": "Versi Aplikasi Tidak Sesuai",
+  "sugestVersion": "Gunakan aplikasi dengan versi",
+  "currentVersion": "Versi aplikasi terpasang adalah",
+  "contactAdmin": "Silahkan menghubungi Administrator untuk keterangan lebih lanjut.",
+  "pressAgain": "Tekan lagi untuk keluar.",
+  "notFound": "Data tidak ditemukan.",
+  "notFound2": "Apa yang kamu cari tidak ada di sini..!",
+  "noInternetTitle": "Tidak ada sambungan internet.",
+  "noInternetDesc": "Periksa dulu sambungan internetmu. Nanti kita lanjutin lagi!",
+  "errorConnectTitle": "Gagal menyambungkan ke server.",
+  "errorConnectDesc": "Tanya ke administrator, harusnya kamu udah bisa nyambung ke server.",
+  "errorServerTitle": "Sedang ada masalah di server.",
+  "errorServerDesc": "Jangan panik, kami sedang berusaha keras agar semua aman terkendali.",
+  "invalidAccountTitle": "Akun tidak terdaftar.",
+  "invalidAccountDesc": "Upps! Akun kamu ga bisa diverifikasi. Coba deh tanyakan ke Administrator.",
+  "expAccountTitle": "Akun sudah kedaluwarsa.",
+  "expAccountDesc": "Kamu ga bisa masuk ke aplikasi karena akunmu sudah kedaluwarsa. Kalau menurutmu ini adalah kesalahan, langsung saja hubungi administrator ya.",
+  "inProcess": "Sedang diproses",
+  "policy": "Kebijakan Privasi",
+  "info": "Info Tambahan",
+  "refresh": "Muat Ulang",
+  "messageCamPermission": "Akses kamera ditolak. Izinkan TelMessenger mengakses kamera melalui menu pengaturan.",
+  "messageInvalidCode": "Kode tidak valid. Silahkan hubungi administrator.",
+  "messagePassChanged": "Kata sandi berhasil diubah.",
+  "wrongOldPass": "Kata sandi lama salah.",
+  "checkNewPass": "Periksa kembali kata sandi baru.",
+  "cannotEmpty": "Data tidak boleh kosong.",
+  "deletedMessage": "Pesan ini telah dihapus.",
+  "resend": "Kirim Ulang",
+  "delete": "Hapus",
+  "alreadyUsePass": "Kata sandi tidak dapat digunakan, coba yang lain.",
+  "notFoundImg": "Gambar tidak ditemukan",
+  "notFoundWorktime":  "Jam kerja tidak ditemukan. Silahkan hubungi Administrator.",
+  "seeAll": "Lihat Semua",
+  "quickAction": "Aksi cepat",
+  "quickDesc": "Biar permintaan kamu lebih cepat.",
+  "times": " kali",
+  "search": "Pencarian",
+  "searchAsk": "Cari...",
+  "helpHint": "Coba tulis masalahmu..",
+  "inProgress": " permintaan kamu sedang diproses.",
+  "currentActiveText": "Laporanmu yg masih diproses",
+  "photo": "Gambar",
+  "selectRecipient": "Pilih penerima",
+  "composeMessage": "Buat pesan",
+  "to": "Kepada",
+  "addAttachment": "Tambah lampiran",
+  "editAttachment": "Ubah lampiran",
+  "unsupportedFile": "Format file tidak didukung",
+  "pdfFile": "File PDF",
+  "other": "lainnya",
+  "noMessageText": "Tidak ada pesan yg ditampilkan.",
+  "noDataText": "Tidak ada data untuk ditampilkan.",
+  "noPIDText": "Tidak ada kode akses ditemukan.",
+  "noPIDText2": "Dapatkan kode akses dari pindai QR atau melalui tautan yang disediakan oleh pemegang lisensi TelMessenger.",
+  "loading": "Sedang memuat...",
+  "backToLogin": "Kembali ke halaman login",
+  "deleteHistory": "Hapus Data Riwayat",
+  "deleteHistoryConfirm": "Yakin ingin menghapus data ini?",
+  "couldnotDelete": "Data ini tidak bisa dihapus.",
+  "allInformants": "Semua Pelapor",
+  "welcome": "Selamat Datang",
+  "createNewPassText": "Silakan membuat kata sandi baru sebelum mulai menggunakan aplikasi.",
+  "description": "Keterangan",
+  "sorry": "Maaf ya..!",
+  "outOfWorkTime": "Laporanmu saat ini di luar jam kerja Pelaksana.",
+  "willResponse": "Mereka akan kembali lagi pada: ",
+  "canNotCancel1": "Laporan ini tidak dapat dibatalkan saat sudah dikerjakan oleh Pelaksana.",
+  "canNotCancel2": "Laporan ini tidak dapat dibatalkan.",
+  "priorityHigh": "Tinggi",
+  "priorityLow": "Rendah",
+  "priorityNormal": "Normal",
+  "priority": "Prioritas",
+  "reported": "Dilaporkan",
+  "escalationNoteBySystem": "Penunjukan",
+  "finishAttachment": "Lampiran Penyelesaian",
+  "pleaseScan": "Silakan pindai kode QR",
+  "mustScan": "Kamu harus pindai kode QR untuk lapor ulang.",
+  "changeCodeMsg": "Anda akan terhubung dengan <company_name>. Apakah ingin tetap melanjutkan?",
+  "currentServer": "Server saat ini",
+  "destinationServer": "Server tujuan",
+  "textContinue": "Lanjutkan",
+  "transferNoteBySystem": "Pengalihan",
+  "activity": "Aktifitas",
+  "image": "Gambar",
+  "titlePassOld": "Masukkan kata sandi lama Anda",
+  "titlePassNew": "Password lama Anda akan diganti dengan yang baru.",
+  "setting": "Pengaturan",
+  "more": "Lainnya",
+  "topMenu": "Menu Utama",
+  "availableMenu": "Menu Tersedia",
+  "customize": "Sesuaikan",
+  "done": "Selesai",
+  "ongoing": "Berlangsung",
+  "maxMenu": "Maksimal 7 menu.",
+  "searchIn": "Cari di",
+  "yourLocation": "Lokasi Anda",
+  "addImage": "Ingin menambahkan gambar?",
+  "addImageMsg": "Anda dapat mengirimkan gambar sebagai petunjuk untuk Pelaksana.",
+  "removeImageMsg": "Saya rasa tidak perlu. Hapus saja gambarnya.",
+  "sendingOpt": "Opsi Pengiriman",
+  "sendingOptMsg": "Apakah Anda ingin mengirim sebagai permintaan terjadwal atau segera?",
+  "scheduled": "Jadwalkan",
+  "sendNow": "Kirim Sekarang",
+  "scheduledMsg": "* Jadwalkan = request akan dikirim pada waktu yang kamu pilih di note.",
+  "reqSuccessMsg": "Mohon tunggu. Permintaan Anda sedang diproses.",
+  "noImgAttach": "Tidak ada gambar yang dilampirkan.",
+  "btnWait": "Oke, saya akan menunggu",
+  "rateReq": "Nilai Permintaan Anda",
+  "reqAgain": "Minta Lagi",
+  "notAvailable": "Menu ini belum tersedia.",
+  "emptyMenuAlert": "Belum ada menu yang dipilih nih.",
+  "redirecting": "Memuat...",
+  "initializing": "Memproses...",
+  "selectAlert": "Silakan pilih menu terlebih dahulu.",
+  "scopeDesc": "Gunakan ini untuk mengganti lingkup Anda.",
+  "notFoundKeyword": "Tidak ditemukan data yang sesuai dengan kata pencarian ",
+  "findQRcode": "Temukan kode QR di sekitar Anda",
+  "isWorking": " sedang mengerjakan permintaan Anda.",
+  "noteLongAlert": "Anda hanya boleh menambahkan catatan maksimal 128 karakter.",
+  "reqCodeNotFound": "Kode laporan tidak valid. Silakan menghubungi Administrator",
+  "noImage": "Tidak Ada Gambar",
+  "related": "Layanan Terkait",
+  "broadcastPermission": "Tidak dapat mengirim pesan, Anda tidak memiliki izin.",
+  "broadcastTenant": "Tidak dapat mengirim pesan, Tenant penerima tidak valid.",
+  "reqForOthers": "Tentu, saya suka membantu orang lain.",
+  "reqForMySelf": "Tidak, permintaan ini untuk saya sendiri.",
+  "requestedBy": "Diminta oleh",
+  "requestedFor": "Diminta untuk",
+  "typeId": "Tuliskan ID orang tersebut",
+  "idNotMatch": "Permintaan pengiriman gagal. Permintaan ini tidak diizinkan untuk diminta oleh #ID.",
+  "idNotFound": "Tidak dapat menemukan ID yang diberikan. Silakan coba ID lain.",
+  "informantNotRegistered": "Anda tidak terdaftar sebagai resepsionis atau petugas kamar.",
+  "link_copied": "Link telah disalin ke clipboard.",
+  "do_not_disturb": "Jangan Ganggu",
+  "set_dnd_status": "Tetapkan Status DND",
+  "active_dnd": "Aktif",
+  "inactive_dnd": "Tidak Aktif",
+  "msg_dnd": "Anda dapat menonaktifkan status DND anda melalui menu Akun.",
+  "msg_change_active": "Apakah anda ingin mengaktifkan status DND?",
+  "msg_change_inactive": "Apakah anda ingin menonaktifkan status DND?",
+  "info_dnd": "Status DND Diaktifkan.",
+  "invalid_bridge": "Bridge URL tidak valid.",
+  "someone_else": "Ingin mengajukan permintaan mewakili orang lain?",
+  "askScheduleTime": "Kapan permintaanmu seharusnya dikerjakan?",
+  "scheduleMessage": "Permintaanmu akan dikerjakan nanti pada",
+  "scan_qr": "Tampilkan QR Saya",
+  "show_qr": "Tampilkan QR",
+  "show_qr_desc": "Tunjukkan QR ini kepada teman atau kolega Anda yang perlu mengakses aplikasi.",
+  "dismiss": "Lewati",
+  "not_allow_permission": "Perangkatmu tidak mengizinkan aplikasi untuk menerima pemberitahuan.",
+  "tap_here": "Tap disini untuk ke menu pengaturan.",
+  "doNotDisturb": "Do Not Disturb",
+  "info_label": "Info",
+  "display_menu": "Tampilan Menu",
+  "req_group": "Kelompok Laporan",
+  "ser_group": "Kelompok Pelaksana",
+  "save_rating": "Simpan Penilaian",
+  "auto_translate": "Terjemahkan Otomatis",
+  "hold": "Ditangguhkan",
+  "holdHistory": "Riwayat Penangguhan",
+  "pending": "Tertunda",
+  "pending_info_success": "Kami menemukan masalah koneksi. Permintaan Anda sedang menunggu keputusan. Kami akan mengirimkannya lagi saat Anda kembali online.",
+  "pending_info_tiles": "Tunggu koneksi internet untuk mengirim permintaan Anda.",
+  "pending_info_detail": "Permintaan Anda belum terkirim karena masalah koneksi.",
+  "cancel_pending": "Batalkan permintaan saya saja",
+  "sending": "Mengirim",
+  "queued": "Diantrikan",
+  "onProgress": "Dalam Proses",
+  "showLess": "Lebih Sedikit",
+  "customTopMenu": "Sesuaikan Menu Utama",
+  "limitTopMenu": "Menu utama terbatas pada 7 item saja!",
+  "searchButton": "Cari",
+  "allInformantsInfo": "Semua pelapor akan menerima pesan Anda.",
+  "action": "Tindakan",
+  "whatMakesYou": "Apa yang membuatmu",
+  "letMeWrite": "Saya punya pendapat lain!",
+  "writeHere": "Tulis disini..",
+  "ratingAspect": "Aspek Penilaian",
+  "sendingRequest": "Mengirim permintaan",
+  "changePriority": "Ubah Prioritas",
+  "referenceNumber": "Nomor Referensi",
+  "enterTicketNumber": "Masukkan nomor tiket",
+  "subject": "Subyek",
+  "requestReference": "Referensi Permintaan",
+  "endSessionTitle": "Sesi kamu telah habis.",
+  "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.",
+  "chat": "Percakapan",
+  "asset": "Aset",
+  "selectAsset": "Pilih Aset",
+  "addAsset": "Tambah Aset",
+  "assetList": "Daftar Aset",
+  "noDataSelected": "Tidak ada data yang dipilih.",
+  "noAssetAdded": "Tidak ada aset yang didaftarkan.",
+  "addLabel": "Tambah"
 }

+ 340 - 333
assets/lang/ja.json

@@ -1,335 +1,342 @@
 {
-   "account": "アカウント",
-   "addNote": "メモを追加",
-   "addNoteCancel": "キャンセルメモを追加",
-   "all": "全て",
-   "anyNote": "使用人へのメモ",
-   "appointment": "予定",
-   "attach": "画像を添付",
-   "buttonCancel": "キャンセルリクエスト",
-   "buttonLogin": "ログイン",
-   "buttonNo": "いいえ",
-   "buttonResubmit": "再送信する",
-   "buttonScan": "QRをスキャン",
-   "buttonSendEmergency": "緊急を送る",
-   "buttonSendComplaint": "苦情を送信する",
-   "buttonSendRequest": "リクエストの送信",
-   "buttonYes": "はい",
-   "buttonSure": "もちろん",
-   "buttonBack": "戻る",
-   "canceledBy": "キャンセル者",
-   "category": "カテゴリー",
-   "scope": "範囲",
-   "changeScope": "スコープの変更",
-   "chatClosed": "この会話は終了しました。",
-   "chooseService": "ご希望のサービスを選択してください",
-   "complaintText": "どうしたの? 専門家があなたのために働きましょう。",
-   "complaint": "苦情",
-   "defaultLocation": "デフォルトの場所",
-   "detail": "詳細",
-   "disatisfied": "不満",
-   "emergencyText": "緊急のことはすべて急いで行う必要があります。",
-   "emergency": "緊急",
-   "forum": "フォーラム",
-   "frequentlyText": "ここでよくリクエストされたもの。",
-   "frequently": "よくあるご要望",
-   "frequentlyTitle": "よくあるご要望",
-   "frequentlyTitleText": "よくリクエストされるリスト",
-   "history": "歴史",
-   "lessSatisfied": "あまり満足していない",
-   "location": "位置",
-   "logout": "ログアウト",
-   "menuAccount": "アカウント",
-   "menuHistory": "歴史",
-   "menuService": "サービス",
-   "menuHome": "家",
-   "message": "メッセージ",
-   "note": "注記",
-   "passwordEmpty": "パスワードを空にすることはできません",
-   "password": "パスワード",
-   "phoneNumber": "電話番号",
-   "placeholderLocation": "どこにいるの?",
-   "placeholderNote": "メモを入力する",
-   "rateMission": "このミッションを評価する",
-   "reallyPleased": "本当に満足です",
-   "requestText2": "何を求めているのですか?",
-   "requestDesc": "助けが必要なときは、タップするだけです。",
-   "requestTitle": "どのような助けが必要ですか?",
-   "request": "リクエスト",
-   "satisfactionAsk": "あなたは満足していますか?",
-   "satisfied": "かなり満足",
-   "scanQr": "アプリケーションの使用を開始するには、まず QR コードをスキャンしてください。",
-   "serialNumber": "シリアルナンバー",
-   "servantGroup": "リクエストグループ",
-   "servant": "サーバント",
-   "service": "サービス",
-   "specifyAnotherLocation": "別の場所を指定したい",
-   "specifyLocation": "場所を定義する",
-   "startDoing": "始める",
-   "stateCancel": "キャンセル",
-   "stateCanceled": "キャンセル",
-   "stateDone": "進行中",
-   "stateFinish": "仕上げる",
-   "stateQueue": "列",
-   "stateRequested": "リクエスト済み",
-   "state": "状態",
-   "sure": "本気ですか?",
-   "switch": "スイッチ",
-   "system": "システム",
-   "textCancel": "キャンセル",
-   "textHistory": "あなたが行ったリクエスト",
-   "textLogout": "ログアウトすると通知の受信やリクエストなどができなくなります。 もちろん?",
-   "textResubmit": "このリクエストをサーバントに再送信します。",
-   "ticketNumber": "チケット番号",
-   "timeline": "タイムライン",
-   "today": "今日",
-   "unrated": "このミッションはまだ評価されていません",
-   "userEmpty": "ユーザー名を空にすることはできません",
-   "userId": "ユーザー名",
-   "version": "バージョン ",
-   "verySatisfied": "満足",
-   "whatComplain": "何の苦情ですか?",
-   "whatHappen": "どうしたの?",
-   "whatNext": "落ち着いてください。 次は何?",
-   "whatProblem": "何が困っているのですか?",
-   "writeMessage": "メッセージを書く",
-   "yesterday": "昨日",
-   "language": "言語",
-   "bahasa": "Indonesia",
-   "english": "English",
-   "japanese": "日本語",
-   "korean": "한국어",
-   "chinese": "中文",
-   "german": "Deutsch",
-   "french": "Français",
-   "hindi": "हिंदी",
-   "arabic": "العربية",
-   "dutch": "Nederlands",
-   "chooseLanguage": "言語を選択する",
-   "rate": "レート",
-   "rated": "このミッションは評価されています。",
-   "rateText": "あなたはこの使命に[満足]しています。",
-   "settingPassword": "パスワードを変更する",
-   "oldPassword": "以前のパスワード",
-   "newPassword": "新しいパスワード",
-   "confirmPassword": "新しいパスワードを確認",
-   "buttonSave": "新しいパスワードを保存する",
-   "settingPasswordText": "パスワードを管理する",
-   "autoResponseText": "あなたのリクエストはすぐにシステムによって応答されます。",
-   "reply": "返事",
-   "selectPicture": "画像を選択",
-   "fromGallery": "ギャラリーから",
-   "fromCamera": "カメラから",
-   "sendPicture": "写真を送る",
-   "seeAttachment": "添付ファイルを参照してください",
-   "confirmCancel": "本当にキャンセルしてもよろしいですか?",
-   "selectDate": "日付を選択してください",
-   "lengthMax": "最大長は 128 文字です。",
-   "locRequired": "場所は必須です。",
-   "idRequired": "身分証明書が必要です。",
-   "dateRequired": "日付は必須です。",
-   "sendLater": "後で送信",
-   "thank": "ありがとう",
-   "pleaseWait": "お待ちください",
-   "sendSuccess": "正常に送信されました",
-   "followUp": "使用人はすぐに応答します。",
-   "okGot": "はい、わかった",
-   "okWait": "わかりました、確かに",
-   "errorConnection": "接続エラー。 数分後にもう一度試してください。",
-   "noInternet": "インターネットアクセスなし。",
-   "invalidLogin": "ユーザー名またはパスワードが間違っています。",
-   "invalidPhone": "電話番号が無効です。",
-   "expAccount": "アカウントの有効期限が切れています。",
-   "errorServer": "サーバーエラー。 数分後にもう一度試してください。",
-   "accessDenied": "アクセスが拒否されました",
-   "licenseProblem": "ライセンスに問題があるため、アプリケーションを実行できませんでした。",
-   "invalidVersion": "バージョンが一致しません",
-   "sugestVersion": "アプリケーションのバージョンを使用する",
-   "currentVersion": "現在のバージョンは",
-   "contactAdmin": "詳細については、管理者にお問い合わせください。",
-   "pressAgain": "終了するにはもう一度押します。",
-   "notFound": "データが見つかりません。",
-   "notFound2": "あなたが調べようとしているものはここにはありません!",
-   "noInternetTitle": "インターネット接続がありません。",
-   "noInternetDesc": "インターネット接続を確認してください。 今はGoogleに問い合わせることもできません。",
-   "errorConnectTitle": "サーバーに接続できませんでした。",
-   "errorConnectDesc": "管理者に連絡してください。サーバーに接続できるはずです。",
-   "errorServerTitle": "サーバーエラー。",
-   "errorServerDesc": "慌てる必要はありません。私たちはすべてを軌道に乗せようと努めています。",
-   "invalidAccountTitle": "無効なアカウント。",
-   "invalidAccountDesc": "ごめん! あなたのアカウントを確認できませんでした。 詳細については、管理者にお問い合わせください。",
-   "expAccountTitle": "アカウントの有効期限が切れました。",
-   "expAccountDesc": "アカウントの有効期限が切れています。 または、間違いだと思われる場合は、管理者に連絡してください。",
-   "inProcess": "処理",
-   "policy": "プライバシーポリシー",
-   "info": "追加情報",
-   "refresh": "リフレッシュ",
-   "messageCamPermission": "アクセスが拒否されました。 アプリの許可設定を通じて TelMessenger がカメラにアクセスできるようにしてください。",
-   "messageInvalidCode": "無効なコード。 システム管理者に連絡してください。",
-   "messagePassChanged": "パスワードが正常に変更されました。",
-   "wrongOldPass": "古いパスワードが間違っています。",
-   "checkNewPass": "新しいパスワードを確認してください。",
-   "cannotEmpty": "データを空にできませんでした。",
-   "deletedMessage": "このメッセージは削除されました。",
-   "resend": "再送信",
-   "delete": "消去",
-   "alreadyUsePass": "新しいパスワードは使用できませんでした。別のパスワードを定義してください。",
-   "notFoundImg": "画像が見つかりません",
-   "notFoundWorktime": "勤務時間が見つかりませんでした。 管理者に連絡してください。",
-   "seeAll": "すべてを見る",
-   "quickAction": "クイックアクション",
-   "quickDesc": "より効率的に移動するのに役立ちます。",
-   "times": " 回",
-   "search": "検索",
-   "searchAsk": "検索...",
-   "helpHint": "助けを探してみてください。..",
-   "inProgress": " リクエストはまだ進行中です。",
-   "currentActiveText": "現在アクティブなリクエスト",
-   "photo": "写真",
-   "selectRecipient": "受信者の選択",
-   "composeMessage": "メッセージを作成します",
-   "to": "に",
-   "addAttachment": "添付ファイルを追加する",
-   "editAttachment": "添付ファイルの変更",
-   "unsupportedFile": "サポートされていないファイル形式です",
-   "pdfFile": "PDF ファイルの種類",
-   "other": "他の",
-   "noMessageText": "プレビューするメッセージはありません。",
-   "noDataText": "利用可能なプレビュー データはありません。",
-   "noPIDText": "アクセスコードが見つかりません。",
-   "noPIDText2": "TelMessenger ライセンス所有者が提供するスキャン QR またはリンクからアクセス コードを取得します。",
-   "loading": "読み込み中...",
-   "backToLogin": "ログインに戻る",
-   "deleteHistory": "履歴データの削除",
-   "deleteHistoryConfirm": "データを削除してもよろしいですか?",
-   "couldnotDelete": "このデータは削除できませんでした。",
-   "allInformants": "情報提供者の皆様",
-   "welcome": "いらっしゃいませ",
-   "createNewPassText": "アプリケーションの使用を開始する前に、新しいパスワードを作成してください。",
-   "description": "説明",
-   "sorry": "ごめん!",
-   "outOfWorkTime": "あなたのリクエストは現在、サーバントの勤務時間外です。",
-   "willResponse": "彼らはすぐに応答します: ",
-   "canNotCancel1": "この報告は、サーヴァントが行った後はキャンセルできません。",
-   "canNotCancel2": "このレポートはキャンセルできません。",
-   "priorityHigh": "高い",
-   "priorityLow": "低い",
-   "priorityNormal": "普通",
-   "priority": "優先度",
-   "reported": "報告",
-   "escalationNoteBySystem": "エスカレーション",
-   "finishAttachment": "添付ファイルが完成しました",
-   "pleaseScan": "QRコードをスキャンしてください",
-   "mustScan": "再送信するには QR コードをスキャンする必要があります。",
-   "changeCodeMsg": "<company_name> に接続されます。 続けますか?",
-   "currentServer": "現在のサーバー",
-   "destinationServer": "宛先サーバー",
-   "textContinue": "続く",
-   "transferNoteBySystem": "移行",
-   "activity": "活動",
-   "image": "画像",
-   "titlePassOld": "古いパスワードを入力してください",
-   "titlePassNew": "古いパスワードは新しいパスワードに置き換えられます。",
-   "setting": "設定",
-   "more": "もっと",
-   "topMenu": "トップメニュー",
-   "availableMenu": "利用可能なメニュー",
-   "customize": "カスタマイズ",
-   "done": "終わり",
-   "ongoing": "進行中",
-   "maxMenu": "最大7メニュー。",
-   "searchIn": "で検索",
-   "yourLocation": "あなたの場所",
-   "addImage": "写真を追加したいですか?",
-   "addImageMsg": "手がかりなどとして写真を送っていただけます。",
-   "removeImageMsg": "いいえ、必要ありません。削除したいと思います。",
-   "sendingOpt": "配送オプション",
-   "sendingOptMsg": "スケジュールされたリクエストとして送信しますか? それともすぐに送信しますか?",
-   "scheduled": "予定されている",
-   "sendNow": "今すぐ送信",
-   "scheduledMsg": "* スケジュール済み = メモで選択した時間にリクエストが送信されます。",
-   "reqSuccessMsg": "お待ちください。 リクエストは処理中です。",
-   "noImgAttach": "画像は添付されていません。",
-   "btnWait": "わかりました、待ってます",
-   "rateReq": "リクエストを評価してください",
-   "reqAgain": "再リクエスト",
-   "notAvailable": "このメニューはご利用いただけません。",
-   "emptyMenuAlert": "表示するメニューが選択されていません。",
-   "redirecting": "リダイレクト中...",
-   "initializing": "初期化中...",
-   "selectAlert": "少なくとも 1 つのメニューを選択してください。",
-   "scopeDesc": "これを使用してスコープを切り替えます。",
-   "notFoundKeyword": "キーワードに一致するものが見つかりませんでした ",
-   "findQRcode": "近くの QR コードを探す",
-   "isWorking": " あなたのリクエストに取り組んでいます。",
-   "noteLongAlert": "128 文字未満のメモを追加してください。",
-   "reqCodeNotFound": "リクエストコードが無効です。 管理者に連絡してください",
-   "noImage": "画像が見つかりません",
-   "related": "関連サービス",
-   "broadcastPermission": "権限がないため、ブロードキャスト メッセージを送信できません。",
-   "broadcastTenant": "ブロードキャスト メッセージを送信できません。受信者のテナントが無効です。",
-   "reqForOthers": "はい、私は他の人を助けるのが好きです。",
-   "reqForMySelf": "いいえ、私は自分自身のために要求しています。",
-   "requestedBy": "に要求された",
-   "requestedFor": "要求された",
-   "typeId": "彼女/彼のIDを入力してください",
-   "idNotMatch": "送信リクエストが失敗しました。 このリクエストは #ID がリクエストすることを許可されていません。",
-   "idNotFound": "指定された ID が見つかりませんでした。 別のIDをお試しください。",
-   "informantNotRegistered": "あなたは受付係または客室係として登録されていません。",
-   "link_copied": "リンクがクリップボードにコピーされました。",
-   "do_not_disturb": "邪魔しないでください",
-   "set_dnd_status": "サイレント ステータスの設定",
-   "active_dnd": "アクティブ",
-   "inactive_dnd": "非活動中",
-   "msg_dnd": "アカウント メニューから DND ステータスを無効化できます。",
-   "msg_change_active": "DND ステータスを有効にしますか?",
-   "msg_change_inactive": "DND ステータスを無効にしますか?",
-   "info_dnd": "DND ステータスがアクティブ化されました。",
-   "invalid_bridge": "無効なブリッジ URL。",
-   "someone_else": "他の人のリクエストを送信したいですか?",
-   "askScheduleTime": "リクエストはいつ完了する必要がありますか?",
-   "scheduleMessage": "リクエストは次の日に行われるはずです",
-   "scan_qr": "私のQRを表示",
-   "show_qr": "QRを表示",
-   "show_qr_desc": "アプリにアクセスする必要がある友人や同僚にこの QR を見せてください。",
-   "dismiss": "却下する",
-   "not_allow_permission": "お使いのデバイスでは、アプリによる通知の送信が許可されていません。",
-   "tap_here": "ここをタップして通知許可を許可します。",
-   "doNotDisturb": "邪魔しないモード",
-   "info_label": "情報",
-   "display_menu": "メニュー表示",
-   "req_group": "リクエストグループ",
-   "ser_group": "サーヴァントグループ",
-   "save_rating": "評価の保存",
-   "auto_translate": "自動翻訳",
-   "hold": "一時停止中",
-   "holdHistory": "停止履歴",
-   "pending": "保留中",
-   "pending_info_success": "接続の問題が見つかりました。リクエストは保留中です。オンラインに戻ったら再度送信します。",
-   "pending_info_tiles": "インターネット接続がリクエストを送信するまで待ちます。",
-   "pending_info_detail": "接続の問題のため、リクエストはまだ送信されていません。",
-   "cancel_pending": "代わりにリクエストをキャンセルしてください",
-   "sending": "送信",
-   "queued": "キューに入れられました",
-   "onProgress": "進行中",
-   "showLess": "あまり見せない",
-   "customTopMenu": "トップメニューのカスタマイズ",
-   "limitTopMenu": "上位メニューは限定7品!",
-   "searchButton": "探す",
-   "allInformantsInfo": "すべての情報提供者があなたのメッセージを受け取ります。",
-   "action": "アクション",
-   "whatMakesYou": "何があなたを作っているのか",
-   "letMeWrite": "書かせてください!",
-   "writeHere": "ここに書いてください。",
-   "ratingAspect": "評価面",
-   "sendingRequest": "リクエストの送信",
-   "changePriority": "優先順位を変更する",
-   "referenceNumber": "参照番号",
-   "enterTicketNumber": "チケット番号を入力してください",
-   "subject": "主題",
-   "requestReference": "リクエストリファレンス",
-   "invalidParentTicket": "親チケットが無効です。",
-   "failedLoad": "アプリケーションのロードに失敗しました。",
-   "tap2retry": "タップして再試行します。",
-   "chat": "会話"
+  "account": "アカウント",
+  "addNote": "メモを追加",
+  "addNoteCancel": "キャンセルメモを追加",
+  "all": "全て",
+  "anyNote": "使用人へのメモ",
+  "appointment": "予定",
+  "attach": "画像を添付",
+  "buttonCancel": "キャンセルリクエスト",
+  "buttonLogin": "ログイン",
+  "buttonNo": "いいえ",
+  "buttonResubmit": "再送信する",
+  "buttonScan": "QRをスキャン",
+  "buttonSendEmergency": "緊急を送る",
+  "buttonSendComplaint": "苦情を送信する",
+  "buttonSendRequest": "リクエストの送信",
+  "buttonYes": "はい",
+  "buttonSure": "もちろん",
+  "buttonBack": "戻る",
+  "canceledBy": "キャンセル者",
+  "category": "カテゴリー",
+  "scope": "範囲",
+  "changeScope": "スコープの変更",
+  "chatClosed": "この会話は終了しました。",
+  "chooseService": "ご希望のサービスを選択してください",
+  "complaintText": "どうしたの? 専門家があなたのために働きましょう。",
+  "complaint": "苦情",
+  "defaultLocation": "デフォルトの場所",
+  "detail": "詳細",
+  "disatisfied": "不満",
+  "emergencyText": "緊急のことはすべて急いで行う必要があります。",
+  "emergency": "緊急",
+  "forum": "フォーラム",
+  "frequentlyText": "ここでよくリクエストされたもの。",
+  "frequently": "よくあるご要望",
+  "frequentlyTitle": "よくあるご要望",
+  "frequentlyTitleText": "よくリクエストされるリスト",
+  "history": "歴史",
+  "lessSatisfied": "あまり満足していない",
+  "location": "位置",
+  "logout": "ログアウト",
+  "menuAccount": "アカウント",
+  "menuHistory": "歴史",
+  "menuService": "サービス",
+  "menuHome": "家",
+  "message": "メッセージ",
+  "note": "注記",
+  "passwordEmpty": "パスワードを空にすることはできません",
+  "password": "パスワード",
+  "phoneNumber": "電話番号",
+  "placeholderLocation": "どこにいるの?",
+  "placeholderNote": "メモを入力する",
+  "rateMission": "このミッションを評価する",
+  "reallyPleased": "本当に満足です",
+  "requestText2": "何を求めているのですか?",
+  "requestDesc": "助けが必要なときは、タップするだけです。",
+  "requestTitle": "どのような助けが必要ですか?",
+  "request": "リクエスト",
+  "satisfactionAsk": "あなたは満足していますか?",
+  "satisfied": "かなり満足",
+  "scanQr": "アプリケーションの使用を開始するには、まず QR コードをスキャンしてください。",
+  "serialNumber": "シリアルナンバー",
+  "servantGroup": "リクエストグループ",
+  "servant": "サーバント",
+  "service": "サービス",
+  "specifyAnotherLocation": "別の場所を指定したい",
+  "specifyLocation": "場所を定義する",
+  "startDoing": "始める",
+  "stateCancel": "キャンセル",
+  "stateCanceled": "キャンセル",
+  "stateDone": "進行中",
+  "stateFinish": "仕上げる",
+  "stateQueue": "列",
+  "stateRequested": "リクエスト済み",
+  "state": "状態",
+  "sure": "本気ですか?",
+  "switch": "スイッチ",
+  "system": "システム",
+  "textCancel": "キャンセル",
+  "textHistory": "あなたが行ったリクエスト",
+  "textLogout": "ログアウトすると通知の受信やリクエストなどができなくなります。 もちろん?",
+  "textResubmit": "このリクエストをサーバントに再送信します。",
+  "ticketNumber": "チケット番号",
+  "timeline": "タイムライン",
+  "today": "今日",
+  "unrated": "このミッションはまだ評価されていません",
+  "userEmpty": "ユーザー名を空にすることはできません",
+  "userId": "ユーザー名",
+  "version": "バージョン ",
+  "verySatisfied": "満足",
+  "whatComplain": "何の苦情ですか?",
+  "whatHappen": "どうしたの?",
+  "whatNext": "落ち着いてください。 次は何?",
+  "whatProblem": "何が困っているのですか?",
+  "writeMessage": "メッセージを書く",
+  "yesterday": "昨日",
+  "language": "言語",
+  "bahasa": "Indonesia",
+  "english": "English",
+  "japanese": "日本語",
+  "korean": "한국어",
+  "chinese": "中文",
+  "german": "Deutsch",
+  "french": "Français",
+  "hindi": "हिंदी",
+  "arabic": "العربية",
+  "dutch": "Nederlands",
+  "chooseLanguage": "言語を選択する",
+  "rate": "レート",
+  "rated": "このミッションは評価されています。",
+  "rateText": "あなたはこの使命に[満足]しています。",
+  "settingPassword": "パスワードを変更する",
+  "oldPassword": "以前のパスワード",
+  "newPassword": "新しいパスワード",
+  "confirmPassword": "新しいパスワードを確認",
+  "buttonSave": "新しいパスワードを保存する",
+  "settingPasswordText": "パスワードを管理する",
+  "autoResponseText": "あなたのリクエストはすぐにシステムによって応答されます。",
+  "reply": "返事",
+  "selectPicture": "画像を選択",
+  "fromGallery": "ギャラリーから",
+  "fromCamera": "カメラから",
+  "sendPicture": "写真を送る",
+  "seeAttachment": "添付ファイルを参照してください",
+  "confirmCancel": "本当にキャンセルしてもよろしいですか?",
+  "selectDate": "日付を選択してください",
+  "lengthMax": "最大長は 128 文字です。",
+  "locRequired": "場所は必須です。",
+  "idRequired": "身分証明書が必要です。",
+  "dateRequired": "日付は必須です。",
+  "sendLater": "後で送信",
+  "thank": "ありがとう",
+  "pleaseWait": "お待ちください",
+  "sendSuccess": "正常に送信されました",
+  "followUp": "使用人はすぐに応答します。",
+  "okGot": "はい、わかった",
+  "okWait": "わかりました、確かに",
+  "errorConnection": "接続エラー。 数分後にもう一度試してください。",
+  "noInternet": "インターネットアクセスなし。",
+  "invalidLogin": "ユーザー名またはパスワードが間違っています。",
+  "invalidPhone": "電話番号が無効です。",
+  "expAccount": "アカウントの有効期限が切れています。",
+  "errorServer": "サーバーエラー。 数分後にもう一度試してください。",
+  "accessDenied": "アクセスが拒否されました",
+  "licenseProblem": "ライセンスに問題があるため、アプリケーションを実行できませんでした。",
+  "invalidVersion": "バージョンが一致しません",
+  "sugestVersion": "アプリケーションのバージョンを使用する",
+  "currentVersion": "現在のバージョンは",
+  "contactAdmin": "詳細については、管理者にお問い合わせください。",
+  "pressAgain": "終了するにはもう一度押します。",
+  "notFound": "データが見つかりません。",
+  "notFound2": "あなたが調べようとしているものはここにはありません!",
+  "noInternetTitle": "インターネット接続がありません。",
+  "noInternetDesc": "インターネット接続を確認してください。 今はGoogleに問い合わせることもできません。",
+  "errorConnectTitle": "サーバーに接続できませんでした。",
+  "errorConnectDesc": "管理者に連絡してください。サーバーに接続できるはずです。",
+  "errorServerTitle": "サーバーエラー。",
+  "errorServerDesc": "慌てる必要はありません。私たちはすべてを軌道に乗せようと努めています。",
+  "invalidAccountTitle": "無効なアカウント。",
+  "invalidAccountDesc": "ごめん! あなたのアカウントを確認できませんでした。 詳細については、管理者にお問い合わせください。",
+  "expAccountTitle": "アカウントの有効期限が切れました。",
+  "expAccountDesc": "アカウントの有効期限が切れています。 または、間違いだと思われる場合は、管理者に連絡してください。",
+  "inProcess": "処理",
+  "policy": "プライバシーポリシー",
+  "info": "追加情報",
+  "refresh": "リフレッシュ",
+  "messageCamPermission": "アクセスが拒否されました。 アプリの許可設定を通じて TelMessenger がカメラにアクセスできるようにしてください。",
+  "messageInvalidCode": "無効なコード。 システム管理者に連絡してください。",
+  "messagePassChanged": "パスワードが正常に変更されました。",
+  "wrongOldPass": "古いパスワードが間違っています。",
+  "checkNewPass": "新しいパスワードを確認してください。",
+  "cannotEmpty": "データを空にできませんでした。",
+  "deletedMessage": "このメッセージは削除されました。",
+  "resend": "再送信",
+  "delete": "消去",
+  "alreadyUsePass": "新しいパスワードは使用できませんでした。別のパスワードを定義してください。",
+  "notFoundImg": "画像が見つかりません",
+  "notFoundWorktime": "勤務時間が見つかりませんでした。 管理者に連絡してください。",
+  "seeAll": "すべてを見る",
+  "quickAction": "クイックアクション",
+  "quickDesc": "より効率的に移動するのに役立ちます。",
+  "times": " 回",
+  "search": "検索",
+  "searchAsk": "検索...",
+  "helpHint": "助けを探してみてください。..",
+  "inProgress": " リクエストはまだ進行中です。",
+  "currentActiveText": "現在アクティブなリクエスト",
+  "photo": "写真",
+  "selectRecipient": "受信者の選択",
+  "composeMessage": "メッセージを作成します",
+  "to": "に",
+  "addAttachment": "添付ファイルを追加する",
+  "editAttachment": "添付ファイルの変更",
+  "unsupportedFile": "サポートされていないファイル形式です",
+  "pdfFile": "PDF ファイルの種類",
+  "other": "他の",
+  "noMessageText": "プレビューするメッセージはありません。",
+  "noDataText": "利用可能なプレビュー データはありません。",
+  "noPIDText": "アクセスコードが見つかりません。",
+  "noPIDText2": "TelMessenger ライセンス所有者が提供するスキャン QR またはリンクからアクセス コードを取得します。",
+  "loading": "読み込み中...",
+  "backToLogin": "ログインに戻る",
+  "deleteHistory": "履歴データの削除",
+  "deleteHistoryConfirm": "データを削除してもよろしいですか?",
+  "couldnotDelete": "このデータは削除できませんでした。",
+  "allInformants": "情報提供者の皆様",
+  "welcome": "いらっしゃいませ",
+  "createNewPassText": "アプリケーションの使用を開始する前に、新しいパスワードを作成してください。",
+  "description": "説明",
+  "sorry": "ごめん!",
+  "outOfWorkTime": "あなたのリクエストは現在、サーバントの勤務時間外です。",
+  "willResponse": "彼らはすぐに応答します: ",
+  "canNotCancel1": "この報告は、サーヴァントが行った後はキャンセルできません。",
+  "canNotCancel2": "このレポートはキャンセルできません。",
+  "priorityHigh": "高い",
+  "priorityLow": "低い",
+  "priorityNormal": "普通",
+  "priority": "優先度",
+  "reported": "報告",
+  "escalationNoteBySystem": "エスカレーション",
+  "finishAttachment": "添付ファイルが完成しました",
+  "pleaseScan": "QRコードをスキャンしてください",
+  "mustScan": "再送信するには QR コードをスキャンする必要があります。",
+  "changeCodeMsg": "<company_name> に接続されます。 続けますか?",
+  "currentServer": "現在のサーバー",
+  "destinationServer": "宛先サーバー",
+  "textContinue": "続く",
+  "transferNoteBySystem": "移行",
+  "activity": "活動",
+  "image": "画像",
+  "titlePassOld": "古いパスワードを入力してください",
+  "titlePassNew": "古いパスワードは新しいパスワードに置き換えられます。",
+  "setting": "設定",
+  "more": "もっと",
+  "topMenu": "トップメニュー",
+  "availableMenu": "利用可能なメニュー",
+  "customize": "カスタマイズ",
+  "done": "終わり",
+  "ongoing": "進行中",
+  "maxMenu": "最大7メニュー。",
+  "searchIn": "で検索",
+  "yourLocation": "あなたの場所",
+  "addImage": "写真を追加したいですか?",
+  "addImageMsg": "手がかりなどとして写真を送っていただけます。",
+  "removeImageMsg": "いいえ、必要ありません。削除したいと思います。",
+  "sendingOpt": "配送オプション",
+  "sendingOptMsg": "スケジュールされたリクエストとして送信しますか? それともすぐに送信しますか?",
+  "scheduled": "予定されている",
+  "sendNow": "今すぐ送信",
+  "scheduledMsg": "* スケジュール済み = メモで選択した時間にリクエストが送信されます。",
+  "reqSuccessMsg": "お待ちください。 リクエストは処理中です。",
+  "noImgAttach": "画像は添付されていません。",
+  "btnWait": "わかりました、待ってます",
+  "rateReq": "リクエストを評価してください",
+  "reqAgain": "再リクエスト",
+  "notAvailable": "このメニューはご利用いただけません。",
+  "emptyMenuAlert": "表示するメニューが選択されていません。",
+  "redirecting": "リダイレクト中...",
+  "initializing": "初期化中...",
+  "selectAlert": "少なくとも 1 つのメニューを選択してください。",
+  "scopeDesc": "これを使用してスコープを切り替えます。",
+  "notFoundKeyword": "キーワードに一致するものが見つかりませんでした ",
+  "findQRcode": "近くの QR コードを探す",
+  "isWorking": " あなたのリクエストに取り組んでいます。",
+  "noteLongAlert": "128 文字未満のメモを追加してください。",
+  "reqCodeNotFound": "リクエストコードが無効です。 管理者に連絡してください",
+  "noImage": "画像が見つかりません",
+  "related": "関連サービス",
+  "broadcastPermission": "権限がないため、ブロードキャスト メッセージを送信できません。",
+  "broadcastTenant": "ブロードキャスト メッセージを送信できません。受信者のテナントが無効です。",
+  "reqForOthers": "はい、私は他の人を助けるのが好きです。",
+  "reqForMySelf": "いいえ、私は自分自身のために要求しています。",
+  "requestedBy": "に要求された",
+  "requestedFor": "要求された",
+  "typeId": "彼女/彼のIDを入力してください",
+  "idNotMatch": "送信リクエストが失敗しました。 このリクエストは #ID がリクエストすることを許可されていません。",
+  "idNotFound": "指定された ID が見つかりませんでした。 別のIDをお試しください。",
+  "informantNotRegistered": "あなたは受付係または客室係として登録されていません。",
+  "link_copied": "リンクがクリップボードにコピーされました。",
+  "do_not_disturb": "邪魔しないでください",
+  "set_dnd_status": "サイレント ステータスの設定",
+  "active_dnd": "アクティブ",
+  "inactive_dnd": "非活動中",
+  "msg_dnd": "アカウント メニューから DND ステータスを無効化できます。",
+  "msg_change_active": "DND ステータスを有効にしますか?",
+  "msg_change_inactive": "DND ステータスを無効にしますか?",
+  "info_dnd": "DND ステータスがアクティブ化されました。",
+  "invalid_bridge": "無効なブリッジ URL。",
+  "someone_else": "他の人のリクエストを送信したいですか?",
+  "askScheduleTime": "リクエストはいつ完了する必要がありますか?",
+  "scheduleMessage": "リクエストは次の日に行われるはずです",
+  "scan_qr": "私のQRを表示",
+  "show_qr": "QRを表示",
+  "show_qr_desc": "アプリにアクセスする必要がある友人や同僚にこの QR を見せてください。",
+  "dismiss": "却下する",
+  "not_allow_permission": "お使いのデバイスでは、アプリによる通知の送信が許可されていません。",
+  "tap_here": "ここをタップして通知許可を許可します。",
+  "doNotDisturb": "邪魔しないモード",
+  "info_label": "情報",
+  "display_menu": "メニュー表示",
+  "req_group": "リクエストグループ",
+  "ser_group": "サーヴァントグループ",
+  "save_rating": "評価の保存",
+  "auto_translate": "自動翻訳",
+  "hold": "一時停止中",
+  "holdHistory": "停止履歴",
+  "pending": "保留中",
+  "pending_info_success": "接続の問題が見つかりました。リクエストは保留中です。オンラインに戻ったら再度送信します。",
+  "pending_info_tiles": "インターネット接続がリクエストを送信するまで待ちます。",
+  "pending_info_detail": "接続の問題のため、リクエストはまだ送信されていません。",
+  "cancel_pending": "代わりにリクエストをキャンセルしてください",
+  "sending": "送信",
+  "queued": "キューに入れられました",
+  "onProgress": "進行中",
+  "showLess": "あまり見せない",
+  "customTopMenu": "トップメニューのカスタマイズ",
+  "limitTopMenu": "上位メニューは限定7品!",
+  "searchButton": "探す",
+  "allInformantsInfo": "すべての情報提供者があなたのメッセージを受け取ります。",
+  "action": "アクション",
+  "whatMakesYou": "何があなたを作っているのか",
+  "letMeWrite": "書かせてください!",
+  "writeHere": "ここに書いてください。",
+  "ratingAspect": "評価面",
+  "sendingRequest": "リクエストの送信",
+  "changePriority": "優先順位を変更する",
+  "referenceNumber": "参照番号",
+  "enterTicketNumber": "チケット番号を入力してください",
+  "subject": "主題",
+  "requestReference": "リクエストリファレンス",
+  "invalidParentTicket": "親チケットが無効です。",
+  "failedLoad": "アプリケーションのロードに失敗しました。",
+  "tap2retry": "タップして再試行します。",
+  "chat": "会話",
+  "asset": "資産",
+  "selectAsset": "資産を選択",
+  "addAsset": "資産を追加",
+  "assetList": "資産リスト",
+  "noDataSelected": "データが選択されていません。",
+  "noAssetAdded": "資産が追加されていません。",
+  "addLabel": "追加"
 }

+ 340 - 333
assets/lang/ko.json

@@ -1,335 +1,342 @@
 {
-   "account": "계정",
-   "addNote": "메모를 추가",
-   "addNoteCancel": "취소 메모 추가",
-   "all": "모두",
-   "anyNote": "하인을 위한 메모",
-   "appointment": "약속",
-   "attach": "이미지 첨부",
-   "buttonCancel": "요청 취소",
-   "buttonLogin": "로그인",
-   "buttonNo": "아니요",
-   "buttonResubmit": "재전송",
-   "buttonScan": "QR 스캔",
-   "buttonSendEmergency": "긴급 상황 보내기",
-   "buttonSendComplaint": "불만사항 보내기",
-   "buttonSendRequest": "요청 보내기",
-   "buttonYes": "예",
-   "buttonSure": "물론",
-   "buttonBack": "뒤쪽에",
-   "canceledBy": "취소자:",
-   "category": "범주",
-   "scope": "범위",
-   "changeScope": "범위 변경",
-   "chatClosed": "이 대화는 종료되었습니다.",
-   "chooseService": "원하는 서비스를 선택하세요",
-   "complaintText": "무슨 일이야? 전문가가 당신을 위해 일해 드리겠습니다.",
-   "complaint": "불평",
-   "defaultLocation": "기본 위치",
-   "detail": "세부 사항",
-   "disatisfied": "불만족",
-   "emergencyText": "긴급하고 긴급한 모든 일은 서둘러야 합니다.",
-   "emergency": "비상",
-   "forum": "법정",
-   "frequentlyText": "여기에서 자주 요청하신 내용입니다.",
-   "frequently": "자주 요청되는",
-   "frequentlyTitle": "자주 요청되는",
-   "frequentlyTitleText": "자주 요청했던 목록",
-   "history": "역사",
-   "lessSatisfied": "너무 만족스럽지 않음",
-   "location": "위치",
-   "logout": "로그 아웃",
-   "menuAccount": "계정",
-   "menuHistory": "역사",
-   "menuService": "서비스",
-   "menuHome": "집",
-   "message": "메시지",
-   "note": "메모",
-   "passwordEmpty": "비밀번호는 비워둘 수 없습니다.",
-   "password": "비밀번호",
-   "phoneNumber": "전화 번호",
-   "placeholderLocation": "어디세요?",
-   "placeholderNote": "메모 입력",
-   "rateMission": "이 임무를 평가해 주세요",
-   "reallyPleased": "정말 만족해요",
-   "requestText2": "무엇을 요구하시나요?",
-   "requestDesc": "도움이 필요하면 탭하세요.",
-   "requestTitle": "어떤 종류의 도움이 필요합니까?",
-   "request": "요구",
-   "satisfactionAsk": "만족하시나요?",
-   "satisfied": "꽤 만족함",
-   "scanQr": "애플리케이션 사용을 시작하려면 먼저 QR 코드를 스캔하세요.",
-   "serialNumber": "일련번호",
-   "servantGroup": "요청 그룹",
-   "servant": "하인",
-   "service": "서비스",
-   "specifyAnotherLocation": "다른 위치를 지정하고 싶어요",
-   "specifyLocation": "위치 결정",
-   "startDoing": "시작",
-   "stateCancel": "취소",
-   "stateCanceled": "취소 된",
-   "stateDone": "진행 중",
-   "stateFinish": "마치다",
-   "stateQueue": "대기줄",
-   "stateRequested": "요청됨",
-   "state": "상태",
-   "sure": "확실합니까?",
-   "switch": "스위치",
-   "system": "체계",
-   "textCancel": "취소",
-   "textHistory": "요청하신 내용",
-   "textLogout": "로그아웃하면 알림을 받을 수 없고 요청 등을 할 수 없게 됩니다. 그렇죠?",
-   "textResubmit": "이 요청을 하인에게 다시 보냅니다.",
-   "ticketNumber": "티켓 번호",
-   "timeline": "타임라인",
-   "today": "오늘",
-   "unrated": "이 임무에 대한 평가는 아직 없습니다",
-   "userEmpty": "사용자 이름은 비워둘 수 없습니다.",
-   "userId": "사용자 이름",
-   "version": "버전 ",
-   "verySatisfied": "만족하는",
-   "whatComplain": "무슨 불만이요?",
-   "whatHappen": "무슨 일이야?",
-   "whatNext": "침착하세요. 다음은 무엇입니까?",
-   "whatProblem": "무슨 문제가 있나요?",
-   "writeMessage": "메시지 쓰기",
-   "yesterday": "어제",
-   "language": "언어",
-   "bahasa": "Indonesia",
-   "english": "English",
-   "japanese": "日本語",
-   "korean": "한국어",
-   "chinese": "中文",
-   "german": "Deutsch",
-   "french": "Français",
-   "hindi": "हिंदी",
-   "arabic": "العربية",
-   "dutch": "Nederlands",
-   "chooseLanguage": "언어 선택",
-   "rate": "비율",
-   "rated": "이 임무는 평가되었습니다.",
-   "rateText": "당신은 이번 임무에 [만족]합니다.",
-   "settingPassword": "비밀번호 변경",
-   "oldPassword": "기존 비밀번호",
-   "newPassword": "새 비밀번호",
-   "confirmPassword": "새 암호를 확인합니다",
-   "buttonSave": "새 비밀번호 저장",
-   "settingPasswordText": "비밀번호 관리",
-   "autoResponseText": "귀하의 요청은 시스템에서 곧 응답될 것입니다.",
-   "reply": "회신하다",
-   "selectPicture": "사진 선택",
-   "fromGallery": "갤러리에서",
-   "fromCamera": "카메라에서",
-   "sendPicture": "사진을 보내",
-   "seeAttachment": "첨부 파일을 참조",
-   "confirmCancel": "정말로 취소하시겠습니까?",
-   "selectDate": "날짜 선택",
-   "lengthMax": "최대 길이는 128자입니다.",
-   "locRequired": "위치는 필수 항목입니다.",
-   "idRequired": "신분증이 필요합니다.",
-   "dateRequired": "날짜가 필요합니다.",
-   "sendLater": "나중에 보내기",
-   "thank": "감사합니다",
-   "pleaseWait": "기다리세요",
-   "sendSuccess": "성공적으로 보냈습니다",
-   "followUp": "하인이 곧 응답할 것이다.",
-   "okGot": "알았어 이해해",
-   "okWait": "알았어, 물론이지",
-   "errorConnection": "연결 오류. 몇 분 후에 다시 시도해 주세요.",
-   "noInternet": "인터넷에 접속할 수 없습니다.",
-   "invalidLogin": "사용자 이름 또는 비밀번호가 잘못되었습니다.",
-   "invalidPhone": "전화번호가 유효하지 않습니다.",
-   "expAccount": "계정이 만료되었습니다.",
-   "errorServer": "서버 오류. 몇 분 후에 다시 시도해 주세요.",
-   "accessDenied": "접근 불가",
-   "licenseProblem": "라이센스 문제로 인해 애플리케이션을 실행할 수 없습니다.",
-   "invalidVersion": "버전이 일치하지 않습니다.",
-   "sugestVersion": "애플리케이션 버전 사용",
-   "currentVersion": "현재 버전은",
-   "contactAdmin": "자세한 내용은 관리자에게 문의하세요.",
-   "pressAgain": "종료하려면 다시 누르세요.",
-   "notFound": "데이터를 찾을 수 없습니다.",
-   "notFound2": "당신이 찾으려고 하는 것은 여기에 없습니다!",
-   "noInternetTitle": "인터넷에 연결되지 않음.",
-   "noInternetDesc": "인터넷 연결을 확인하세요. 지금은 Google에 물어볼 수도 없습니다.",
-   "errorConnectTitle": "서버에 연결할 수 없습니다.",
-   "errorConnectDesc": "관리자에게 문의하세요. 서버에 연결할 수 있을 것입니다.",
-   "errorServerTitle": "서버 오류.",
-   "errorServerDesc": "당황하지 마십시오. 우리는 모든 것을 정상 궤도에 올려놓으려고 노력하고 있습니다.",
-   "invalidAccountTitle": "잘못된 계정입니다.",
-   "invalidAccountDesc": "죄송합니다! 귀하의 계정을 확인할 수 없습니다. 자세한 내용은 관리자에게 문의하세요.",
-   "expAccountTitle": "만료된 계정.",
-   "expAccountDesc": "귀하의 계정이 만료되었습니다. 또는 실수라고 생각되면 관리자에게 문의할 수 있습니다.",
-   "inProcess": "처리",
-   "policy": "개인 정보 정책",
-   "info": "추가 정보",
-   "refresh": "새로 고치다",
-   "messageCamPermission": "접근 불가. TelMessenger가 앱 권한 설정을 통해 카메라에 접근할 수 있도록 허용해주세요.",
-   "messageInvalidCode": "유효하지 않은 코드. 시스템 관리자에게 문의하세요.",
-   "messagePassChanged": "비밀번호를 성공적으로 변경했습니다.",
-   "wrongOldPass": "이전 비밀번호가 잘못되었습니다.",
-   "checkNewPass": "새로운 비밀번호를 확인해주세요.",
-   "cannotEmpty": "데이터는 비워둘 수 없습니다.",
-   "deletedMessage": "이 메시지는 삭제되었습니다.",
-   "resend": "재전송",
-   "delete": "삭제",
-   "alreadyUsePass": "새 비밀번호를 사용할 수 없습니다. 다른 비밀번호를 정의하세요.",
-   "notFoundImg": "이미지를 찾을 수 없습니다",
-   "notFoundWorktime": "근무 시간을 찾을 수 없습니다. 관리자에게 문의하세요.",
-   "seeAll": "모두 보기",
-   "quickAction": "빠른 행동",
-   "quickDesc": "보다 효율적으로 이동할 수 있도록 도와드립니다.",
-   "times": " 타임스",
-   "search": "찾다",
-   "searchAsk": "찾다...",
-   "helpHint": "도움을 찾아보세요..",
-   "inProgress": " 요청이 아직 진행 중입니다.",
-   "currentActiveText": "현재 활성 요청",
-   "photo": "사진",
-   "selectRecipient": "수신자 선택",
-   "composeMessage": "메시지 작성",
-   "to": "에게",
-   "addAttachment": "첨부파일 추가",
-   "editAttachment": "첨부파일 변경",
-   "unsupportedFile": "지원되지 않는 파일 형식",
-   "pdfFile": "PDF 파일 형식",
-   "other": "다른",
-   "noMessageText": "미리 볼 메시지가 없습니다.",
-   "noDataText": "미리보기 데이터가 없습니다.",
-   "noPIDText": "액세스 코드를 찾을 수 없습니다.",
-   "noPIDText2": "TelMessenger 라이선스 보유자가 제공한 링크나 QR 스캔에서 액세스 코드를 받으세요.",
-   "loading": "로드 중...",
-   "backToLogin": "로그인으로 돌아가기",
-   "deleteHistory": "기록 데이터 삭제",
-   "deleteHistoryConfirm": "데이터를 삭제하시겠습니까?",
-   "couldnotDelete": "이 데이터는 삭제할 수 없습니다.",
-   "allInformants": "제보자 전체",
-   "welcome": "환영",
-   "createNewPassText": "응용 프로그램을 사용하기 전에 새 비밀번호를 만드십시오.",
-   "description": "설명",
-   "sorry": "죄송합니다!",
-   "outOfWorkTime": "귀하의 요청은 현재 하인 근무 시간이 아닙니다.",
-   "willResponse": "그들은 곧 다음 사항에 응답할 것입니다: ",
-   "canNotCancel1": "이 보고서는 서번트가 작성한 후에는 취소할 수 없습니다.",
-   "canNotCancel2": "이 보고서는 취소할 수 없습니다.",
-   "priorityHigh": "높은",
-   "priorityLow": "낮은",
-   "priorityNormal": "정상",
-   "priority": "우선 사항",
-   "reported": "신고됨",
-   "escalationNoteBySystem": "단계적 확대",
-   "finishAttachment": "첨부 완료",
-   "pleaseScan": "QR코드를 스캔해주세요",
-   "mustScan": "다시 보내려면 QR 코드를 스캔해야 합니다.",
-   "changeCodeMsg": "<company_name>으로 연결됩니다. 계속하시겠습니까?",
-   "currentServer": "현재 서버",
-   "destinationServer": "대상 서버",
-   "textContinue": "계속하다",
-   "transferNoteBySystem": "옮기다",
-   "activity": "활동",
-   "image": "이미지",
-   "titlePassOld": "이전 비밀번호를 입력하세요.",
-   "titlePassNew": "기존 비밀번호는 새 비밀번호로 교체됩니다.",
-   "setting": "설정",
-   "more": "더",
-   "topMenu": "상위 메뉴",
-   "availableMenu": "이용 가능한 메뉴",
-   "customize": "사용자 정의",
-   "done": "완료",
-   "ongoing": "전진",
-   "maxMenu": "최대 7개 메뉴.",
-   "searchIn": "검색",
-   "yourLocation": "귀하의 위치",
-   "addImage": "사진을 추가하고 싶으신가요?",
-   "addImageMsg": "단서 등으로 사진을 보내주실 수 있습니다.",
-   "removeImageMsg": "아니요, 필요하지 않습니다. 제거하고 싶습니다.",
-   "sendingOpt": "배송 옵션",
-   "sendingOptMsg": "예약된 요청으로 보내시겠습니까, 아니면 즉시 보내시겠습니까?",
-   "scheduled": "예정됨",
-   "sendNow": "지금 보내",
-   "scheduledMsg": "* 예약됨 = 메모에서 선택한 시간에 요청이 전송됩니다.",
-   "reqSuccessMsg": "기다리세요. 귀하의 요청을 처리 중입니다.",
-   "noImgAttach": "첨부된 이미지가 없습니다.",
-   "btnWait": "알았어, 기다릴게",
-   "rateReq": "귀하의 요청을 평가해 주세요",
-   "reqAgain": "다시 요청",
-   "notAvailable": "이 메뉴를 사용할 수 없습니다.",
-   "emptyMenuAlert": "표시할 메뉴를 선택하지 않았습니다.",
-   "redirecting": "리디렉션 중...",
-   "initializing": "초기화 중...",
-   "selectAlert": "메뉴를 하나 이상 선택해 주세요.",
-   "scopeDesc": "이를 사용하여 범위 간을 전환합니다.",
-   "notFoundKeyword": "키워드와 일치하는 항목을 찾을 수 없습니다. ",
-   "findQRcode": "가까운 QR 코드 찾기",
-   "isWorking": " 귀하의 요청을 처리하는 중입니다.",
-   "noteLongAlert": "128자 미만의 메모를 추가하세요.",
-   "reqCodeNotFound": "요청 코드가 잘못되었습니다. 관리자에게 문의하세요",
-   "noImage": "이미지를 찾을 수 없습니다",
-   "related": "관련 서비스",
-   "broadcastPermission": "권한이 없으므로 브로드캐스트 메시지를 보낼 수 없습니다.",
-   "broadcastTenant": "브로드캐스트 메시지를 보낼 수 없습니다. 수신자 테넌트가 유효하지 않습니다.",
-   "reqForOthers": "예, 저는 다른 사람을 돕는 것을 좋아합니다.",
-   "reqForMySelf": "아니요, 제가 직접 요청합니다.",
-   "requestedBy": "에 의해 요청",
-   "requestedFor": "요청한",
-   "typeId": "아이디를 입력해주세요",
-   "idNotMatch": "배송 요청에 실패했습니다. 이 요청은 #ID 요청에는 허용되지 않습니다.",
-   "idNotFound": "단말 ID를 찾을 수 없습니다. 새로운 ID를 살펴보세요.",
-   "informantNotRegistered": "귀하는 접수원이나 룸어텐더로 등록되어 있지 않습니다.",
-   "link_copied": "링크가 클립보드에 복사되었습니다.",
-   "do_not_disturb": "방해하지 마",
-   "set_dnd_status": "방해사절 상태 설정",
-   "active_dnd": "활동적인",
-   "inactive_dnd": "활성화되지 않은",
-   "msg_dnd": "계정 메뉴를 통해 DND 상태를 비활성화할 수 있습니다.",
-   "msg_change_active": "DND 상태를 활성화하시겠습니까?",
-   "msg_change_inactive": "DND 상태를 비활성화하시겠습니까?",
-   "info_dnd": "DND 상태가 활성화되었습니다.",
-   "invalid_bridge": "잘못된 브리지 URL입니다.",
-   "someone_else": "다른 사람의 요청을 제출하고 싶으십니까?",
-   "askScheduleTime": "귀하의 요청은 언제 완료되어야 합니까?",
-   "scheduleMessage": "귀하의 요청은 다음 날짜에 완료될 예정입니다.",
-   "scan_qr": "내 QR 표시",
-   "show_qr": "QR 표시",
-   "show_qr_desc": "앱에 액세스해야 하는 친구나 동료에게 이 QR을 보여주세요.",
-   "dismiss": "해고하다",
-   "not_allow_permission": "귀하의 기기는 앱이 귀하에게 알림을 보내는 것을 허용하지 않습니다.",
-   "tap_here": "알림 권한을 허용하려면 여기를 탭하세요.",
-   "doNotDisturb": "방해하지 마세요 모드",
-   "info_label": "정보",
-   "display_menu": "메뉴 표시",
-   "req_group": "요청 그룹",
-   "ser_group": "서번트 그룹",
-   "save_rating": "평가 저장",
-   "auto_translate": "자동 번역",
-   "hold": "정지된",
-   "holdHistory": "정지 내역",
-   "pending": "보류 중",
-   "pending_info_success": "연결 문제를 발견했습니다. 귀하의 요청이 보류 중입니다. 다시 온라인 상태가 되면 다시 보내드리겠습니다.",
-   "pending_info_tiles": "요청을 보내기 위해 인터넷 연결을 기다립니다.",
-   "pending_info_detail": "연결 문제로 인해 귀하의 요청이 아직 전송되지 않았습니다.",
-   "cancel_pending": "대신 내 요청을 취소하세요",
-   "sending": "배상",
-   "queued": "대기 중",
-   "onProgress": "진행 중",
-   "showLess": "간략하게 표시",
-   "customTopMenu": "상단 메뉴 사용자 정의",
-   "limitTopMenu": "상위 메뉴는 7개로만 제한됩니다!",
-   "searchButton": "찾다",
-   "allInformantsInfo": "모든 제보자가 귀하의 메시지를 받게 됩니다.",
-   "action": "행동",
-   "whatMakesYou": "뭐가 널 그렇게 만드니",
-   "letMeWrite": "내가 쓰게 해주세요!",
-   "writeHere": "여기 쓰시 오..",
-   "ratingAspect": "평가 측면",
-   "sendingRequest": "요청 보내기",
-   "changePriority": "우선순위 변경",
-   "referenceNumber": "참조번호",
-   "enterTicketNumber": "티켓번호를 입력하세요",
-   "subject": "주제",
-   "requestReference": "참조 요청",
-   "invalidParentTicket": "부모 티켓이 유효하지 않습니다.",
-   "failedLoad": "애플리케이션을 로드하지 못했습니다.",
-   "tap2retry": "다시 시도하려면 탭하세요.",
-   "chat": "대화"
+  "account": "계정",
+  "addNote": "메모를 추가",
+  "addNoteCancel": "취소 메모 추가",
+  "all": "모두",
+  "anyNote": "하인을 위한 메모",
+  "appointment": "약속",
+  "attach": "이미지 첨부",
+  "buttonCancel": "요청 취소",
+  "buttonLogin": "로그인",
+  "buttonNo": "아니요",
+  "buttonResubmit": "재전송",
+  "buttonScan": "QR 스캔",
+  "buttonSendEmergency": "긴급 상황 보내기",
+  "buttonSendComplaint": "불만사항 보내기",
+  "buttonSendRequest": "요청 보내기",
+  "buttonYes": "예",
+  "buttonSure": "물론",
+  "buttonBack": "뒤쪽에",
+  "canceledBy": "취소자:",
+  "category": "범주",
+  "scope": "범위",
+  "changeScope": "범위 변경",
+  "chatClosed": "이 대화는 종료되었습니다.",
+  "chooseService": "원하는 서비스를 선택하세요",
+  "complaintText": "무슨 일이야? 전문가가 당신을 위해 일해 드리겠습니다.",
+  "complaint": "불평",
+  "defaultLocation": "기본 위치",
+  "detail": "세부 사항",
+  "disatisfied": "불만족",
+  "emergencyText": "긴급하고 긴급한 모든 일은 서둘러야 합니다.",
+  "emergency": "비상",
+  "forum": "법정",
+  "frequentlyText": "여기에서 자주 요청하신 내용입니다.",
+  "frequently": "자주 요청되는",
+  "frequentlyTitle": "자주 요청되는",
+  "frequentlyTitleText": "자주 요청했던 목록",
+  "history": "역사",
+  "lessSatisfied": "너무 만족스럽지 않음",
+  "location": "위치",
+  "logout": "로그 아웃",
+  "menuAccount": "계정",
+  "menuHistory": "역사",
+  "menuService": "서비스",
+  "menuHome": "집",
+  "message": "메시지",
+  "note": "메모",
+  "passwordEmpty": "비밀번호는 비워둘 수 없습니다.",
+  "password": "비밀번호",
+  "phoneNumber": "전화 번호",
+  "placeholderLocation": "어디세요?",
+  "placeholderNote": "메모 입력",
+  "rateMission": "이 임무를 평가해 주세요",
+  "reallyPleased": "정말 만족해요",
+  "requestText2": "무엇을 요구하시나요?",
+  "requestDesc": "도움이 필요하면 탭하세요.",
+  "requestTitle": "어떤 종류의 도움이 필요합니까?",
+  "request": "요구",
+  "satisfactionAsk": "만족하시나요?",
+  "satisfied": "꽤 만족함",
+  "scanQr": "애플리케이션 사용을 시작하려면 먼저 QR 코드를 스캔하세요.",
+  "serialNumber": "일련번호",
+  "servantGroup": "요청 그룹",
+  "servant": "하인",
+  "service": "서비스",
+  "specifyAnotherLocation": "다른 위치를 지정하고 싶어요",
+  "specifyLocation": "위치 결정",
+  "startDoing": "시작",
+  "stateCancel": "취소",
+  "stateCanceled": "취소 된",
+  "stateDone": "진행 중",
+  "stateFinish": "마치다",
+  "stateQueue": "대기줄",
+  "stateRequested": "요청됨",
+  "state": "상태",
+  "sure": "확실합니까?",
+  "switch": "스위치",
+  "system": "체계",
+  "textCancel": "취소",
+  "textHistory": "요청하신 내용",
+  "textLogout": "로그아웃하면 알림을 받을 수 없고 요청 등을 할 수 없게 됩니다. 그렇죠?",
+  "textResubmit": "이 요청을 하인에게 다시 보냅니다.",
+  "ticketNumber": "티켓 번호",
+  "timeline": "타임라인",
+  "today": "오늘",
+  "unrated": "이 임무에 대한 평가는 아직 없습니다",
+  "userEmpty": "사용자 이름은 비워둘 수 없습니다.",
+  "userId": "사용자 이름",
+  "version": "버전 ",
+  "verySatisfied": "만족하는",
+  "whatComplain": "무슨 불만이요?",
+  "whatHappen": "무슨 일이야?",
+  "whatNext": "침착하세요. 다음은 무엇입니까?",
+  "whatProblem": "무슨 문제가 있나요?",
+  "writeMessage": "메시지 쓰기",
+  "yesterday": "어제",
+  "language": "언어",
+  "bahasa": "Indonesia",
+  "english": "English",
+  "japanese": "日本語",
+  "korean": "한국어",
+  "chinese": "中文",
+  "german": "Deutsch",
+  "french": "Français",
+  "hindi": "हिंदी",
+  "arabic": "العربية",
+  "dutch": "Nederlands",
+  "chooseLanguage": "언어 선택",
+  "rate": "비율",
+  "rated": "이 임무는 평가되었습니다.",
+  "rateText": "당신은 이번 임무에 [만족]합니다.",
+  "settingPassword": "비밀번호 변경",
+  "oldPassword": "기존 비밀번호",
+  "newPassword": "새 비밀번호",
+  "confirmPassword": "새 암호를 확인합니다",
+  "buttonSave": "새 비밀번호 저장",
+  "settingPasswordText": "비밀번호 관리",
+  "autoResponseText": "귀하의 요청은 시스템에서 곧 응답될 것입니다.",
+  "reply": "회신하다",
+  "selectPicture": "사진 선택",
+  "fromGallery": "갤러리에서",
+  "fromCamera": "카메라에서",
+  "sendPicture": "사진을 보내",
+  "seeAttachment": "첨부 파일을 참조",
+  "confirmCancel": "정말로 취소하시겠습니까?",
+  "selectDate": "날짜 선택",
+  "lengthMax": "최대 길이는 128자입니다.",
+  "locRequired": "위치는 필수 항목입니다.",
+  "idRequired": "신분증이 필요합니다.",
+  "dateRequired": "날짜가 필요합니다.",
+  "sendLater": "나중에 보내기",
+  "thank": "감사합니다",
+  "pleaseWait": "기다리세요",
+  "sendSuccess": "성공적으로 보냈습니다",
+  "followUp": "하인이 곧 응답할 것이다.",
+  "okGot": "알았어 이해해",
+  "okWait": "알았어, 물론이지",
+  "errorConnection": "연결 오류. 몇 분 후에 다시 시도해 주세요.",
+  "noInternet": "인터넷에 접속할 수 없습니다.",
+  "invalidLogin": "사용자 이름 또는 비밀번호가 잘못되었습니다.",
+  "invalidPhone": "전화번호가 유효하지 않습니다.",
+  "expAccount": "계정이 만료되었습니다.",
+  "errorServer": "서버 오류. 몇 분 후에 다시 시도해 주세요.",
+  "accessDenied": "접근 불가",
+  "licenseProblem": "라이센스 문제로 인해 애플리케이션을 실행할 수 없습니다.",
+  "invalidVersion": "버전이 일치하지 않습니다.",
+  "sugestVersion": "애플리케이션 버전 사용",
+  "currentVersion": "현재 버전은",
+  "contactAdmin": "자세한 내용은 관리자에게 문의하세요.",
+  "pressAgain": "종료하려면 다시 누르세요.",
+  "notFound": "데이터를 찾을 수 없습니다.",
+  "notFound2": "당신이 찾으려고 하는 것은 여기에 없습니다!",
+  "noInternetTitle": "인터넷에 연결되지 않음.",
+  "noInternetDesc": "인터넷 연결을 확인하세요. 지금은 Google에 물어볼 수도 없습니다.",
+  "errorConnectTitle": "서버에 연결할 수 없습니다.",
+  "errorConnectDesc": "관리자에게 문의하세요. 서버에 연결할 수 있을 것입니다.",
+  "errorServerTitle": "서버 오류.",
+  "errorServerDesc": "당황하지 마십시오. 우리는 모든 것을 정상 궤도에 올려놓으려고 노력하고 있습니다.",
+  "invalidAccountTitle": "잘못된 계정입니다.",
+  "invalidAccountDesc": "죄송합니다! 귀하의 계정을 확인할 수 없습니다. 자세한 내용은 관리자에게 문의하세요.",
+  "expAccountTitle": "만료된 계정.",
+  "expAccountDesc": "귀하의 계정이 만료되었습니다. 또는 실수라고 생각되면 관리자에게 문의할 수 있습니다.",
+  "inProcess": "처리",
+  "policy": "개인 정보 정책",
+  "info": "추가 정보",
+  "refresh": "새로 고치다",
+  "messageCamPermission": "접근 불가. TelMessenger가 앱 권한 설정을 통해 카메라에 접근할 수 있도록 허용해주세요.",
+  "messageInvalidCode": "유효하지 않은 코드. 시스템 관리자에게 문의하세요.",
+  "messagePassChanged": "비밀번호를 성공적으로 변경했습니다.",
+  "wrongOldPass": "이전 비밀번호가 잘못되었습니다.",
+  "checkNewPass": "새로운 비밀번호를 확인해주세요.",
+  "cannotEmpty": "데이터는 비워둘 수 없습니다.",
+  "deletedMessage": "이 메시지는 삭제되었습니다.",
+  "resend": "재전송",
+  "delete": "삭제",
+  "alreadyUsePass": "새 비밀번호를 사용할 수 없습니다. 다른 비밀번호를 정의하세요.",
+  "notFoundImg": "이미지를 찾을 수 없습니다",
+  "notFoundWorktime": "근무 시간을 찾을 수 없습니다. 관리자에게 문의하세요.",
+  "seeAll": "모두 보기",
+  "quickAction": "빠른 행동",
+  "quickDesc": "보다 효율적으로 이동할 수 있도록 도와드립니다.",
+  "times": " 타임스",
+  "search": "찾다",
+  "searchAsk": "찾다...",
+  "helpHint": "도움을 찾아보세요..",
+  "inProgress": " 요청이 아직 진행 중입니다.",
+  "currentActiveText": "현재 활성 요청",
+  "photo": "사진",
+  "selectRecipient": "수신자 선택",
+  "composeMessage": "메시지 작성",
+  "to": "에게",
+  "addAttachment": "첨부파일 추가",
+  "editAttachment": "첨부파일 변경",
+  "unsupportedFile": "지원되지 않는 파일 형식",
+  "pdfFile": "PDF 파일 형식",
+  "other": "다른",
+  "noMessageText": "미리 볼 메시지가 없습니다.",
+  "noDataText": "미리보기 데이터가 없습니다.",
+  "noPIDText": "액세스 코드를 찾을 수 없습니다.",
+  "noPIDText2": "TelMessenger 라이선스 보유자가 제공한 링크나 QR 스캔에서 액세스 코드를 받으세요.",
+  "loading": "로드 중...",
+  "backToLogin": "로그인으로 돌아가기",
+  "deleteHistory": "기록 데이터 삭제",
+  "deleteHistoryConfirm": "데이터를 삭제하시겠습니까?",
+  "couldnotDelete": "이 데이터는 삭제할 수 없습니다.",
+  "allInformants": "제보자 전체",
+  "welcome": "환영",
+  "createNewPassText": "응용 프로그램을 사용하기 전에 새 비밀번호를 만드십시오.",
+  "description": "설명",
+  "sorry": "죄송합니다!",
+  "outOfWorkTime": "귀하의 요청은 현재 하인 근무 시간이 아닙니다.",
+  "willResponse": "그들은 곧 다음 사항에 응답할 것입니다: ",
+  "canNotCancel1": "이 보고서는 서번트가 작성한 후에는 취소할 수 없습니다.",
+  "canNotCancel2": "이 보고서는 취소할 수 없습니다.",
+  "priorityHigh": "높은",
+  "priorityLow": "낮은",
+  "priorityNormal": "정상",
+  "priority": "우선 사항",
+  "reported": "신고됨",
+  "escalationNoteBySystem": "단계적 확대",
+  "finishAttachment": "첨부 완료",
+  "pleaseScan": "QR코드를 스캔해주세요",
+  "mustScan": "다시 보내려면 QR 코드를 스캔해야 합니다.",
+  "changeCodeMsg": "<company_name>으로 연결됩니다. 계속하시겠습니까?",
+  "currentServer": "현재 서버",
+  "destinationServer": "대상 서버",
+  "textContinue": "계속하다",
+  "transferNoteBySystem": "옮기다",
+  "activity": "활동",
+  "image": "이미지",
+  "titlePassOld": "이전 비밀번호를 입력하세요.",
+  "titlePassNew": "기존 비밀번호는 새 비밀번호로 교체됩니다.",
+  "setting": "설정",
+  "more": "더",
+  "topMenu": "상위 메뉴",
+  "availableMenu": "이용 가능한 메뉴",
+  "customize": "사용자 정의",
+  "done": "완료",
+  "ongoing": "전진",
+  "maxMenu": "최대 7개 메뉴.",
+  "searchIn": "검색",
+  "yourLocation": "귀하의 위치",
+  "addImage": "사진을 추가하고 싶으신가요?",
+  "addImageMsg": "단서 등으로 사진을 보내주실 수 있습니다.",
+  "removeImageMsg": "아니요, 필요하지 않습니다. 제거하고 싶습니다.",
+  "sendingOpt": "배송 옵션",
+  "sendingOptMsg": "예약된 요청으로 보내시겠습니까, 아니면 즉시 보내시겠습니까?",
+  "scheduled": "예정됨",
+  "sendNow": "지금 보내",
+  "scheduledMsg": "* 예약됨 = 메모에서 선택한 시간에 요청이 전송됩니다.",
+  "reqSuccessMsg": "기다리세요. 귀하의 요청을 처리 중입니다.",
+  "noImgAttach": "첨부된 이미지가 없습니다.",
+  "btnWait": "알았어, 기다릴게",
+  "rateReq": "귀하의 요청을 평가해 주세요",
+  "reqAgain": "다시 요청",
+  "notAvailable": "이 메뉴를 사용할 수 없습니다.",
+  "emptyMenuAlert": "표시할 메뉴를 선택하지 않았습니다.",
+  "redirecting": "리디렉션 중...",
+  "initializing": "초기화 중...",
+  "selectAlert": "메뉴를 하나 이상 선택해 주세요.",
+  "scopeDesc": "이를 사용하여 범위 간을 전환합니다.",
+  "notFoundKeyword": "키워드와 일치하는 항목을 찾을 수 없습니다. ",
+  "findQRcode": "가까운 QR 코드 찾기",
+  "isWorking": " 귀하의 요청을 처리하는 중입니다.",
+  "noteLongAlert": "128자 미만의 메모를 추가하세요.",
+  "reqCodeNotFound": "요청 코드가 잘못되었습니다. 관리자에게 문의하세요",
+  "noImage": "이미지를 찾을 수 없습니다",
+  "related": "관련 서비스",
+  "broadcastPermission": "권한이 없으므로 브로드캐스트 메시지를 보낼 수 없습니다.",
+  "broadcastTenant": "브로드캐스트 메시지를 보낼 수 없습니다. 수신자 테넌트가 유효하지 않습니다.",
+  "reqForOthers": "예, 저는 다른 사람을 돕는 것을 좋아합니다.",
+  "reqForMySelf": "아니요, 제가 직접 요청합니다.",
+  "requestedBy": "에 의해 요청",
+  "requestedFor": "요청한",
+  "typeId": "아이디를 입력해주세요",
+  "idNotMatch": "배송 요청에 실패했습니다. 이 요청은 #ID 요청에는 허용되지 않습니다.",
+  "idNotFound": "단말 ID를 찾을 수 없습니다. 새로운 ID를 살펴보세요.",
+  "informantNotRegistered": "귀하는 접수원이나 룸어텐더로 등록되어 있지 않습니다.",
+  "link_copied": "링크가 클립보드에 복사되었습니다.",
+  "do_not_disturb": "방해하지 마",
+  "set_dnd_status": "방해사절 상태 설정",
+  "active_dnd": "활동적인",
+  "inactive_dnd": "활성화되지 않은",
+  "msg_dnd": "계정 메뉴를 통해 DND 상태를 비활성화할 수 있습니다.",
+  "msg_change_active": "DND 상태를 활성화하시겠습니까?",
+  "msg_change_inactive": "DND 상태를 비활성화하시겠습니까?",
+  "info_dnd": "DND 상태가 활성화되었습니다.",
+  "invalid_bridge": "잘못된 브리지 URL입니다.",
+  "someone_else": "다른 사람의 요청을 제출하고 싶으십니까?",
+  "askScheduleTime": "귀하의 요청은 언제 완료되어야 합니까?",
+  "scheduleMessage": "귀하의 요청은 다음 날짜에 완료될 예정입니다.",
+  "scan_qr": "내 QR 표시",
+  "show_qr": "QR 표시",
+  "show_qr_desc": "앱에 액세스해야 하는 친구나 동료에게 이 QR을 보여주세요.",
+  "dismiss": "해고하다",
+  "not_allow_permission": "귀하의 기기는 앱이 귀하에게 알림을 보내는 것을 허용하지 않습니다.",
+  "tap_here": "알림 권한을 허용하려면 여기를 탭하세요.",
+  "doNotDisturb": "방해하지 마세요 모드",
+  "info_label": "정보",
+  "display_menu": "메뉴 표시",
+  "req_group": "요청 그룹",
+  "ser_group": "서번트 그룹",
+  "save_rating": "평가 저장",
+  "auto_translate": "자동 번역",
+  "hold": "정지된",
+  "holdHistory": "정지 내역",
+  "pending": "보류 중",
+  "pending_info_success": "연결 문제를 발견했습니다. 귀하의 요청이 보류 중입니다. 다시 온라인 상태가 되면 다시 보내드리겠습니다.",
+  "pending_info_tiles": "요청을 보내기 위해 인터넷 연결을 기다립니다.",
+  "pending_info_detail": "연결 문제로 인해 귀하의 요청이 아직 전송되지 않았습니다.",
+  "cancel_pending": "대신 내 요청을 취소하세요",
+  "sending": "배상",
+  "queued": "대기 중",
+  "onProgress": "진행 중",
+  "showLess": "간략하게 표시",
+  "customTopMenu": "상단 메뉴 사용자 정의",
+  "limitTopMenu": "상위 메뉴는 7개로만 제한됩니다!",
+  "searchButton": "찾다",
+  "allInformantsInfo": "모든 제보자가 귀하의 메시지를 받게 됩니다.",
+  "action": "행동",
+  "whatMakesYou": "뭐가 널 그렇게 만드니",
+  "letMeWrite": "내가 쓰게 해주세요!",
+  "writeHere": "여기 쓰시 오..",
+  "ratingAspect": "평가 측면",
+  "sendingRequest": "요청 보내기",
+  "changePriority": "우선순위 변경",
+  "referenceNumber": "참조번호",
+  "enterTicketNumber": "티켓번호를 입력하세요",
+  "subject": "주제",
+  "requestReference": "참조 요청",
+  "invalidParentTicket": "부모 티켓이 유효하지 않습니다.",
+  "failedLoad": "애플리케이션을 로드하지 못했습니다.",
+  "tap2retry": "다시 시도하려면 탭하세요.",
+  "chat": "대화",
+  "asset": "자산",
+  "selectAsset": "자산 선택",
+  "addAsset": "자산 추가",
+  "assetList": "자산 목록",
+  "noDataSelected": "선택된 데이터가 없습니다.",
+  "noAssetAdded": "추가된 자산이 없습니다.",
+  "addLabel": "추가"
 }

+ 8 - 1
assets/lang/nl.json

@@ -333,5 +333,12 @@
   "invalidParentTicket": "Ongeldig referentienummer.",
   "failedLoad": "App kon niet worden geladen.",
   "tap2retry": "Tik om opnieuw te proberen.",
-  "chat": "Gesprek"
+  "chat": "Gesprek",
+  "asset": "Vermögenswert",
+  "selectAsset": "Vermögenswert auswählen",
+  "addAsset": "Vermögenswert hinzufügen",
+  "assetList": "Liste der Vermögenswerte",
+  "noDataSelected": "Keine Daten ausgewählt.",
+  "noAssetAdded": "Kein Vermögenswert hinzugefügt.",
+  "addLabel": "Hinzufügen"
 }

+ 340 - 333
assets/lang/zh.json

@@ -1,335 +1,342 @@
 {
-   "account": "帐户",
-   "addNote": "添加备注",
-   "addNoteCancel": "添加取消备注",
-   "all": "全部",
-   "anyNote": "仆人须知",
-   "appointment": "预约",
-   "attach": "附上图片",
-   "buttonCancel": "取消请求",
-   "buttonLogin": "登录",
-   "buttonNo": "不",
-   "buttonResubmit": "重发",
-   "buttonScan": "扫描二维码",
-   "buttonSendEmergency": "发送紧急信息",
-   "buttonSendComplaint": "发送投诉",
-   "buttonSendRequest": "发送请求",
-   "buttonYes": "是的",
-   "buttonSure": "当然",
-   "buttonBack": "后退",
-   "canceledBy": "取消日期:",
-   "category": "类别",
-   "scope": "范围",
-   "changeScope": "范围变更",
-   "chatClosed": "此对话已结束。",
-   "chooseService": "选择您想要的服务",
-   "complaintText": "这是怎么回事? 让专家为您服务。",
-   "complaint": "抱怨",
-   "defaultLocation": "默认位置",
-   "detail": "细节",
-   "disatisfied": "不满意",
-   "emergencyText": "一切紧急和紧急的事情都应该尽快处理。",
-   "emergency": "紧急情况",
-   "forum": "论坛",
-   "frequentlyText": "您在这里经常要求的内容。",
-   "frequently": "经常要求",
-   "frequentlyTitle": "经常要求",
-   "frequentlyTitleText": "您经常请求的列表",
-   "history": "历史",
-   "lessSatisfied": "不太满意",
-   "location": "地点",
-   "logout": "登出",
-   "menuAccount": "帐户",
-   "menuHistory": "历史",
-   "menuService": "服务",
-   "menuHome": "家",
-   "message": "信息",
-   "note": "笔记",
-   "passwordEmpty": "密码不能为空",
-   "password": "密码",
-   "phoneNumber": "电话号码",
-   "placeholderLocation": "你在哪里?",
-   "placeholderNote": "类型注释",
-   "rateMission": "评价此任务",
-   "reallyPleased": "真的很高兴",
-   "requestText2": "你要什么?",
-   "requestDesc": "当您需要帮助时,只需点击它即可。",
-   "requestTitle": "您需要什么样的帮助?",
-   "request": "要求",
-   "satisfactionAsk": "你满意吗?",
-   "satisfied": "相当满意",
-   "scanQr": "请先扫描二维码开始使用应用程序。",
-   "serialNumber": "序列号",
-   "servantGroup": "请求组",
-   "servant": "仆人",
-   "service": "服务",
-   "specifyAnotherLocation": "我想指定另一个位置",
-   "specifyLocation": "定义位置",
-   "startDoing": "开始",
-   "stateCancel": "取消",
-   "stateCanceled": "取消",
-   "stateDone": "处理中",
-   "stateFinish": "结束",
-   "stateQueue": "队列",
-   "stateRequested": "已请求",
-   "state": "地位",
-   "sure": "你确定吗?",
-   "switch": "转变",
-   "system": "系统",
-   "textCancel": "取消",
-   "textHistory": "您已提出的请求",
-   "textLogout": "注销将导致您无法收到通知、发出任何请求等。确定吗?",
-   "textResubmit": "您将将此请求重新发送给仆人。",
-   "ticketNumber": "票号",
-   "timeline": "时间线",
-   "today": "今天",
-   "unrated": "尚未对该任务进行评级",
-   "userEmpty": "用户名不能为空",
-   "userId": "用户名",
-   "version": "版本 ",
-   "verySatisfied": "使满意",
-   "whatComplain": "什么抱怨?",
-   "whatHappen": "到底是怎么回事?",
-   "whatNext": "保持冷静。 接下来是什么?",
-   "whatProblem": "有什么麻烦吗?",
-   "writeMessage": "写信息",
-   "yesterday": "昨天",
-   "language": "语言",
-   "bahasa": "Indonesia",
-   "english": "English",
-   "japanese": "日本語",
-   "korean": "한국어",
-   "chinese": "中文",
-   "german": "Deutsch",
-   "french": "Français",
-   "hindi": "हिंदी",
-   "arabic": "العربية",
-   "dutch": "Nederlands",
-   "chooseLanguage": "选择语言",
-   "rate": "速度",
-   "rated": "该任务已被评级。",
-   "rateText": "你对这次任务[满意]。",
-   "settingPassword": "更改密码",
-   "oldPassword": "旧密码",
-   "newPassword": "新密码",
-   "confirmPassword": "确认新密码",
-   "buttonSave": "保存新密码",
-   "settingPasswordText": "管理您的密码",
-   "autoResponseText": "系统很快就会回复您的请求。",
-   "reply": "回复",
-   "selectPicture": "选择图片",
-   "fromGallery": "来自画廊",
-   "fromCamera": "来自相机",
-   "sendPicture": "发送图片",
-   "seeAttachment": "见附件",
-   "confirmCancel": "您确定要取消吗?",
-   "selectDate": "选择日期",
-   "lengthMax": "允许的最大长度为 128 个字符。",
-   "locRequired": "位置为必填项。",
-   "idRequired": "需要提供身份证件。",
-   "dateRequired": "日期为必填项。",
-   "sendLater": "稍后发送",
-   "thank": "谢谢",
-   "pleaseWait": "请稍等",
-   "sendSuccess": "发送成功",
-   "followUp": "捐助者很快就回复了。",
-   "okGot": "好的,我知道了",
-   "okWait": "可以,当然",
-   "errorConnection": "连接错误。 请在几分钟后重试。",
-   "noInternet": "不能访问网络。",
-   "invalidLogin": "用户名或密码错误。",
-   "invalidPhone": "电话号码无效。",
-   "expAccount": "帐户已过期。",
-   "errorServer": "服务器错误。 请在几分钟后重试。",
-   "accessDenied": "拒绝访问",
-   "licenseProblem": "由于许可证问题,无法运行应用程序。",
-   "invalidVersion": "版本不匹配",
-   "sugestVersion": "使用应用程序版本",
-   "currentVersion": "当前版本是",
-   "contactAdmin": "请联系管理员以获取更多信息。",
-   "pressAgain": "再按一次即可退出。",
-   "notFound": "未找到数据。",
-   "notFound2": "你试图找出的东西不在这里!",
-   "noInternetTitle": "没有网络连接。",
-   "noInternetDesc": "请检查您的互联网连接。 即使我们现在也无法向 Google 询问。",
-   "errorConnectTitle": "无法连接到服务器。",
-   "errorConnectDesc": "请联系管理员,您应该能够连接到服务器。",
-   "errorServerTitle": "服务器错误。",
-   "errorServerDesc": "别惊慌,我们正在努力让一切都回到正轨。",
-   "invalidAccountTitle": "无效账户。",
-   "invalidAccountDesc": "对不起! 我们无法验证您的帐户。 请联系管理员以获取更多信息。",
-   "expAccountTitle": "帐户已过期。",
-   "expAccountDesc": "您的帐户已过期。 或者,如果您认为这是一个错误,您可以联系管理员。",
-   "inProcess": "加工",
-   "policy": "隐私政策",
-   "info": "附加信息",
-   "refresh": "刷新",
-   "messageCamPermission": "拒绝访问。 请通过应用程序权限设置允许 TelMessenger 访问摄像头。",
-   "messageInvalidCode": "无效的代码。 请联系系统管理员。",
-   "messagePassChanged": "修改密码成功。",
-   "wrongOldPass": "旧密码错误。",
-   "checkNewPass": "请检查您的新密码。",
-   "cannotEmpty": "数据不能清空。",
-   "deletedMessage": "此消息已被删除。",
-   "resend": "重发",
-   "delete": "删除",
-   "alreadyUsePass": "无法使用新密码,请定义另一个密码。",
-   "notFoundImg": "找不到图片",
-   "notFoundWorktime": "工作时间没找到。 请联系管理员。",
-   "seeAll": "查看全部",
-   "quickAction": "快速行动",
-   "quickDesc": "帮助您更有效地移动。",
-   "times": " 时间",
-   "search": "搜索",
-   "searchAsk": "搜索...",
-   "helpHint": "尝试寻找一些帮助..",
-   "inProgress": " 请求仍在进行中。",
-   "currentActiveText": "您当前有效的请求",
-   "photo": "照片",
-   "selectRecipient": "选择收件人",
-   "composeMessage": "撰写信息",
-   "to": "到",
-   "addAttachment": "添加附件",
-   "editAttachment": "更改附件",
-   "unsupportedFile": "不支持的文件格式",
-   "pdfFile": "PDF 文件类型",
-   "other": "其他",
-   "noMessageText": "没有消息可供预览。",
-   "noDataText": "没有可用的预览数据。",
-   "noPIDText": "未找到访问代码。",
-   "noPIDText2": "通过扫描 QR 或 TelMessenger 许可证持有者提供的链接获取访问代码。",
-   "loading": "加载中...",
-   "backToLogin": "回到登入",
-   "deleteHistory": "删除历史数据",
-   "deleteHistoryConfirm": "您确定要删除数据吗?",
-   "couldnotDelete": "该数据无法删除。",
-   "allInformants": "所有举报人",
-   "welcome": "欢迎",
-   "createNewPassText": "请在开始使用应用程序之前创建新密码。",
-   "description": "描述",
-   "sorry": "对不起!",
-   "outOfWorkTime": "您的请求目前超出了仆人工作时间。",
-   "willResponse": "他们将很快回复: ",
-   "canNotCancel1": "一旦仆人完成此报告,就无法取消。",
-   "canNotCancel2": "该报告无法取消。",
-   "priorityHigh": "高的",
-   "priorityLow": "低的",
-   "priorityNormal": "普通的",
-   "priority": "优先事项",
-   "reported": "报道",
-   "escalationNoteBySystem": "升级",
-   "finishAttachment": "完成附件",
-   "pleaseScan": "请扫描二维码",
-   "mustScan": "您必须扫描二维码才能重新发送。",
-   "changeCodeMsg": "您将与 <company_name> 建立联系。 你想继续吗?",
-   "currentServer": "当前服务器",
-   "destinationServer": "目的服务器",
-   "textContinue": "继续",
-   "transferNoteBySystem": "转移",
-   "activity": "活动",
-   "image": "图像",
-   "titlePassOld": "输入您的旧密码",
-   "titlePassNew": "您的旧密码将替换为新密码。",
-   "setting": "安排",
-   "more": "更多的",
-   "topMenu": "顶部菜单",
-   "availableMenu": "可用菜单",
-   "customize": "定制",
-   "done": "完毕",
-   "ongoing": "进行中",
-   "maxMenu": "最多 7 个菜单。",
-   "searchIn": "寻找",
-   "yourLocation": "你的地点",
-   "addImage": "欲添图片?",
-   "addImageMsg": "您可以向我们发送图片作为线索或其他东西。",
-   "removeImageMsg": "不,无也。 愿削除之。",
-   "sendingOpt": "交付选项",
-   "sendingOptMsg": "您想按预定请求发送还是立即发送?",
-   "scheduled": "预定",
-   "sendNow": "现在发送",
-   "scheduledMsg": "* 已安排 = 请求将在您在注释中选择的时间发送。",
-   "reqSuccessMsg": "请稍等。 您的请求正在处理中。",
-   "noImgAttach": "没有附上图片.",
-   "btnWait": "好的,我会等",
-   "rateReq": "评价您的请求",
-   "reqAgain": "再次请求",
-   "notAvailable": "该菜单不可用。",
-   "emptyMenuAlert": "您尚未选择任何要显示的菜单。",
-   "redirecting": "重定向...",
-   "initializing": "正在初始化...",
-   "selectAlert": "请至少选择一项菜单。",
-   "scopeDesc": "使用它可以在范围之间切换。",
-   "notFoundKeyword": "找不到与关键字匹配的任何内容 ",
-   "findQRcode": "查找您附近的二维码",
-   "isWorking": " 正在按照您的要求进行处理。",
-   "noteLongAlert": "请添加少于 128 个字符的注释。",
-   "reqCodeNotFound": "请求代码无效。 请联系管理员",
-   "noImage": "未找到图像",
-   "related": "相关服务",
-   "broadcastPermission": "无法发送广播消息,您没有权限。",
-   "broadcastTenant": "无法发送广播消息,收件人租户无效。",
-   "reqForOthers": "是的,我喜欢帮助别人。",
-   "reqForMySelf": "不,我是为自己提出要求。",
-   "requestedBy": "被要求",
-   "requestedFor": "请求的",
-   "typeId": "请输入她/他的 ID",
-   "idNotMatch": "发送请求失败。 #ID 不允许请求此请求。",
-   "idNotFound": "找不到提供的 ID。 请尝试使用其他 ID。",
-   "informantNotRegistered": "您没有注册为接待员或客房服务员。",
-   "link_copied": "链接已复制到剪贴板。",
-   "do_not_disturb": "请勿打扰",
-   "set_dnd_status": "设置免打扰状态",
-   "active_dnd": "积极的",
-   "inactive_dnd": "不活跃",
-   "msg_dnd": "您可以通过帐户菜单停用免打扰状态。",
-   "msg_change_active": "您想激活免打扰状态吗?",
-   "msg_change_inactive": "您想停用 DND 状态吗?",
-   "info_dnd": "DND 状态已激活。",
-   "invalid_bridge": "桥接 URL 无效。",
-   "someone_else": "想要提交其他人的请求吗?",
-   "askScheduleTime": "您的请求应该什么时候完成?",
-   "scheduleMessage": "您的请求应该完成于",
-   "scan_qr": "显示我的二维码",
-   "show_qr": "显示二维码",
-   "show_qr_desc": "将此二维码展示给需要访问该应用程序的朋友或同事。",
-   "dismiss": "解雇",
-   "not_allow_permission": "您的设备不允许该应用程序向您发送任何通知。",
-   "tap_here": "点击此处以允许通知权限。",
-   "doNotDisturb": "请勿打扰模式",
-   "info_label": "信息",
-   "display_menu": "菜单显示",
-   "req_group": "请求组",
-   "ser_group": "仆人组",
-   "save_rating": "保存评级",
-   "auto_translate": "自动翻译",
-   "hold": "暂停",
-   "holdHistory": "暂停历史记录",
-   "pending": "待办的",
-   "pending_info_success": "我们发现连接问题。您的请求正在等待处理。当您重新上线时,我们会再次发送。",
-   "pending_info_tiles": "等待互联网连接发送您的请求。",
-   "pending_info_detail": "由于连接问题,您的请求尚未发送。",
-   "cancel_pending": "取消我的请求",
-   "sending": "发送",
-   "queued": "排队",
-   "onProgress": "关于进展",
-   "showLess": "显示较少",
-   "customTopMenu": "自定义顶部菜单",
-   "limitTopMenu": "顶级菜单仅限7种!",
-   "searchButton": "寻找",
-   "allInformantsInfo": "所有举报人都会收到您的消息。",
-   "action": "行动",
-   "whatMakesYou": "是什么让你",
-   "letMeWrite": "让我来写吧!",
-   "writeHere": "写在这里..",
-   "ratingAspect": "评级方面",
-   "sendingRequest": "发送请求",
-   "changePriority": "改变优先级",
-   "referenceNumber": "参考编号",
-   "enterTicketNumber": "输入票号",
-   "subject": "主题",
-   "requestReference": "请求参考",
-   "invalidParentTicket": "父母票无效。",
-   "failedLoad": "无法加载应用程序。",
-   "tap2retry": "点击重试。",
-   "chat": "对话"
+  "account": "帐户",
+  "addNote": "添加备注",
+  "addNoteCancel": "添加取消备注",
+  "all": "全部",
+  "anyNote": "仆人须知",
+  "appointment": "预约",
+  "attach": "附上图片",
+  "buttonCancel": "取消请求",
+  "buttonLogin": "登录",
+  "buttonNo": "不",
+  "buttonResubmit": "重发",
+  "buttonScan": "扫描二维码",
+  "buttonSendEmergency": "发送紧急信息",
+  "buttonSendComplaint": "发送投诉",
+  "buttonSendRequest": "发送请求",
+  "buttonYes": "是的",
+  "buttonSure": "当然",
+  "buttonBack": "后退",
+  "canceledBy": "取消日期:",
+  "category": "类别",
+  "scope": "范围",
+  "changeScope": "范围变更",
+  "chatClosed": "此对话已结束。",
+  "chooseService": "选择您想要的服务",
+  "complaintText": "这是怎么回事? 让专家为您服务。",
+  "complaint": "抱怨",
+  "defaultLocation": "默认位置",
+  "detail": "细节",
+  "disatisfied": "不满意",
+  "emergencyText": "一切紧急和紧急的事情都应该尽快处理。",
+  "emergency": "紧急情况",
+  "forum": "论坛",
+  "frequentlyText": "您在这里经常要求的内容。",
+  "frequently": "经常要求",
+  "frequentlyTitle": "经常要求",
+  "frequentlyTitleText": "您经常请求的列表",
+  "history": "历史",
+  "lessSatisfied": "不太满意",
+  "location": "地点",
+  "logout": "登出",
+  "menuAccount": "帐户",
+  "menuHistory": "历史",
+  "menuService": "服务",
+  "menuHome": "家",
+  "message": "信息",
+  "note": "笔记",
+  "passwordEmpty": "密码不能为空",
+  "password": "密码",
+  "phoneNumber": "电话号码",
+  "placeholderLocation": "你在哪里?",
+  "placeholderNote": "类型注释",
+  "rateMission": "评价此任务",
+  "reallyPleased": "真的很高兴",
+  "requestText2": "你要什么?",
+  "requestDesc": "当您需要帮助时,只需点击它即可。",
+  "requestTitle": "您需要什么样的帮助?",
+  "request": "要求",
+  "satisfactionAsk": "你满意吗?",
+  "satisfied": "相当满意",
+  "scanQr": "请先扫描二维码开始使用应用程序。",
+  "serialNumber": "序列号",
+  "servantGroup": "请求组",
+  "servant": "仆人",
+  "service": "服务",
+  "specifyAnotherLocation": "我想指定另一个位置",
+  "specifyLocation": "定义位置",
+  "startDoing": "开始",
+  "stateCancel": "取消",
+  "stateCanceled": "取消",
+  "stateDone": "处理中",
+  "stateFinish": "结束",
+  "stateQueue": "队列",
+  "stateRequested": "已请求",
+  "state": "地位",
+  "sure": "你确定吗?",
+  "switch": "转变",
+  "system": "系统",
+  "textCancel": "取消",
+  "textHistory": "您已提出的请求",
+  "textLogout": "注销将导致您无法收到通知、发出任何请求等。确定吗?",
+  "textResubmit": "您将将此请求重新发送给仆人。",
+  "ticketNumber": "票号",
+  "timeline": "时间线",
+  "today": "今天",
+  "unrated": "尚未对该任务进行评级",
+  "userEmpty": "用户名不能为空",
+  "userId": "用户名",
+  "version": "版本 ",
+  "verySatisfied": "使满意",
+  "whatComplain": "什么抱怨?",
+  "whatHappen": "到底是怎么回事?",
+  "whatNext": "保持冷静。 接下来是什么?",
+  "whatProblem": "有什么麻烦吗?",
+  "writeMessage": "写信息",
+  "yesterday": "昨天",
+  "language": "语言",
+  "bahasa": "Indonesia",
+  "english": "English",
+  "japanese": "日本語",
+  "korean": "한국어",
+  "chinese": "中文",
+  "german": "Deutsch",
+  "french": "Français",
+  "hindi": "हिंदी",
+  "arabic": "العربية",
+  "dutch": "Nederlands",
+  "chooseLanguage": "选择语言",
+  "rate": "速度",
+  "rated": "该任务已被评级。",
+  "rateText": "你对这次任务[满意]。",
+  "settingPassword": "更改密码",
+  "oldPassword": "旧密码",
+  "newPassword": "新密码",
+  "confirmPassword": "确认新密码",
+  "buttonSave": "保存新密码",
+  "settingPasswordText": "管理您的密码",
+  "autoResponseText": "系统很快就会回复您的请求。",
+  "reply": "回复",
+  "selectPicture": "选择图片",
+  "fromGallery": "来自画廊",
+  "fromCamera": "来自相机",
+  "sendPicture": "发送图片",
+  "seeAttachment": "见附件",
+  "confirmCancel": "您确定要取消吗?",
+  "selectDate": "选择日期",
+  "lengthMax": "允许的最大长度为 128 个字符。",
+  "locRequired": "位置为必填项。",
+  "idRequired": "需要提供身份证件。",
+  "dateRequired": "日期为必填项。",
+  "sendLater": "稍后发送",
+  "thank": "谢谢",
+  "pleaseWait": "请稍等",
+  "sendSuccess": "发送成功",
+  "followUp": "捐助者很快就回复了。",
+  "okGot": "好的,我知道了",
+  "okWait": "可以,当然",
+  "errorConnection": "连接错误。 请在几分钟后重试。",
+  "noInternet": "不能访问网络。",
+  "invalidLogin": "用户名或密码错误。",
+  "invalidPhone": "电话号码无效。",
+  "expAccount": "帐户已过期。",
+  "errorServer": "服务器错误。 请在几分钟后重试。",
+  "accessDenied": "拒绝访问",
+  "licenseProblem": "由于许可证问题,无法运行应用程序。",
+  "invalidVersion": "版本不匹配",
+  "sugestVersion": "使用应用程序版本",
+  "currentVersion": "当前版本是",
+  "contactAdmin": "请联系管理员以获取更多信息。",
+  "pressAgain": "再按一次即可退出。",
+  "notFound": "未找到数据。",
+  "notFound2": "你试图找出的东西不在这里!",
+  "noInternetTitle": "没有网络连接。",
+  "noInternetDesc": "请检查您的互联网连接。 即使我们现在也无法向 Google 询问。",
+  "errorConnectTitle": "无法连接到服务器。",
+  "errorConnectDesc": "请联系管理员,您应该能够连接到服务器。",
+  "errorServerTitle": "服务器错误。",
+  "errorServerDesc": "别惊慌,我们正在努力让一切都回到正轨。",
+  "invalidAccountTitle": "无效账户。",
+  "invalidAccountDesc": "对不起! 我们无法验证您的帐户。 请联系管理员以获取更多信息。",
+  "expAccountTitle": "帐户已过期。",
+  "expAccountDesc": "您的帐户已过期。 或者,如果您认为这是一个错误,您可以联系管理员。",
+  "inProcess": "加工",
+  "policy": "隐私政策",
+  "info": "附加信息",
+  "refresh": "刷新",
+  "messageCamPermission": "拒绝访问。 请通过应用程序权限设置允许 TelMessenger 访问摄像头。",
+  "messageInvalidCode": "无效的代码。 请联系系统管理员。",
+  "messagePassChanged": "修改密码成功。",
+  "wrongOldPass": "旧密码错误。",
+  "checkNewPass": "请检查您的新密码。",
+  "cannotEmpty": "数据不能清空。",
+  "deletedMessage": "此消息已被删除。",
+  "resend": "重发",
+  "delete": "删除",
+  "alreadyUsePass": "无法使用新密码,请定义另一个密码。",
+  "notFoundImg": "找不到图片",
+  "notFoundWorktime": "工作时间没找到。 请联系管理员。",
+  "seeAll": "查看全部",
+  "quickAction": "快速行动",
+  "quickDesc": "帮助您更有效地移动。",
+  "times": " 时间",
+  "search": "搜索",
+  "searchAsk": "搜索...",
+  "helpHint": "尝试寻找一些帮助..",
+  "inProgress": " 请求仍在进行中。",
+  "currentActiveText": "您当前有效的请求",
+  "photo": "照片",
+  "selectRecipient": "选择收件人",
+  "composeMessage": "撰写信息",
+  "to": "到",
+  "addAttachment": "添加附件",
+  "editAttachment": "更改附件",
+  "unsupportedFile": "不支持的文件格式",
+  "pdfFile": "PDF 文件类型",
+  "other": "其他",
+  "noMessageText": "没有消息可供预览。",
+  "noDataText": "没有可用的预览数据。",
+  "noPIDText": "未找到访问代码。",
+  "noPIDText2": "通过扫描 QR 或 TelMessenger 许可证持有者提供的链接获取访问代码。",
+  "loading": "加载中...",
+  "backToLogin": "回到登入",
+  "deleteHistory": "删除历史数据",
+  "deleteHistoryConfirm": "您确定要删除数据吗?",
+  "couldnotDelete": "该数据无法删除。",
+  "allInformants": "所有举报人",
+  "welcome": "欢迎",
+  "createNewPassText": "请在开始使用应用程序之前创建新密码。",
+  "description": "描述",
+  "sorry": "对不起!",
+  "outOfWorkTime": "您的请求目前超出了仆人工作时间。",
+  "willResponse": "他们将很快回复: ",
+  "canNotCancel1": "一旦仆人完成此报告,就无法取消。",
+  "canNotCancel2": "该报告无法取消。",
+  "priorityHigh": "高的",
+  "priorityLow": "低的",
+  "priorityNormal": "普通的",
+  "priority": "优先事项",
+  "reported": "报道",
+  "escalationNoteBySystem": "升级",
+  "finishAttachment": "完成附件",
+  "pleaseScan": "请扫描二维码",
+  "mustScan": "您必须扫描二维码才能重新发送。",
+  "changeCodeMsg": "您将与 <company_name> 建立联系。 你想继续吗?",
+  "currentServer": "当前服务器",
+  "destinationServer": "目的服务器",
+  "textContinue": "继续",
+  "transferNoteBySystem": "转移",
+  "activity": "活动",
+  "image": "图像",
+  "titlePassOld": "输入您的旧密码",
+  "titlePassNew": "您的旧密码将替换为新密码。",
+  "setting": "安排",
+  "more": "更多的",
+  "topMenu": "顶部菜单",
+  "availableMenu": "可用菜单",
+  "customize": "定制",
+  "done": "完毕",
+  "ongoing": "进行中",
+  "maxMenu": "最多 7 个菜单。",
+  "searchIn": "寻找",
+  "yourLocation": "你的地点",
+  "addImage": "欲添图片?",
+  "addImageMsg": "您可以向我们发送图片作为线索或其他东西。",
+  "removeImageMsg": "不,无也。 愿削除之。",
+  "sendingOpt": "交付选项",
+  "sendingOptMsg": "您想按预定请求发送还是立即发送?",
+  "scheduled": "预定",
+  "sendNow": "现在发送",
+  "scheduledMsg": "* 已安排 = 请求将在您在注释中选择的时间发送。",
+  "reqSuccessMsg": "请稍等。 您的请求正在处理中。",
+  "noImgAttach": "没有附上图片.",
+  "btnWait": "好的,我会等",
+  "rateReq": "评价您的请求",
+  "reqAgain": "再次请求",
+  "notAvailable": "该菜单不可用。",
+  "emptyMenuAlert": "您尚未选择任何要显示的菜单。",
+  "redirecting": "重定向...",
+  "initializing": "正在初始化...",
+  "selectAlert": "请至少选择一项菜单。",
+  "scopeDesc": "使用它可以在范围之间切换。",
+  "notFoundKeyword": "找不到与关键字匹配的任何内容 ",
+  "findQRcode": "查找您附近的二维码",
+  "isWorking": " 正在按照您的要求进行处理。",
+  "noteLongAlert": "请添加少于 128 个字符的注释。",
+  "reqCodeNotFound": "请求代码无效。 请联系管理员",
+  "noImage": "未找到图像",
+  "related": "相关服务",
+  "broadcastPermission": "无法发送广播消息,您没有权限。",
+  "broadcastTenant": "无法发送广播消息,收件人租户无效。",
+  "reqForOthers": "是的,我喜欢帮助别人。",
+  "reqForMySelf": "不,我是为自己提出要求。",
+  "requestedBy": "被要求",
+  "requestedFor": "请求的",
+  "typeId": "请输入她/他的 ID",
+  "idNotMatch": "发送请求失败。 #ID 不允许请求此请求。",
+  "idNotFound": "找不到提供的 ID。 请尝试使用其他 ID。",
+  "informantNotRegistered": "您没有注册为接待员或客房服务员。",
+  "link_copied": "链接已复制到剪贴板。",
+  "do_not_disturb": "请勿打扰",
+  "set_dnd_status": "设置免打扰状态",
+  "active_dnd": "积极的",
+  "inactive_dnd": "不活跃",
+  "msg_dnd": "您可以通过帐户菜单停用免打扰状态。",
+  "msg_change_active": "您想激活免打扰状态吗?",
+  "msg_change_inactive": "您想停用 DND 状态吗?",
+  "info_dnd": "DND 状态已激活。",
+  "invalid_bridge": "桥接 URL 无效。",
+  "someone_else": "想要提交其他人的请求吗?",
+  "askScheduleTime": "您的请求应该什么时候完成?",
+  "scheduleMessage": "您的请求应该完成于",
+  "scan_qr": "显示我的二维码",
+  "show_qr": "显示二维码",
+  "show_qr_desc": "将此二维码展示给需要访问该应用程序的朋友或同事。",
+  "dismiss": "解雇",
+  "not_allow_permission": "您的设备不允许该应用程序向您发送任何通知。",
+  "tap_here": "点击此处以允许通知权限。",
+  "doNotDisturb": "请勿打扰模式",
+  "info_label": "信息",
+  "display_menu": "菜单显示",
+  "req_group": "请求组",
+  "ser_group": "仆人组",
+  "save_rating": "保存评级",
+  "auto_translate": "自动翻译",
+  "hold": "暂停",
+  "holdHistory": "暂停历史记录",
+  "pending": "待办的",
+  "pending_info_success": "我们发现连接问题。您的请求正在等待处理。当您重新上线时,我们会再次发送。",
+  "pending_info_tiles": "等待互联网连接发送您的请求。",
+  "pending_info_detail": "由于连接问题,您的请求尚未发送。",
+  "cancel_pending": "取消我的请求",
+  "sending": "发送",
+  "queued": "排队",
+  "onProgress": "关于进展",
+  "showLess": "显示较少",
+  "customTopMenu": "自定义顶部菜单",
+  "limitTopMenu": "顶级菜单仅限7种!",
+  "searchButton": "寻找",
+  "allInformantsInfo": "所有举报人都会收到您的消息。",
+  "action": "行动",
+  "whatMakesYou": "是什么让你",
+  "letMeWrite": "让我来写吧!",
+  "writeHere": "写在这里..",
+  "ratingAspect": "评级方面",
+  "sendingRequest": "发送请求",
+  "changePriority": "改变优先级",
+  "referenceNumber": "参考编号",
+  "enterTicketNumber": "输入票号",
+  "subject": "主题",
+  "requestReference": "请求参考",
+  "invalidParentTicket": "父母票无效。",
+  "failedLoad": "无法加载应用程序。",
+  "tap2retry": "点击重试。",
+  "chat": "对话",
+  "asset": "资产",
+  "selectAsset": "选择资产",
+  "addAsset": "添加资产",
+  "assetList": "资产列表",
+  "noDataSelected": "未选择任何数据。",
+  "noAssetAdded": "未添加任何资产。",
+  "addLabel": "添加"
 }

+ 24 - 17
lib/main.dart

@@ -9,6 +9,7 @@ import 'package:firebase_messaging/firebase_messaging.dart';
 import 'package:flutter/foundation.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter/services.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
 import 'package:flutter_local_notifications/flutter_local_notifications.dart';
 // import 'package:flutter_native_splash/flutter_native_splash.dart';
 import 'package:fluttertoast/fluttertoast.dart';
@@ -17,6 +18,7 @@ import 'package:provider/provider.dart';
 import 'package:quick_notify_2/quick_notify.dart';
 import 'package:shared_preferences/shared_preferences.dart';
 import 'package:telnow_mobile_new/src/api/api_auth_provider.dart';
+import 'package:telnow_mobile_new/src/cubit/user_data_cubit.dart';
 import 'package:telnow_mobile_new/src/injector/injector.dart';
 import 'package:telnow_mobile_new/src/layouts/mobile/history_forum.dart';
 import 'package:telnow_mobile_new/src/layouts/mobile/message_list.dart';
@@ -119,23 +121,28 @@ class MyApp extends StatelessWidget {
         ChangeNotifierProvider(create: (_) => CreateSerModule()),
         ChangeNotifierProvider(create: (_) => MessageModule()),
       ],
-      child: MaterialApp.router(
-        // routerDelegate: _appRouter.delegate(),
-        // routeInformationParser: _appRouter.defaultRouteParser(),
-        scrollBehavior: MyCustomScrollBehavior(),
-        debugShowCheckedModeBanner: false,
-        localizationsDelegates: context.localizationDelegates,
-        supportedLocales: context.supportedLocales,
-        locale: context.locale,
-        key: NavigationService.navigatorKey,
-        theme: ThemeData(useMaterial3: false, fontFamily: 'SF Compact Display', appBarTheme: AppBarTheme(
-          systemOverlayStyle: SystemUiOverlayStyle(
-              statusBarColor: Colors.transparent,
-              statusBarIconBrightness: Brightness.dark,
-              statusBarBrightness: Brightness.dark
-          ),
-        ), colorScheme: ColorScheme.fromSeed(seedColor: Color(0xff078C84))),
-        routerConfig: _appRouter.config(),
+      child: MultiBlocProvider(
+        providers: [
+          BlocProvider(create: (_) => UserCubit()),
+        ],
+        child: MaterialApp.router(
+          // routerDelegate: _appRouter.delegate(),
+          // routeInformationParser: _appRouter.defaultRouteParser(),
+          scrollBehavior: MyCustomScrollBehavior(),
+          debugShowCheckedModeBanner: false,
+          localizationsDelegates: context.localizationDelegates,
+          supportedLocales: context.supportedLocales,
+          locale: context.locale,
+          key: NavigationService.navigatorKey,
+          theme: ThemeData(useMaterial3: false, fontFamily: 'SF Compact Display', appBarTheme: AppBarTheme(
+            systemOverlayStyle: SystemUiOverlayStyle(
+                statusBarColor: Colors.transparent,
+                statusBarIconBrightness: Brightness.dark,
+                statusBarBrightness: Brightness.dark
+            ),
+          ), colorScheme: ColorScheme.fromSeed(seedColor: Color(0xff078C84))),
+          routerConfig: _appRouter.config(),
+        ),
       ),
     );
   }

+ 2 - 1
lib/src/api/api_auth_provider.dart

@@ -26,7 +26,7 @@ class ApiAuthProvider {
 
   final String displayVersion = '4.0.17'; //versi aplikasi untuk di tampilkan
   final int currentVersion = 40; //versi aplikasi yang digunakan untuk pengecekan versi
-  final String buildNumber = '2539.01';
+  final String buildNumber = '2617.01';
 
 //  final String companyName = '999';
 //  final String _baseUrl = 'http://139.162.7.140:9090/';
@@ -215,6 +215,7 @@ class ApiAuthProvider {
       );
       return json.decode(response.data!);
     } on DioException catch (error) {
+      debugPrint("Error DIO: ${error.toString()}");
       bool isOpen = UIService.isCurrentRouteInactive;
       if (error.response == null) {
         try {

+ 2 - 6
lib/src/api/jwt_token.dart

@@ -103,12 +103,8 @@ class JwtToken{
       }
 
       if(user != null){
-        if(U.newServerVersion(1754624839)){
-          var code = U.getLang(user['language']).toLowerCase();
-          setLocale(code);
-        } else {
-          setLocale(user['language'].toLowerCase());
-        }
+        var code = U.getLang(user['language']).toLowerCase();
+        setLocale(code);
       }
 
       if(U.getInternetStatus()){

+ 129 - 0
lib/src/cubit/history_detail_cubit.dart

@@ -0,0 +1,129 @@
+import 'package:equatable/equatable.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+
+import '../repository/history_repository.dart';
+import '../utils/U.dart';
+
+class HistoryDetailState extends Equatable{
+  final Map<String, dynamic> data;
+  final Map<String, dynamic> asset;
+  final String fileName;
+  final bool isActive;
+  final bool timeLimit;
+  final bool showLoading;
+  final bool isLoading;
+
+  const HistoryDetailState({
+    this.data = const {},
+    this.asset = const {},
+    this.fileName = '',
+    this.isActive = false,
+    this.timeLimit = false,
+    this.showLoading = false,
+    this.isLoading = false,
+  });
+
+  HistoryDetailState copyWith({
+    Map<String, dynamic>? data,
+    Map<String, dynamic>? asset,
+    String? fileName,
+    bool? isActive,
+    bool? timeLimit,
+    bool? showLoading,
+    bool? isLoading,
+  }) {
+    return HistoryDetailState(
+      data: data ?? this.data,
+      asset: asset ?? this.asset,
+      fileName: fileName ?? this.fileName,
+      isActive: isActive ?? this.isActive,
+      timeLimit: timeLimit ?? this.timeLimit,
+      showLoading: showLoading ?? this.showLoading,
+      isLoading: isLoading ?? this.isLoading,
+    );
+  }
+
+  @override
+  // TODO: implement props
+  List<Object?> get props => [data, asset, fileName, isActive, timeLimit, showLoading, isLoading];
+
+}
+
+class OpenAttachment extends HistoryDetailState {}
+
+class NavigateBack extends HistoryDetailState {
+  final bool exc;
+  const NavigateBack(this.exc);
+}
+
+class HistoryDetailCubit extends Cubit<HistoryDetailState> {
+  final HistoryRepository historyRepo = HistoryRepository();
+
+  HistoryDetailCubit() : super(const HistoryDetailState());
+
+  Future<void> getData(String ticketNo, String locale) async {
+    Map<String, dynamic>? data = {};
+    Map<String, dynamic>? asset = {};
+    String baseUrl = await HistoryRepository().getBaseUrl();
+    bool isActive = false;
+
+    emit(state.copyWith(isLoading: true));
+
+    try {
+      data = await historyRepo.getDetail(ticketNo, locale);
+
+      if (data['_asset'] != null){
+        asset['name'] = data['_asset']['name'];
+        asset['description'] = data['_asset']['description'];
+        asset['_mobileImage'] = baseUrl + data['_asset']['image'];
+      }
+      isActive = data['currentState'] == 'DIPROSES' ||
+          data['currentState'] == 'DIANTRIKAN' ||
+          data['currentState'] == 'DIMULAI' ||
+          data['currentState'] == 'DISELESAIKAN';
+
+      emit(state.copyWith(data: data, asset: asset, isActive: isActive, isLoading: false));
+    } catch (e) {
+      data = {};
+      emit(state.copyWith(data: data, isLoading: false, timeLimit: true));
+    }
+
+  }
+
+  void setFileName(String fileName){
+    emit(state.copyWith(fileName: fileName));
+  }
+
+  Future<void> openAttachment(Map<String, dynamic> data) async {
+    String fileName = await HistoryRepository().getPath(state.data);
+
+    emit(state.copyWith(fileName: fileName));
+    emit(OpenAttachment());
+  }
+
+  Future<void> setAsset(String ticketNo, Map<String, dynamic> data) async {
+    Map<String, dynamic> asset = {};
+    String baseUrl = await HistoryRepository().getBaseUrl();
+
+    asset = await HistoryRepository().setAsset(ticketNo, data, baseUrl);
+
+    emit(state.copyWith(asset: asset));
+  }
+
+  Future<void> cancelRequest(list, controllerNote) async {
+    emit(state.copyWith(showLoading: true));
+
+    var data = {
+      'note': controllerNote.text.trim(),
+    };
+
+    var res = await HistoryRepository().cancelRequest(list['ticketNo'], data);
+    if(res != null){
+      emit(NavigateBack(true));
+      // navigateBack(context, exc: true);
+    }
+    emit(state.copyWith(showLoading: false));
+  }
+
+}

+ 179 - 0
lib/src/cubit/history_menu_cubit.dart

@@ -0,0 +1,179 @@
+import 'dart:convert';
+
+import 'package:easy_localization/easy_localization.dart';
+import 'package:equatable/equatable.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+
+import '../repository/history_repository.dart';
+import '../storage/sharedpreferences/shared_preferences_manager.dart';
+import '../utils/U.dart';
+import '../utils/cache_manager.dart';
+
+enum HistoryTab {
+  ongoing,
+  done;
+
+  List get filters {
+    switch(this){
+      case HistoryTab.ongoing:
+        return [
+          {'title': 'stateQueue'.tr(), 'value': 'queue', 'filter': '{"or":[{"f":["currentState","EQ","DIANTRIKAN"]},{"f":["currentState","EQ","DIPROSES"]}]}'},
+          {'title': 'stateDone'.tr(), 'value': 'done', 'filter': '{"f":["currentState","EQ","DIMULAI"]}'},
+          {'title': 'hold'.tr(), 'value': 'hold', 'filter': '{"f":["currentState","EQ","HOLD"]}'}
+        ];
+      case HistoryTab.done:
+        return [
+          {'title': 'stateFinish'.tr(), 'value': 'finish', 'filter': '{"or":[{"f":["currentState","EQ","DISELESAIKAN"]},{"f":["currentState","EQ","TUNTAS"]}]}'},
+          {'title': 'stateCancel'.tr(), 'value': 'cancel', 'filter': '{"f":["currentState","EQ","DIBATALKAN"]}'}
+        ];
+    }
+  }
+}
+
+class MenuHistoryState extends Equatable {
+  final HistoryTab activeTab;
+  final List<dynamic> pendingData;
+  final List activeForum;
+  final bool multiSelectMode;
+  final List<int> selectedIndex;
+  final int activeIndex;
+
+
+  const MenuHistoryState({
+    this.activeTab = HistoryTab.ongoing,
+    this.pendingData = const [],
+    this.activeForum = const [],
+    this.multiSelectMode = false,
+    this.selectedIndex = const [],
+    this.activeIndex = 0,
+  });
+
+  MenuHistoryState copyWith({
+    HistoryTab? activeTab,
+    List<dynamic>? pendingData,
+    List? activeForum,
+    bool? multiSelectMode,
+    List<int>? selectedIndex,
+    int? activeIndex,
+  }){
+    return MenuHistoryState(
+      activeTab: activeTab ?? this.activeTab,
+      pendingData: pendingData ?? this.pendingData,
+      activeForum: activeForum ?? this.activeForum,
+      multiSelectMode: multiSelectMode ?? this.multiSelectMode,
+      selectedIndex: selectedIndex ?? this.selectedIndex,
+      activeIndex: activeIndex ?? this.activeIndex,
+    );
+  }
+
+  @override
+  List<Object?> get props => [activeTab, pendingData, activeForum, multiSelectMode, selectedIndex, activeIndex];
+
+}
+
+class ReloadPage extends MenuHistoryState {}
+
+class CreateNewRequest extends MenuHistoryState {
+  final Map<String,dynamic> request;
+  const CreateNewRequest(this.request);
+}
+
+class ShowError extends MenuHistoryState {
+  final String error;
+  const ShowError(this.error);
+}
+
+class TabChanged extends MenuHistoryState {
+  final int index;
+  const TabChanged(this.index);
+}
+
+class MenuHistoryCubit extends Cubit<MenuHistoryState> {
+  MenuHistoryCubit() : super(MenuHistoryState());
+  final SharedPreferencesManager sharedPreferencesManager = SharedPreferencesManager();
+
+  void init() {
+    setActiveTab(state.activeTab);
+    getActiveForum();
+    getPendingData();
+  }
+
+  void getPendingData() async {
+    if(!U.getInternetStatus()){
+      List pendingList = sharedPreferencesManager.isKeyExists(SharedPreferencesManager.keyPendingData)!?jsonDecode(sharedPreferencesManager.getString(SharedPreferencesManager.keyPendingData)!):[];
+      setPendingData(pendingList);
+    }
+  }
+
+  void setPendingData(List<dynamic> data){
+    emit(state.copyWith(pendingData: data));
+  }
+
+  void setActiveTab(HistoryTab tab){
+    if(state.activeTab == tab) return;
+
+    int index = 0;
+    switch(tab){
+      case HistoryTab.ongoing:
+        index = 0;
+        break;
+      case HistoryTab.done:
+        index = 1;
+        break;
+    }
+
+    emit(state.copyWith(activeTab: tab, activeIndex: index));
+  }
+
+  Future<void> getActiveForum() async {
+    String url = '/api/notifications/search/forumNotification';
+    var forum = [];
+
+    // # check cache
+    var cacheData = await CacheMan.readData(url);
+    if(cacheData?['data'] != null){
+      emit(state.copyWith(activeForum: cacheData['data']));
+    }
+
+    forum = await HistoryRepository().getActiveForum(url);
+    emit(state.copyWith(activeForum: forum));
+  }
+
+  void setMultiSelectMode(bool val){
+    emit(state.copyWith(multiSelectMode: val));
+  }
+
+  void selectIndex(int index){
+    final updated = List<int>.from(state.selectedIndex);
+
+    if(updated.contains(index)) {
+      updated.remove(index);
+    } else {
+      updated.add(index);
+    }
+
+    if(updated.isEmpty){
+      emit(state.copyWith(selectedIndex: [], multiSelectMode: false));
+    } else {
+      emit(state.copyWith(selectedIndex: updated, multiSelectMode: true));
+    }
+  }
+
+  void deleteData(List<dynamic> data){
+    List<String> params = [];
+
+    for (var e in state.selectedIndex) {
+      params.add(data[e]["ticketNo"]);
+    }
+
+    var res = HistoryRepository().deleteData(params);
+    if (res != null) {
+      emit(ReloadPage());
+    }
+  }
+
+  void showError(String error){
+    emit(ShowError(error));
+  }
+
+}

+ 235 - 0
lib/src/cubit/history_tab_cubit.dart

@@ -0,0 +1,235 @@
+import 'package:equatable/equatable.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+
+import '../repository/history_repository.dart';
+import '../utils/cache_manager.dart';
+
+class TabState extends Equatable {
+  final List data;
+  final bool isLoading;
+  final bool stopLoad;
+  final int page;
+  final String filter;
+  final List<dynamic> activeForum;
+  final bool reload;
+
+  const TabState({
+    this.data = const [],
+    this.isLoading = false,
+    this.stopLoad = false,
+    this.page = 0,
+    this.filter = 'none',
+    this.activeForum = const [],
+    this.reload = false
+  });
+
+  TabState copyWith({
+    List? data,
+    bool? isLoading,
+    bool? stopLoad,
+    int? page,
+    String? filter,
+    List? activeForum,
+    bool? reload
+  }) {
+    return TabState(
+      data: data ?? this.data,
+      isLoading: isLoading ?? this.isLoading,
+      stopLoad: stopLoad ?? this.stopLoad,
+      page: page ?? this.page,
+      filter: filter ?? this.filter,
+      activeForum: activeForum ?? this.activeForum,
+      reload: reload ?? this.reload,
+    );
+  }
+
+  @override
+  List<Object?> get props => [data, isLoading, stopLoad, page, filter, activeForum, reload];
+}
+
+class ReloadContainer extends TabState {}
+
+// # Cubit for Ongoing Tab
+class OngoingCubit extends Cubit<TabState> {
+  final HistoryRepository historyRepo = HistoryRepository();
+
+  OngoingCubit() : super(const TabState());
+
+  Future<void> loadOngoing() async {
+    if(state.stopLoad) return;
+
+    if(!state.reload) {
+      if (state.data.isNotEmpty) {
+        emit(state.copyWith(isLoading: false));
+      }
+      if (state.page == 0) emit(state.copyWith(isLoading: true));
+    } else {
+      emit(state.copyWith(reload: false));
+    }
+
+    String filter = '';
+    int page = 0;
+    int size = 30;
+    bool stopLoad = false;
+
+    switch(state.filter){
+      case 'none':
+        filter = '{"or":[{"f":["currentState","EQ","DIANTRIKAN"]},{"f":["currentState","EQ","DIPROSES"]},{"f":["currentState","EQ","DIMULAI"]}]}';
+        break;
+      case 'queue':
+        filter = '{"or":[{"f":["currentState","EQ","DIANTRIKAN"]},{"f":["currentState","EQ","DIPROSES"]}]}';
+        break;
+      case 'done':
+        filter = '{"f":["currentState","EQ","DIMULAI"]}';
+        break;
+      case 'hold':
+        filter = '{"f":["currentState","EQ","HOLD"]}';
+        break;
+      default:
+        filter = '{"or":[{"f":["currentState","EQ","DIANTRIKAN"]},{"f":["currentState","EQ","DIPROSES"]},{"f":["currentState","EQ","DIMULAI"]}]}';
+    }
+
+    if(state.page != 0) page = state.page;
+
+    // cache manager
+    String key = '#ongoing#$filter';
+    if(!state.reload) {
+      var val = await CacheMan.readData(key);
+      if (val != null && page == 0) {
+        emit(state.copyWith(data: val['data'], isLoading: false, stopLoad: stopLoad));
+      }
+    }
+
+    try {
+      List tempData = List<dynamic>.from(state.data);
+
+      final result = await historyRepo.getData(key, filter, page, size, state.activeForum);
+      if(result.length < size) stopLoad = true;
+
+      if(state.page > 0){
+        for (var element in result) {
+          tempData.add(element);
+        }
+      } else {
+        tempData = result;
+      }
+
+      emit(state.copyWith(data: tempData, isLoading: false, stopLoad: stopLoad));
+    } catch (e) {
+      emit(state.copyWith(data: [], isLoading: false));
+    }
+  }
+
+  void setFilter(currentFilter) {
+    emit(state.copyWith(data: [], filter: currentFilter, page: 0, stopLoad: false));
+    loadOngoing();
+  }
+
+  void loadNextPage() {
+    emit(state.copyWith(page: state.page + 1));
+    loadOngoing();
+  }
+
+  void reloadPage(){
+    emit(state.copyWith(data: [], page: 0, stopLoad: false, isLoading: true, reload: true));
+    loadOngoing();
+  }
+
+}
+
+// # Cubit for Done Tab
+class DoneCubit extends Cubit<TabState> {
+  final HistoryRepository historyRepo = HistoryRepository();
+
+  DoneCubit() : super(const TabState());
+
+  Future<void> loadDone() async {
+    if(state.stopLoad || state.isLoading) return;
+    emit(state.copyWith(isLoading: true));
+
+    if(!state.reload) {
+      if (state.data.isNotEmpty) {
+        emit(state.copyWith(isLoading: false));
+      }
+
+      if (state.page == 0) emit(state.copyWith(isLoading: true));
+    } else {
+      emit(state.copyWith(reload: false));
+    }
+
+    String filter = '';
+    int page = 0;
+    int size = 30;
+    bool stopLoad = false;
+
+    switch(state.filter){
+      case 'none':
+        filter = '{"or":[{"f":["currentState","EQ","DISELESAIKAN"]},{"f":["currentState","EQ","TUNTAS"]},{"f":["currentState","EQ","DIBATALKAN"]}]}';
+        break;
+      case 'finish':
+        filter = '{"or":[{"f":["currentState","EQ","DISELESAIKAN"]},{"f":["currentState","EQ","TUNTAS"]}]}';
+        break;
+      case 'cancel':
+        filter = '{"f":["currentState","EQ","DIBATALKAN"]}';
+        break;
+      default:
+        filter = '{"or":[{"f":["currentState","EQ","DISELESAIKAN"]},{"f":["currentState","EQ","TUNTAS"]},{"f":["currentState","EQ","DIBATALKAN"]}]}';
+    }
+
+    if(state.page != 0) page = state.page;
+
+    // # cache manager
+    String key = '#done#$filter';
+    if(!state.reload) {
+      var val = await CacheMan.readData(key);
+      if (val != null && page == 0) {
+        emit(state.copyWith(
+            data: val['data'], isLoading: false, stopLoad: stopLoad));
+      }
+    }
+
+    try {
+      List tempData = List<dynamic>.from(state.data);
+
+      final result = await historyRepo.getData(key, filter, page, size, state.activeForum);
+
+      if(result.length < size) stopLoad = true;
+
+      if(state.page > 0){
+        for (var element in result) {
+          tempData.add(element);
+        }
+      } else {
+        tempData = result;
+      }
+
+      emit(state.copyWith(data: tempData, isLoading: false, stopLoad: stopLoad));
+    } catch (e) {
+      emit(state.copyWith(data: [], isLoading: false));
+    }
+  }
+
+  void setFilter(currentFilter) {
+    emit(state.copyWith(filter: currentFilter, page: 0, stopLoad: false));
+    loadDone();
+  }
+
+  void loadNextPage() {
+    emit(state.copyWith(page: state.page + 1));
+    loadDone();
+  }
+
+  void reloadPage(){
+    emit(state.copyWith(data: [], page: 0, stopLoad: false, isLoading: true, reload: true));
+    loadDone();
+  }
+
+  void setSatisfaction(int index, int tempRating) {
+    emit(state.copyWith(isLoading: true));
+    List tempData = List<dynamic>.from(state.data);
+    tempData[index]['satisfactionRate'] = tempRating;
+
+    emit(state.copyWith(data: tempData, isLoading: false));
+  }
+}

+ 86 - 0
lib/src/cubit/pickup_asset_cubit.dart

@@ -0,0 +1,86 @@
+// State
+import 'package:equatable/equatable.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+
+import '../api/api_auth_provider.dart';
+
+class AssetState extends Equatable {
+  final int idSelected;
+  final List<dynamic> data;
+  final List<dynamic> result;
+  final String keyword;
+  final int page;
+  final bool isLoading;
+
+  const AssetState({
+    this.idSelected = -1,
+    this.data = const [],
+    this.result = const [],
+    this.keyword = '',
+    this.page = 0,
+    this.isLoading = true,
+  });
+
+  AssetState copyWith({
+    int? idSelected,
+    List<dynamic>? data,
+    List<dynamic>? result,
+    String? keyword,
+    int? page,
+    bool? isLoading,
+  }) {
+    return AssetState(
+      idSelected: idSelected ?? this.idSelected,
+      data: data ?? this.data,
+      result: result ?? this.result,
+      keyword: keyword ?? this.keyword,
+      page: page ?? this.page,
+      isLoading: isLoading ?? this.isLoading,
+    );
+  }
+
+  @override
+  List<Object?> get props => [idSelected, data, result, keyword, page, isLoading];
+}
+
+// Cubit
+class AssetCubit extends Cubit<AssetState> {
+  AssetCubit() : super(const AssetState());
+
+  final ApiAuthProvider _apiAuthProvider = ApiAuthProvider();
+
+  void getData({String keyword = '', int page = 0}) async {
+    String filter = keyword == '' ? '{"f":["1","EQ","1"]}' : '{"or":[{"f":["name","LIKE","%$keyword%"]},{"f":["description","LIKE","%$keyword%"]}]}';
+    final params = {
+      "select": "id, code, name, description, image, status",
+      "sort": "name:ASC",
+      "filter": filter,
+      "size": "10",
+      "page": "$page"
+    };
+    final rawData = await _apiAuthProvider.getData('/api/assets/findData', params);
+    final data = rawData['_embedded']['assets'];
+
+    if (data.isEmpty && page != 0) return;
+    var finalData = page == 0 ? data : state.data + data;
+
+    emit(state.copyWith(data: finalData, keyword: keyword, page: page, isLoading: false));
+  }
+
+  void toggleSelection(int id) {
+    final newID = id;
+    final res = state.data.where((element) => element['id'] == newID).toList();
+
+    emit(state.copyWith(idSelected: newID, result: res));
+  }
+
+  void search(String keyword) {
+    getData(keyword: keyword, page: 0);
+
+    emit(state.copyWith(isLoading: true, data: []));
+  }
+
+  void loadNextPage() {
+    getData(keyword: state.keyword, page: state.page + 1);
+  }
+}

+ 101 - 0
lib/src/cubit/user_data_cubit.dart

@@ -0,0 +1,101 @@
+import 'package:equatable/equatable.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+
+import '../api/jwt_token.dart';
+
+class UserState extends Equatable {
+  final String serialNumber;
+  final Map<String, dynamic> user;
+  final Map<String, dynamic> profile;
+  final bool reset;
+  final bool dnd;
+  final bool servantDisplay;
+  final bool houseKeeping;
+  final String text;
+
+  const UserState({
+    this.serialNumber = '',
+    this.user = const {},
+    this.profile = const {},
+    this.reset = false,
+    this.dnd = false,
+    this.servantDisplay = false,
+    this.houseKeeping = false,
+    this.text = '',
+  });
+
+  UserState copyWith({
+    String? serialNumber,
+    Map<String, dynamic>? user,
+    Map<String, dynamic>? profile,
+    bool? reset,
+    bool? dnd,
+    bool? servantDisplay,
+    bool? houseKeeping,
+    String? text,
+  }) {
+    return UserState(
+      serialNumber: serialNumber ?? this.serialNumber,
+      user: user ?? this.user,
+      profile: profile ?? this.profile,
+      reset: reset ?? this.reset,
+      dnd: dnd ?? this.dnd,
+      servantDisplay: servantDisplay ?? this.servantDisplay,
+      houseKeeping: houseKeeping ?? this.houseKeeping,
+      text: text ?? this.text,
+    );
+  }
+
+  @override
+  List<Object?> get props => [serialNumber, user, profile, reset, dnd, servantDisplay, houseKeeping, text];
+}
+
+class UserCubit extends Cubit<UserState> {
+  UserCubit() : super(const UserState());
+  final JwtToken token = JwtToken();
+
+  void setSerialNumber(String value) {
+    emit(state.copyWith(serialNumber: value));
+  }
+
+  void setUser(Map<String, dynamic> value) {
+    emit(state.copyWith(user: value));
+  }
+
+  void setProfile(Map<String, dynamic> value) {
+    emit(state.copyWith(profile: value));
+  }
+
+  void setReset(bool value) {
+    emit(state.copyWith(reset: value));
+  }
+
+  void setDnd(bool value) {
+    emit(state.copyWith(dnd: value));
+  }
+
+  void setServantDisplay(bool value) {
+    emit(state.copyWith(servantDisplay: value));
+  }
+
+  void setHouseKeeping(bool value) {
+    emit(state.copyWith(houseKeeping: value));
+  }
+
+  void setText(String value) {
+    emit(state.copyWith(text: value));
+  }
+
+  void getUser() async {
+    try {
+      var res = await token.getUserData();
+      if (res != null) {
+        setUser(res);
+      } else {
+        setReset(true);
+      }
+    } catch (e) {
+      setReset(true);
+    }
+  }
+}

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

@@ -65,11 +65,7 @@ class _LoginPageState extends State<LoginPage> {
       companyName = lics['companyName']??'';
       serialNumber = lics['serialNumber']??'';
       companyLogo = lics['logo']??'';
-      if(await U.isCompatibleWith(VersionKey.multiBahasa)){
-        lang = lics['_validLang'] ?? [];
-      } else if(1698720817 <= lics['serverVersion']){
-        lang = lics['languages'] != null ? lics['languages'].split(',') : [];
-      }
+      lang = lics['_validLang'] ?? [];
       if(mounted) setState(() {});
     }
   }
@@ -318,18 +314,11 @@ class _LoginPageState extends State<LoginPage> {
       lg = lang.indexOf(code) - 1;
     }
     Map<String, dynamic> p;
-    if(U.newServerVersion(1754624839)){
-      p = {
-        'userId': tkn['user_name'].toString().replaceFirst('inf-', ""),
-        'language': 'ID',
-        '_language': lg
-      };
-    } else {
-      p = {
-        'userId': tkn['user_name'].toString().replaceFirst('inf-', ""),
-        'language': lg
-      };
-    }
+    p = {
+      'userId': tkn['user_name'].toString().replaceFirst('inf-', ""),
+      'language': 'ID',
+      '_language': lg
+    };
     try{
       var res = await apiAuthProvider.patchData('/api/informants/${tkn['userId']}', p);
       if (res != null) {
@@ -681,7 +670,7 @@ class _ForceChgPassPageState extends State<ForceChgPassPage> {
         }
       }
       else{
-        debugPrint("Mbuh");
+        // debugPrint("Mbuh");
         UIService.showError('cannotEmpty'.tr());
         // showError(context, 'cannotEmpty'.tr());
       }

+ 1 - 5
lib/src/layouts/auth/qr.dart

@@ -62,11 +62,7 @@ class _NewQrPageState extends State<NewQrPage> {
         setState(() {
           companyName = lics['companyName']??'';
           serialNumber = lics['serialNumber']??'';
-          if(U.newServerVersion(1754624839)){
-            lang = lics['_validLang'] ?? [];
-          } else if(1698720817 <= lics['serverVersion']){
-            lang = lics['languages'] != null ? lics['languages'].split(',') : [];
-          }
+          lang = lics['_validLang'] ?? [];
         });
       }
     }

+ 302 - 0
lib/src/layouts/components/rate_mission.dart

@@ -0,0 +1,302 @@
+import 'package:easy_localization/easy_localization.dart';
+import 'package:flutter/material.dart';
+import 'package:provider/provider.dart';
+import 'package:telnow_mobile_new/src/layouts/components/template.dart';
+
+import '../../api/api_auth_provider.dart';
+import '../../cubit/history_tab_cubit.dart';
+import '../../utils/U.dart';
+import '../../utils/extensions.dart';
+
+class RateMission extends StatefulWidget {
+  final BuildContext parentContext;
+  final Map<String, dynamic> list;
+  final List<dynamic> rating;
+  final int index;
+  final TabState state;
+
+  const RateMission({
+    super.key,
+    required this.parentContext,
+    required this.list,
+    required this.index,
+    required this.rating,
+    required this.state,
+  });
+
+  @override
+  State<RateMission> createState() => _RateMissionState();
+}
+
+class _RateMissionState extends State<RateMission> {
+  int tempRating = 0;
+  String description = '';
+  String ratingAspect = '';
+  late TextEditingController controllerOptOther;
+  late List aspectList;
+
+  @override
+  void initState() {
+    super.initState();
+    controllerOptOther = TextEditingController();
+
+    String locale = widget.parentContext.locale.toString();
+    aspectList = widget.list[
+                    '_ratingAspect${locale[0].toUpperCase()}${locale[1]}'] !=
+                null &&
+            widget.list['_ratingAspect${locale[0].toUpperCase()}${locale[1]}']
+                    .trim() !=
+                ''
+        ? widget.list['_ratingAspect${locale[0].toUpperCase()}${locale[1]}']
+            .split(';')
+        : [];
+
+    if (aspectList.isNotEmpty) {
+      aspectList.add('OTHER_OPTION');
+    } else {
+      ratingAspect = 'OTHER_OPTION';
+    }
+  }
+
+  @override
+  void dispose() {
+    controllerOptOther.dispose();
+    super.dispose();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return AlertDialog(
+      backgroundColor: Colors.transparent,
+      contentPadding: EdgeInsets.zero,
+      content: Container(
+        decoration: BoxDecoration(
+          color: secondaryColor,
+          borderRadius: BorderRadius.circular(25),
+        ),
+        child: Column(
+          mainAxisSize: MainAxisSize.min,
+          children: [
+            // Bagian header
+            Padding(
+              padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16),
+              child: Column(
+                crossAxisAlignment: CrossAxisAlignment.start,
+                children: [
+                  Text(widget.list[U.langColumn(context, 'requestSubject')],
+                      style: const TextStyle(
+                          color: Colors.white,
+                          fontSize: 14,
+                          fontWeight: FontWeight.w600)),
+                  const SizedBox(height: 4),
+                  Row(
+                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
+                    children: [
+                      Text('${'ticketNumber'.tr()}: ${widget.list['ticketNo']}',
+                          style: const TextStyle(
+                              color: Colors.white,
+                              fontSize: 12,
+                              fontWeight: FontWeight.w300)),
+                      Text(
+                          convertDate(widget.list['datetimeRequest'],
+                              context.locale.toString()),
+                          style: const TextStyle(
+                              color: Colors.white,
+                              fontSize: 12,
+                              fontWeight: FontWeight.w300)),
+                    ],
+                  ),
+                ],
+              ),
+            ),
+
+            // Bagian rating
+            Container(
+              padding: const EdgeInsets.fromLTRB(30, 15, 30, 15),
+              decoration: BoxDecoration(
+                  color: Colors.white, borderRadius: BorderRadius.circular(25)),
+              child: Column(
+                children: [
+                  Text('satisfactionAsk'.tr(),
+                      style: const TextStyle(fontSize: 16)),
+                  const SizedBox(height: 12),
+                  Row(
+                    mainAxisAlignment: MainAxisAlignment.center,
+                    children: List.generate(widget.rating.length, (i) {
+                      return Expanded(
+                        child: GestureDetector(
+                          child: Image(
+                            image: AssetImage(
+                                widget.rating[i]['image'].toString()),
+                            color: Colors.white.withValues(
+                                alpha: tempRating == widget.rating[i]['key']
+                                    ? 1
+                                    : 0.3),
+                            colorBlendMode: BlendMode.modulate,
+                          ),
+                          onTap: () {
+                            setState(() {
+                              tempRating = widget.rating[i]['key'] as int;
+                              description = widget.rating[i]['label'] as String;
+                            });
+                          },
+                        ).withHover(),
+                      );
+                    }),
+                  ),
+                  const SizedBox(height: 6),
+                  Text(description,
+                      style: const TextStyle(
+                          color: textColor,
+                          fontSize: 14,
+                          fontWeight: FontWeight.w300),
+                      textAlign: TextAlign.center),
+
+                  // Bagian aspek tambahan
+                  if (tempRating != 0) ...[
+                    const SizedBox(height: 20),
+                    separator(),
+                    const SizedBox(height: 20),
+                    Column(
+                      crossAxisAlignment: CrossAxisAlignment.start,
+                      children: [
+                        Text('${'whatMakesYou'.tr()} $description?',
+                            style: const TextStyle(fontSize: 16)),
+                        const SizedBox(height: 12),
+                        Wrap(
+                          runSpacing: 10,
+                          spacing: 10,
+                          children: List.generate(aspectList.length, (i) {
+                            return GestureDetector(
+                              child: Container(
+                                padding: const EdgeInsets.symmetric(
+                                    vertical: 5, horizontal: 10),
+                                decoration: BoxDecoration(
+                                  color: aspectList[i] == ratingAspect
+                                      ? primaryColor.withValues(alpha: 0.3)
+                                      : Colors.white,
+                                  border: Border.all(
+                                      color: aspectList[i] == ratingAspect
+                                          ? primaryColor
+                                          : textColor),
+                                  borderRadius: const BorderRadius.all(
+                                      Radius.circular(50)),
+                                ),
+                                child: Text(
+                                    aspectList[i] == 'OTHER_OPTION'
+                                        ? 'letMeWrite'.tr()
+                                        : aspectList[i],
+                                    style: const TextStyle(color: textColor)),
+                              ),
+                              onTap: () {
+                                setState(() {
+                                  ratingAspect = ratingAspect == aspectList[i]
+                                      ? ''
+                                      : aspectList[i];
+                                });
+                              },
+                            ).withHover();
+                          }),
+                        ),
+                        if (ratingAspect == 'OTHER_OPTION')
+                          TextFormField(
+                            maxLines: 1,
+                            maxLength: 50,
+                            autofocus: true,
+                            controller: controllerOptOther,
+                            style: const TextStyle(
+                                fontSize: 14, color: Colors.black),
+                            decoration: InputDecoration(
+                              counterText: '',
+                              hintText: 'writeHere'.tr(),
+                              hintStyle: TextStyle(
+                                  color: textColor.withValues(alpha: 0.5),
+                                  fontSize: 14),
+                              filled: true,
+                              fillColor: Colors.white,
+                              isDense: true,
+                              contentPadding: const EdgeInsets.all(13),
+                              prefixIcon: Padding(
+                                padding:
+                                    const EdgeInsets.only(left: 13, right: 13),
+                                child: U.iconsax('edit-2',
+                                    color: textColor, size: 22),
+                              ),
+                              enabledBorder: OutlineInputBorder(
+                                  borderRadius: BorderRadius.circular(12),
+                                  borderSide: BorderSide(
+                                      color: const Color(0xff262626)
+                                          .withValues(alpha: 0.5))),
+                              focusedBorder: OutlineInputBorder(
+                                  borderRadius: BorderRadius.circular(12),
+                                  borderSide:
+                                      const BorderSide(color: primaryColor)),
+                            ),
+                          ),
+                      ],
+                    ),
+                  ],
+
+                  // Tombol aksi
+                  const SizedBox(height: 20),
+                  Opacity(
+                    opacity: tempRating > 0 ? 1 : 0,
+                    child: Row(
+                      mainAxisAlignment: MainAxisAlignment.center,
+                      children: [
+                        Expanded(
+                          child: buttonTemplate(
+                            text: 'textCancel'.tr(),
+                            backgroundColor: Colors.black12,
+                            borderColor: Colors.black12,
+                            textColor: textColor,
+                            height: 40,
+                            action: () => navigateBack(context),
+                          ),
+                        ),
+                        const SizedBox(width: 20),
+                        Expanded(
+                          child: buttonTemplate(
+                            text: 'save_rating'.tr(),
+                            backgroundColor: primaryColor,
+                            borderColor: primaryColor,
+                            height: 40,
+                            action: () async {
+                              if (tempRating > 0) {
+                                var data = {
+                                  "ticketNo": widget.list['ticketNo'],
+                                  "rateSatisfy": tempRating,
+                                };
+                                if (ratingAspect != 'OTHER_OPTION') {
+                                  data['aspect'] = ratingAspect;
+                                } else if (controllerOptOther.text.isNotEmpty) {
+                                  data['aspect'] = controllerOptOther.text;
+                                }
+
+                                var res = await ApiAuthProvider().postData(
+                                    '/api/requestHistories/rateSatisfy',
+                                    null,
+                                    data);
+                                if (res != null) {
+                                  widget.parentContext
+                                      .read<DoneCubit>()
+                                      .setSatisfaction(
+                                          widget.index, tempRating);
+                                  navigateBack(context);
+                                }
+                              }
+                            },
+                          ),
+                        ),
+                      ],
+                    ),
+                  ),
+                ],
+              ),
+            ),
+          ],
+        ),
+      ),
+    );
+  }
+}

+ 7 - 1
lib/src/layouts/components/responsive.dart

@@ -1,5 +1,6 @@
 import 'package:auto_route/auto_route.dart';
 import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
 import 'package:telnow_mobile_new/src/layouts/mobile/app_mobile.dart';
 import 'package:telnow_mobile_new/src/layouts/web/app_web.dart';
 import 'package:telnow_mobile_new/src/layouts/web/menu_account.dart';
@@ -7,6 +8,8 @@ import 'package:telnow_mobile_new/src/layouts/web/menu_history.dart';
 import 'package:telnow_mobile_new/src/layouts/web/menu_home.dart';
 import 'package:telnow_mobile_new/src/utils/U.dart';
 
+import '../../cubit/history_menu_cubit.dart';
+
 @RoutePage()
 class AppResponsive extends StatelessWidget {
   const AppResponsive({super.key});
@@ -33,7 +36,10 @@ class HistoryResponsive extends StatelessWidget {
 
   @override
   Widget build(BuildContext context) {
-    return U.webView(context) ? WebHistoryPage() : MobMenuTemplate();
+    return BlocProvider(
+      create: (context) => MenuHistoryCubit(),
+      child: U.webView(context) ? WebHistoryPage() : MobMenuTemplate(),
+    );
   }
 }
 

+ 250 - 0
lib/src/layouts/components/widgets.dart

@@ -0,0 +1,250 @@
+import 'package:another_flushbar/flushbar.dart';
+import 'package:easy_localization/easy_localization.dart';
+import 'package:flutter/material.dart';
+import 'package:telnow_mobile_new/src/utils/U.dart';
+
+class WidgetComponent {
+
+  static Widget searchBar({String hintText = '', initialValue = '', required Function(dynamic) onSearch}){
+    TextEditingController searchKey = TextEditingController();
+    if(hintText == ''){
+      hintText = 'searchAsk'.tr();
+    }
+    if(initialValue != ''){
+      searchKey.text = initialValue;
+    }
+
+    return Padding(
+      padding: const EdgeInsets.fromLTRB(15, 0, 15, 0),
+      child: TextFormField(
+        controller: searchKey,
+        maxLines: 1,
+        style: TextStyle(fontSize: 14, color: Colors.black),
+        decoration: InputDecoration(
+          border: OutlineInputBorder(
+            borderRadius: BorderRadius.circular(32),
+            borderSide: BorderSide(width: 1.0, color: Colors.black45),
+          ),
+          prefixIcon: U.iconsax('search-normal-1', color: textColor),
+          hintText: hintText,
+          hintStyle: TextStyle(fontSize: 14, color: Colors.black54),
+          contentPadding: EdgeInsets.only(right: 15),
+          enabledBorder: OutlineInputBorder(
+            borderSide: BorderSide(width: 1.0, color: Colors.black45),
+            borderRadius: BorderRadius.circular(32),
+          ),
+          focusedBorder: OutlineInputBorder(
+              borderSide: BorderSide(width: 1.0, color: primaryColor),
+              borderRadius: BorderRadius.circular(32)
+          ),
+        ),
+        textInputAction: TextInputAction.done,
+        onFieldSubmitted: onSearch,
+      ),
+    );
+  }
+
+  static Widget boxSeparator(){
+    return Container(
+        height: 12,
+        width: double.infinity,
+        decoration: BoxDecoration(
+            color: Color(0xFFFAFAFA),
+            border: Border(
+                top: BorderSide(
+                    color: Color(0xFFDCDCDC),
+                    width: 1.0
+                )
+            )
+        )
+    );
+  }
+
+  static Widget buttonWithIcon(String label, IconData icon, VoidCallback onPressed){
+    return TextButton.icon(
+      style: TextButton.styleFrom(
+        shape: const StadiumBorder(),
+        backgroundColor: Color(0xFF00BFA6).withAlpha(15),
+        foregroundColor: Color(0xFF00BFA6),
+        padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 1),
+        minimumSize: const Size(0, 36),
+      ),
+      onPressed: onPressed,
+      icon: Icon(icon, color: Color(0xFF078C84), size: 16,),
+      label: Text(
+        label,
+        style: const TextStyle(color: Color(0xFF078C84), fontSize: 14, fontWeight: FontWeight.w500),
+      ),
+    );
+  }
+
+  static Widget button({required String label, textColor = Colors.white, color = primaryColor, border = primaryColor, action}) {
+    return SizedBox(
+        width: double.infinity,
+        height: 48,
+        child: TextButton(
+          style: ButtonStyle(
+            backgroundColor: WidgetStatePropertyAll(color),
+            shape: WidgetStatePropertyAll(
+              RoundedRectangleBorder(borderRadius: BorderRadius.circular(12), side: BorderSide(color: border))
+            )),
+          child: Text(label, style: TextStyle(color: textColor, fontSize: 16), textAlign: TextAlign.center),
+          onPressed: () => action(),
+        )
+    );
+  }
+
+  static Widget bottomButtonGroup(
+    {
+      required VoidCallback actionSave,
+      required VoidCallback actionCancel,
+      required String submitLabel,
+      required String cancelLabel,
+      Color submitColor = primaryColor,
+      Color submitBorder = primaryColor,
+      EdgeInsets padding = const EdgeInsets.symmetric(horizontal: 15, vertical: 15)
+    }){
+    return Container(
+      padding: padding,
+      width: double.infinity,
+      decoration: BoxDecoration(
+          color: Colors.white,
+          border: Border(
+              top: BorderSide(
+                  color: Color(0xFFDCDCDC),
+                  width: 1.0
+              )
+          )
+      ),
+      child: Row(
+        children: [
+          Expanded(
+              child: button(
+                label: cancelLabel,
+                color: Colors.white,
+                textColor: Color(0xffa5a5a5),
+                border: Color(0xffa5a5a5),
+                action: actionCancel,
+              )
+          ),
+          SizedBox(width: 10),
+          Expanded(
+              child: button(
+                color: submitColor,
+                border: submitBorder,
+                label: submitLabel,
+                action: actionSave,
+              )
+          )
+        ],
+      ),
+    );
+  }
+
+  static Widget lineSeparator(){
+    return Padding(padding: const EdgeInsets.symmetric(horizontal: 0.0, vertical: 5.0),
+        child: Divider(color: Color(0xffF5F5F5), thickness: 1.0,)
+    );
+  }
+
+  static Widget fieldCustom(String unit, TextEditingController controller, callBack){
+    return Container(
+      decoration: BoxDecoration(
+        border: Border.all(color: Color(0xffDCDCDC), width: 1),
+        borderRadius: BorderRadius.circular(5),
+      ),
+      height: 40,
+      child: Row(
+        mainAxisAlignment: MainAxisAlignment.spaceBetween,
+        crossAxisAlignment: CrossAxisAlignment.center,
+        children: [
+          Expanded(
+            child: TextField(
+              keyboardType: TextInputType.number,
+              decoration: InputDecoration(
+                hintText: '0',
+                hintStyle: TextStyle(color: Color(0xFFA3A3A3)),
+                border: InputBorder.none,
+                contentPadding: EdgeInsets.only(left: 10, bottom: 10),
+              ),
+              controller: controller,
+              onChanged: callBack,
+            ),
+          ),
+          Padding(
+            padding: const EdgeInsets.only(right: 8.0),
+            child: Text(unit, style: TextStyle(color: Color(0xFFA3A3A3)),),
+          ),
+        ],
+      ),
+    );
+  }
+
+  static Widget deleteButton(VoidCallback onTap){
+    return GestureDetector(
+      onTap: onTap,
+      child: Container(
+        width: 40,
+        height: 40,
+        decoration: BoxDecoration(
+          color: const Color(0xFFC9223B).withAlpha(20),
+          borderRadius: BorderRadius.circular(8),
+        ),
+        child: const Icon(
+          Icons.delete_sweep,
+          color: Color(0xFFC9223B),
+          size: 24,
+        ),
+      ),
+    );
+  }
+
+  static Widget popUpConfirm(context, String title, String message){
+    return AlertDialog(
+      title: Text(title, style: TextStyle(fontSize: 15)),
+      content: Text(message, style: TextStyle(fontSize: 15)),
+      actions: <Widget>[
+        TextButton(
+          child: Text('cancel'.tr()),
+          onPressed: () {
+            Navigator.pop(context);
+          },
+        ),
+        TextButton(
+          style: ButtonStyle(
+            foregroundColor: WidgetStateProperty.all<Color>(Colors.red),
+          ),
+          child: Text('confirm'.tr()),
+          onPressed: () {
+            Navigator.pop(context, {'remove': true});
+          },
+        ),
+      ],
+    );
+  }
+
+  static Widget loading(){
+    return Row(
+      children: [
+        SizedBox(width: 12, height:12, child: CircularProgressIndicator(strokeWidth: 0.6,)),
+        SizedBox(width: 10,),
+        Text('loading'.tr()),
+      ],
+    );
+  }
+
+  static Future<dynamic> alert(message, isError, context){
+    return Flushbar(
+      message: message,
+      icon: Icon(
+        Icons.info_outline,
+        size: 28.0,
+        color: isError?Colors.red:Colors.green,
+      ),
+      duration: Duration(seconds: 5),
+      flushbarPosition: FlushbarPosition.BOTTOM,
+      margin: EdgeInsets.all(8),
+      borderRadius: BorderRadius.circular(8),
+    ).show(context);
+  }
+}

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

@@ -41,11 +41,7 @@ class AccountFunction{
     }
     try{
       Map<String, dynamic> p;
-      if(await U.isCompatibleWith(VersionKey.multiBahasa)){
-        p = {'userId': user['userId'], 'language': 'ID', '_language': code.toUpperCase()};
-      } else {
-        p = {'userId': user['userId'], 'language': code.toUpperCase()};
-      }
+      p = {'userId': user['userId'], 'language': 'ID', '_language': code.toUpperCase()};
       var res = await apiAuthProvider.patchData('/api/informants/${user['id']}', p);
       if (res != null) {
         UIService.closeLoading();

+ 43 - 2
lib/src/layouts/functions/detail.dart

@@ -15,9 +15,37 @@ class DetailFunction{
   final JwtToken token = JwtToken();
   final translator = GoogleTranslator();
 
-  Future getMission(String locale, list) async{
+  Future getData(String ticketNo) async {
+    Map<String,dynamic> res = {};
+    try {
+      var newData = await apiAuthProvider.getData(
+          '/api/requestHistories/$ticketNo', null);
+
+      if (newData != null){
+        res = newData;
+      }
+    } catch(e) {
+      debugPrint(e.toString());
+    }
+    return res;
+  }
+
+
+  getBaseUrl() async {
+    try {
+      return '${U.decodeBase64Url(U.getBaseUrl()!)}${U.decodeBase64Url(
+          U.getAccessCode()!)}';
+    }catch(e) {
+      debugPrint(e.toString());
+    }
+    return '';
+  }
+
+  Future getMission(String locale, String ticketNo) async{
     var userData = await token.getUserData();
-    var data = list;
+    var data = await getData(ticketNo);
+    var baseUrl = await getBaseUrl();
+
     if (data['datetimeScheduled'] != null && data['datetimeScheduled'] != '' && data['noteFormat'] == 'DATE') {
       var date = data['datetimeScheduled'];
       data['datetimeScheduled'] = DateFormat('dd MMM yyyy HH:mm', 'id').format(DateTime.parse(date));
@@ -99,4 +127,17 @@ class DetailFunction{
       });
     }
   }
+
+  Future<dynamic> setAsset(String ticketNo, Map<String, dynamic> data) async {
+    try {
+      var res = await ApiAuthProvider().postData('/api/requestHistories/$ticketNo/asset/add', null, data);
+
+      if (res != null){
+        return res;
+      }
+    } catch(e){
+      debugPrint(e.toString());
+    }
+    return null;
+  }
 }

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

@@ -123,7 +123,7 @@ class HistoryFunction{
         }
 
         // If no internet connection and selected status is On going and filter button is Queued, display pending data.
-        if(historyModule.activeTab().name == "ongoing" && (selectedFilter == 'none' || selectedFilter == 'queue') && U.newServerVersion(1709864293) && !U.getInternetStatus()){
+        if(historyModule.activeTab().name == "ongoing" && (selectedFilter == 'none' || selectedFilter == 'queue') && !U.getInternetStatus()){
           List pendingList = sharedPreferencesManager.isKeyExists(SharedPreferencesManager.keyPendingData)!?jsonDecode(sharedPreferencesManager.getString(SharedPreferencesManager.keyPendingData)!):[];
           historyModule.setPendingData(pendingList);
         }

+ 3 - 16
lib/src/layouts/functions/home.dart

@@ -76,13 +76,7 @@ class HomeFunction{
 
         var profile = userModule.profile();
         if(profile['topMenu']['show'] != null && profile['topMenu']['show'] == true) {
-          if(U.newServerVersion(1709864293)){
-            getTopMenuNew();
-          }
-          else{
-            getTopMenu();
-            getReqGroup();
-          }
+          getTopMenuNew();
         }
         if(profile['specialOffer'] != null && profile['specialOffer']['show'] == true) getSpecialOffer(context);
         if(profile['frequentlyRequested'] != null && profile['frequentlyRequested']['show'] == true) getFrequentlyRequested();
@@ -303,7 +297,7 @@ class HomeFunction{
         }
 
         serviceModule.setMessage([]);
-        if (tempData.length > 0) {
+        if (tempData.isNotEmpty) {
           serviceModule.setMessage(tempData);
         }
       }
@@ -311,7 +305,6 @@ class HomeFunction{
       print(e.toString());
     }
 
-    if(await U.isCompatibleWith(VersionKey.multiBahasa) == false) return;
     try{
       String url = '/api/messages/search/myForum';
       var res = await apiAuthProvider.getData(url, null);
@@ -328,13 +321,7 @@ class HomeFunction{
   onRefresh(BuildContext context){
     var profile = userModule.profile();
     if(profile['topMenu']['show'] != null && profile['topMenu']['show'] == true) {
-      if(U.newServerVersion(1709864293)){
-        getTopMenuNew();
-      }
-      else{
-        getTopMenu();
-        getReqGroup();
-      }
+      getTopMenuNew();
     }
     if(profile['specialOffer'] != null && profile['specialOffer']['show'] == true) getSpecialOffer(context);
     if(profile['frequentlyRequested'] != null && profile['frequentlyRequested']['show'] == true) getFrequentlyRequested();

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

@@ -26,7 +26,7 @@ class MessageFunction{
   }
 
   getDataMessages(BuildContext context) async {
-    if(await U.isCompatibleWith(VersionKey.multiBahasa)) getDataForum(context);
+    getDataForum(context);
     String url = '/api/messages/search/myMessages';
     var val = await CacheMan.readData(url);
     if (val != null) {

+ 32 - 38
lib/src/layouts/functions/request.dart

@@ -44,24 +44,14 @@ class RequestFunction{
           search = ',{"f":["$subject","LIKE","%$_keyword%"]}';
         }
 
-        if(U.newServerVersion(1709864293)){
-          if(widget.groupCode != null){
-            url = '/api/requests/search/custom';
-            group = ',{"f":["${U.servantDisplay()?'servantGroupCode':'requestGroup.code'}","EQ","${widget.groupCode}"]}';
-            filter = '{"and":[{"or":[{"f":["scope","EQ","ALL"]},{"f":["scope","EQ","${widget.scope}"]}]}$search$group]}';
-          }
-          else{
-            url = '/api/requests/search/menu';
-            filter = '{"and":[{"or":[{"f":["scope","EQ","ALL"]},{"f":["scope","EQ","${widget.scope}"]}]}$search]}';
-          }
+        if(widget.groupCode != null){
+          url = '/api/requests/search/custom';
+          group = ',{"f":["${U.servantDisplay()?'servantGroupCode':'requestGroup.code'}","EQ","${widget.groupCode}"]}';
+          filter = '{"and":[{"or":[{"f":["scope","EQ","ALL"]},{"f":["scope","EQ","${widget.scope}"]}]}$search$group]}';
         }
         else{
-          if(widget.groupCode != null){
-            group = ',{"f":["${U.servantDisplay()?'servantGroupCode':'requestGroup.code'}","EQ","${widget.groupCode}"]}';
-          }
-
-          filter = '{"and":[{"or":[{"f":["scope","EQ","ALL"]},{"f":["scope","EQ","${widget.scope}"]}]}$search$group$tenant]}';
-          url = '/api/requests/search/custom';
+          url = '/api/requests/search/menu';
+          filter = '{"and":[{"or":[{"f":["scope","EQ","ALL"]},{"f":["scope","EQ","${widget.scope}"]}]}$search]}';
         }
 
         String key = '$url-$filter';
@@ -145,43 +135,48 @@ class RequestFunction{
     }
   }
 
-  sendRequest(BuildContext context, widget, controllerNote, controllerReferenceNumber, controllerLocation, controllerDateString, currentSliderValue) async{
+  sendRequest(BuildContext context, widget, controllerNote, controllerReferenceNumber, controllerLocation, controllerDateString, currentSliderValue, dynamic asset) async{
     // showLoading(context, lottie: kIsWeb && !isCanvasKit ? null : 'Paperplane.json', text: 'sendingRequest'.tr());
     UIService.showLoading(text: 'sendingRequest'.tr(), lottie: kIsWeb && !isCanvasKit ? null : 'Paperplane.json' );
-    var data;
+    Map<String, dynamic> data;
     data = {
       'note': controllerNote.text.trim() == '' ? '' : controllerNote.text.trim(),
       'parentTicket': controllerReferenceNumber.text.trim() == '' ? null : controllerReferenceNumber.text.trim(),
       'location': Provider.of<CreateSerModule>(context, listen: false).locationType() == 2 ? controllerLocation.text.trim() : Provider.of<CreateSerModule>(context, listen: false).defaultLocation(),
       'sendLater': Provider.of<CreateSerModule>(context, listen: false).sendLater(),
       'datetimeScheduled': controllerDateString.text.trim(),
-      'requestPriority': getPrioValue(currentSliderValue)
+      'requestPriority': getPrioValue(currentSliderValue),
+      'assetCode': asset
     };
 
-    if(!kIsWeb && U.newServerVersion(1709864293) && !U.getInternetStatus()){
+    if(!kIsWeb && !U.getInternetStatus()){
       closeLoading(context);
       sendRequestNoInternet(context, widget, controllerLocation, controllerNote, data: data, others: false);
-    }
-    else{
+    } else {
       List imageEncode = Provider.of<CreateSerModule>(context, listen: false).images();
       imageEncode.forEach((element) {
         element = base64Encode(element);
       });
       data['images'] = imageEncode;
 
-      var res = await apiAuthProvider.postData('/api/requestHistories/search/request/' + widget.request['type'] + '/' + widget.request['id'].toString() + '/' + widget.request['noteFormat'] + '/submit', null, data);
-      if (res != null) {
-        Future.delayed(Duration(seconds: 3), (){
-          closeLoading(context);
-          navigateTo(context, U.webView(context)?WebReqSuccessPage(user: widget.user, ticketNo: res['ticketNo'], fromSearch: widget.fromSearch):MobReqSuccessPage(user: widget.user, ticketNo: res['ticketNo'], fromSearch: widget.fromSearch)).then((res){
-            while (Navigator.canPop(context)){
-              Navigator.pop(context);
-            }
+      String url = '/api/requestHistories/search/request/${widget.request['type']}/${widget.request['id']}/${widget.request['noteFormat']}/submit';
+      try{
+        var res = await apiAuthProvider.postData(url, null, data);
+        if (res != null) {
+          Future.delayed(Duration(seconds: 3), (){
+            closeLoading(context);
+            navigateTo(context, U.webView(context) ? WebReqSuccessPage(user: widget.user, ticketNo: res['ticketNo'], fromSearch: widget.fromSearch) : MobReqSuccessPage(user: widget.user, ticketNo: res['ticketNo'], fromSearch: widget.fromSearch)).then((res){
+              while (Navigator.canPop(context)){
+                Navigator.pop(context);
+              }
+            });
           });
-        });
-      }
-      else{
-        closeLoading(context);
+        }
+        else{
+          closeLoading(context);
+        }
+      }catch(e){
+        UIService.showError(e.toString());
       }
     }
   }
@@ -212,11 +207,10 @@ class RequestFunction{
       }]
     };
 
-    if(!kIsWeb && U.newServerVersion(1709864293) && !U.getInternetStatus()){
+    if(!kIsWeb && !U.getInternetStatus()){
       closeLoading(context);
       sendRequestNoInternet(context, widget, controllerLocation, controllerNote, data: data, others: true);
-    }
-    else{
+    } else {
       List imageEncode = Provider.of<CreateSerModule>(context, listen: false).images();
       imageEncode.forEach((element) {
         element = base64Encode(element);
@@ -225,7 +219,7 @@ class RequestFunction{
 
       try{
         var res = await apiAuthProvider.postData('/api/receptionists/send/request', null, data);
-        print("res ##> $res");
+        // print("res ##> $res");
         if (res != null) {
           Future.delayed(Duration(seconds: 3), (){
             closeLoading(context);

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

@@ -22,7 +22,7 @@ class _MobBannerDetailPageState extends State<MobBannerDetailPage> {
 
   @override
   void initState() {
-    if(U.newServerVersion(1719194415) && widget.data['videoId'] != null){
+    if(widget.data['videoId'] != null){
       _controller = YoutubePlayerController.fromVideoId(
         videoId: widget.data['videoId'],
         autoPlay: true,
@@ -58,7 +58,7 @@ class _MobBannerDetailPageState extends State<MobBannerDetailPage> {
                 child: Column(
                   crossAxisAlignment: CrossAxisAlignment.start,
                   children: [
-                    U.newServerVersion(1719194415) && widget.data['videoId'] != null ? YoutubePlayer(
+                    widget.data['videoId'] != null ? YoutubePlayer(
                       controller: _controller,
                       aspectRatio: 16 / 9,
                     ) : widget.data['image'] != null ? ClipRRect(

+ 233 - 80
lib/src/layouts/mobile/history_detail.dart

@@ -1,17 +1,24 @@
 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_bloc/flutter_bloc.dart';
 import 'package:flutter_linkify/flutter_linkify.dart';
 import 'package:provider/provider.dart';
 import 'package:telnow_mobile_new/src/layouts/functions/detail.dart';
 import 'package:telnow_mobile_new/src/layouts/mobile/history_forum.dart';
 import 'package:telnow_mobile_new/src/layouts/components/template.dart';
+import 'package:telnow_mobile_new/src/layouts/mobile/pickup_asset.dart';
 import 'package:telnow_mobile_new/src/utils/U.dart';
 import 'package:telnow_mobile_new/src/utils/provider.dart';
 import 'package:telnow_mobile_new/src/utils/ui_service.dart';
 import 'package:timelines_plus/timelines_plus.dart';
 import 'package:url_launcher/url_launcher.dart';
 
+import '../../cubit/pickup_asset_cubit.dart';
+
+// import '../functions/history.dart';
+
 class MobHistoryDetailPage extends StatefulWidget {
   final int index;
   const MobHistoryDetailPage({required this.index, super.key});
@@ -22,10 +29,12 @@ class MobHistoryDetailPage extends StatefulWidget {
 
 class _MobHistoryDetailPageState extends State<MobHistoryDetailPage> {
   final DetailFunction detFunc = DetailFunction();
+  // final HistoryFunction historyFunction = HistoryFunction();
 
-  TextEditingController controllerNote = new TextEditingController()..text = '';
+  TextEditingController controllerNote = TextEditingController()..text = '';
   Map<String, dynamic> list = {};
   Map<String, dynamic> user = {};
+  Map<String, dynamic> asset = {};
 
   var rating = [
     {'key': 1, 'image': "assets/image/icon/very_dissatisfied.png", 'label': 'disatisfied'.tr()},
@@ -35,22 +44,39 @@ class _MobHistoryDetailPageState extends State<MobHistoryDetailPage> {
     {'key': 5, 'image': "assets/image/icon/very_satisfied.png", 'label': 'reallyPleased'.tr()},
   ];
   bool _timeLimit = false;
+  bool isActiveMission = false;
 
   @override
   void initState() {
-    getData();
     // TODO: implement initState
+    getData();
     super.initState();
   }
 
   getData() async{
-    var res = await detFunc.getMission(UIService.getLocale(), Provider.of<HistoryModule>(context, listen: false).dataRequests()[widget.index]);
-    setState((){
-      user = res['user'];
-      list = res['list'];
-    });
-    // print(list);
-    // print(list['_parentTicket']);
+    var res = await detFunc.getMission(UIService.getLocale(), Provider.of<HistoryModule>(context, listen: false).dataRequests()[widget.index]['ticketNo']);
+    var baseUrl = await detFunc.getBaseUrl();
+    var mobileImage = '';
+
+    user = res['user'];
+    list = res['list'];
+
+    if (list['_asset'] != null && list['_asset']['image'] != null){
+      mobileImage = baseUrl + list['_asset']['image'];
+    }
+
+    if (list['_asset'] != null){
+      asset['name'] = list['_asset']['name'];
+      asset['description'] = list['_asset']['description'];
+      asset['_mobileImage'] = mobileImage;
+    }
+
+    isActiveMission = list['currentState'] == 'DIPROSES' ||
+        list['currentState'] == 'DIANTRIKAN' ||
+        list['currentState'] == 'DIMULAI' ||
+        list['currentState'] == 'DISELESAIKAN';
+
+    setState((){});
   }
 
   @override
@@ -133,6 +159,10 @@ class _MobHistoryDetailPageState extends State<MobHistoryDetailPage> {
                                     child: Container(
                                         width: double.infinity,
                                         margin: EdgeInsets.only(top: 8),
+                                        decoration: BoxDecoration(
+                                          border: Border.all(color: Colors.deepOrange),
+                                          borderRadius: BorderRadius.all(Radius.circular(12)),
+                                        ),
                                         child: Center(
                                           child: Column(
                                             children: [
@@ -140,92 +170,216 @@ class _MobHistoryDetailPageState extends State<MobHistoryDetailPage> {
                                               Text('seeAttachment'.tr(), style: TextStyle(color: Colors.black45, fontSize: 12))
                                             ],
                                           ),
-                                        ),
-                                        decoration: BoxDecoration(
-                                          border: Border.all(color: Colors.deepOrange),
-                                          borderRadius: BorderRadius.all(Radius.circular(12)),
                                         )
                                     ),
                                     onTap: () => kIsWeb ? () async{
-                                      Uri _url = Uri.parse(list['_mobileResponseAttachment']);
-                                      await canLaunchUrl(_url) ? await launchUrl(_url) : print('Could not launch $_url');
+                                      Uri url = Uri.parse(list['_mobileResponseAttachment']);
+                                      await canLaunchUrl(url) ? await launchUrl(url) : print('Could not launch $url');
                                       // html.window.open(list['responseAttachment'], '_blank');
                                     } : detFunc.openAttachment(list)
                                 ):GestureDetector(
-                                    child: Container(
-                                      child:Image.network(list['_mobileResponseAttachment'], fit: BoxFit.cover, width: double.infinity, height: U.bodyWidth(context)/(kIsWeb?2.1:1.7), loadingBuilder:(BuildContext? context, Widget? child,ImageChunkEvent? loadingProgress) {
-                                        if (loadingProgress == null) return child!;
-                                        return Container(
-                                          height: U.bodyWidth(context)/(kIsWeb?2.1:1.7),
-                                          child: Center(
-                                            child: CircularProgressIndicator(
-                                              value: loadingProgress.expectedTotalBytes != null ? loadingProgress.cumulativeBytesLoaded / loadingProgress.expectedTotalBytes! : null,
-                                            ),
+                                    child: Image.network(list['_mobileResponseAttachment'], fit: BoxFit.cover, width: double.infinity, height: U.bodyWidth(context)/(kIsWeb?2.1:1.7), loadingBuilder:(BuildContext? context, Widget? child,ImageChunkEvent? loadingProgress) {
+                                      if (loadingProgress == null) return child!;
+                                      return SizedBox(
+                                        height: U.bodyWidth(context)/(kIsWeb?2.1:1.7),
+                                        child: Center(
+                                          child: CircularProgressIndicator(
+                                            value: loadingProgress.expectedTotalBytes != null ? loadingProgress.cumulativeBytesLoaded / loadingProgress.expectedTotalBytes! : null,
                                           ),
-                                        );
-                                      },
-                                      ),
+                                        ),
+                                      );
+                                    },
                                     ),
                                     onTap: ()=>navigateTo(context, PhotoPreview('image'.tr(), list['_mobileResponseAttachment'], true))
                                 ):Container()
                               ],
                             ) : attachment_new(list),
 
-                            list['autoResponse'] ? Container() : SizedBox(height: 16),
-                            list['autoResponse'] ? Container() : textVertical('note'.tr(), list['requestNote']!=''?list['requestNote']:'-'),
-                            list['autoResponse'] ? Container() : SizedBox(height: 16),
-                            list['autoResponse'] || list['datetimeScheduled'] == null || list['datetimeScheduled'] == '' ? Container() : Text("${"scheduleMessage".tr()} ${list['datetimeScheduled']}."),
-                            SizedBox(height: 24),
+                            if (!list['autoResponse']) ...[
+                              Padding(
+                                padding: EdgeInsetsGeometry.symmetric(vertical: 16),
+                                child: textVertical('note'.tr(), list['requestNote'] != '' ? list['requestNote'] : '-'),
+                              ),
+                              asset.isEmpty ? !isActiveMission ? SizedBox() : Row(
+                                mainAxisAlignment: MainAxisAlignment.spaceBetween,
+                                children: [
+                                  Column(
+                                    spacing: 6,
+                                    crossAxisAlignment: CrossAxisAlignment.start,
+                                    children: [
+                                      Text('asset'.tr(), style: TextStyle(fontSize: 15),),
+                                      Text('noAssetAdded'.tr(), style: TextStyle(fontSize: 12),)
+                                    ],
+                                  ),
+                                  ElevatedButton.icon(
+                                    style: ElevatedButton.styleFrom(
+                                      backgroundColor: primaryColor,
+                                      foregroundColor: Colors.white,
+                                      shape: RoundedRectangleBorder(
+                                        borderRadius: BorderRadius.circular(24),
+                                      ),
+                                      elevation: 0.0,
+                                      alignment: Alignment.center,
+                                    ),
+                                    onPressed: () async{
+                                      final assetPicked = await Navigator.push(
+                                        context, MaterialPageRoute(
+                                        builder: (_) => BlocProvider(
+                                          create: (_) => AssetCubit()..getData(),
+                                          child: PickupAsset(web: false,),
+                                        ),),
+                                      );
+
+                                      if (assetPicked != null) {
+                                        var data = {'assetCode': assetPicked[0]['code']};
+                                        var res = await detFunc.setAsset(list['ticketNo'], data);
+                                        if(res != null){
+                                          setState(() {
+                                            for (var item in assetPicked) {
+                                              asset['_mobileImage'] = item['_mobileImage']+'?bridge-cache=true';
+                                              asset['name'] = item['name'];
+                                              asset['description'] = item['description'];
+                                            }
+                                          });
+                                        }
+                                      }
+                                    },
+                                    icon: Icon(Icons.add, size: 18,),
+                                    label: Text('addLabel'.tr(),),
+                                  ),
+                                ],
+                              ) : Column(
+                                spacing: 6,
+                                crossAxisAlignment: CrossAxisAlignment.start,
+                                children: [
+                                  Text('asset'.tr(), style: TextStyle(fontSize: 15),),
+                                  Container(
+                                    decoration: BoxDecoration(
+                                      border: Border.all(color: Color(0xff262626).withValues(alpha: 0.1)),
+                                      borderRadius: BorderRadius.circular(12),
+                                    ),
+                                    child: Padding(
+                                      padding: EdgeInsets.symmetric(vertical: 0),
+                                      child: Row(
+                                        spacing: 12,
+                                        children: [
+                                          ClipRRect(
+                                            borderRadius: BorderRadius.circular(12.0),
+                                            child: Image.network(
+                                              asset['_mobileImage'],
+                                              width: 80,
+                                              height: 64,
+                                              fit: BoxFit.cover,
+                                              errorBuilder: (context, error, stackTrace) =>
+                                              const Icon(Icons.broken_image, size: 60, color: Colors.grey),
+                                              loadingBuilder: (context, child, loadingProgress) {
+                                                if (loadingProgress == null) return child;
+                                                return const SizedBox(
+                                                  width: 80,
+                                                  height: 64,
+                                                  child: Center(child: CupertinoActivityIndicator()),
+                                                );
+                                              },
+                                            ),
+                                          ),
+                                          Expanded(
+                                            child: Column(
+                                              crossAxisAlignment: CrossAxisAlignment.start,
+                                              spacing: 4,
+                                              children: [
+                                                Text(asset['name'],
+                                                  maxLines: 1,
+                                                  overflow: TextOverflow.ellipsis,
+                                                  style: TextStyle(
+                                                    color: textColor,
+                                                    fontSize: 14,
+                                                    fontWeight: FontWeight.w600,
+                                                  ),),
+                                                Text(asset['description'],
+                                                    maxLines: 2,
+                                                    overflow: TextOverflow.ellipsis,
+                                                    style: TextStyle(color: textColor, fontSize: 14)),
+                                              ],
+                                            ),
+                                          ),
+                                          GestureDetector(
+                                            onTap: () async {
+                                              var data = {'assetCode': null};
+                                              var res = await detFunc.setAsset(list['ticketNo'], data);
+                                              if(res != null) {
+                                                setState(() {
+                                                asset = {};
+                                              });
+                                              }
+                                            },
+                                            child: Padding(
+                                              padding: const EdgeInsets.all(12.0),
+                                              child: Icon(Icons.delete_rounded, size: 24, color: Colors.red.withValues(alpha: 0.85),),
+                                            ),
+                                          )
+                                        ],
+                                      ),
+                                    ),
+                                  ),
+                                ],
+                              ),
+                              SizedBox(height: 16,)
+                            ],
+                            if (list['datetimeScheduled'] != null && list['datetimeScheduled'] != '') Text("${"scheduleMessage".tr()} ${list['datetimeScheduled']}."),
+                            // SizedBox(height: 24),
                           ],
                         ),
                       ),
-                      U.newServerVersion(1741166029) && list['_parentTicket'] != null?separator():Container(),
-                      U.newServerVersion(1741166029) && list['_parentTicket'] != null?Padding(
-                        padding: EdgeInsets.symmetric(vertical: 12, horizontal: 16),
-                        child: Column(
-                          crossAxisAlignment: CrossAxisAlignment.start,
-                          children: [
-                            Text('requestReference'.tr(), style: TextStyle(color: textColor, fontWeight: FontWeight.w600)),
-                            SizedBox(height: 16),
-                            textHorizontal('ticketNumber'.tr(), list['_parentTicket']['ticketNo']),
-                            SizedBox(height: 16),
-                            divider(opacity: 0.05),
-                            SizedBox(height: 16),
-                            textHorizontal('subject'.tr(), list['_parentTicket'][U.langColumn(context, 'requestSubject')]),
-                            SizedBox(height: 16),
-                            textHorizontal('note'.tr(), list['_parentTicket']['requestNote']!=null && list['_parentTicket']['requestNote']!=''?list['_parentTicket']['requestNote']:'-'),
-                            SizedBox(height: 16),
-                            divider(opacity: 0.05),
-                            SizedBox(height: 16),
-                            list['_parentTicket']['_activeHoldRequest'] != null ? Row(
-                              mainAxisAlignment: MainAxisAlignment.spaceBetween,
-                              children: [
-                                Text('state'.tr(), style: TextStyle(fontSize: 14, color: textColor)),
-                                Row(
-                                  mainAxisAlignment: MainAxisAlignment.end,
-                                  children: [
-                                    Image(image: AssetImage('assets/image/general/Watch.png'), width: 20, height: 20),
-                                    SizedBox(width: 5),
-                                    Text('hold'.tr(), style: TextStyle(fontSize: 14, color: primaryColor)),
-                                  ],
-                                )
-                              ],
-                            ) : textHorizontal('state'.tr(), U.renderStatus(list['_parentTicket']['currentState'])),
-                            SizedBox(height: 16),
-                            textHorizontal('description'.tr(), list['_parentTicket'][U.langColumn(context, '_subjectDescription')]??''),
-                            SizedBox(height: 16),
-                          ],
+                      if (list['_parentTicket'] != null) ...[
+                        separator(),
+                        Padding(
+                          padding: EdgeInsets.symmetric(vertical: 12, horizontal: 16),
+                          child: Column(
+                            spacing: 16,
+                            crossAxisAlignment: CrossAxisAlignment.start,
+                            children: [
+                              Text('requestReference'.tr(), style: TextStyle(color: textColor, fontWeight: FontWeight.w600)),
+                              // SizedBox(height: 16),
+                              textHorizontal('ticketNumber'.tr(), list['_parentTicket']['ticketNo']),
+                              // SizedBox(height: 16),
+                              divider(opacity: 0.05),
+                              // SizedBox(height: 16),
+                              textHorizontal('subject'.tr(), list['_parentTicket'][U.langColumn(context, 'requestSubject')]),
+                              // SizedBox(height: 16),
+                              textHorizontal('note'.tr(), list['_parentTicket']['requestNote']!=null && list['_parentTicket']['requestNote']!=''?list['_parentTicket']['requestNote']:'-'),
+                              // SizedBox(height: 16),
+                              divider(opacity: 0.05),
+                              // SizedBox(height: 16),
+                              list['_parentTicket']['_activeHoldRequest'] != null ? Row(
+                                mainAxisAlignment: MainAxisAlignment.spaceBetween,
+                                children: [
+                                  Text('state'.tr(), style: TextStyle(fontSize: 14, color: textColor)),
+                                  Row(
+                                    mainAxisAlignment: MainAxisAlignment.end,
+                                    children: [
+                                      Image(image: AssetImage('assets/image/general/Watch.png'), width: 20, height: 20),
+                                      SizedBox(width: 5),
+                                      Text('hold'.tr(), style: TextStyle(fontSize: 14, color: primaryColor)),
+                                    ],
+                                  )
+                                ],
+                              ) : textHorizontal('state'.tr(), U.renderStatus(list['_parentTicket']['currentState'])),
+                              // SizedBox(height: 16),
+                              textHorizontal('description'.tr(), list['_parentTicket'][U.langColumn(context, '_subjectDescription')]??''),
+                              SizedBox(height: 16),
+                            ],
+                          ),
                         ),
-                      ):Container(),
+                      ],
                       separator(),
                       list['autoResponse'] ? Container() : Padding(
                         padding: EdgeInsets.symmetric(vertical: 12, horizontal: 16),
                         child: Column(
+                          spacing: 16,
                           crossAxisAlignment: CrossAxisAlignment.start,
                           children: [
                             Text('activity'.tr(), style: TextStyle(color: textColor, fontWeight: FontWeight.w600)),
-                            SizedBox(height: 16),
-
+                            // SizedBox(height: 16),
                             list['currentState'] != 'DIBATALKAN' && list['currentState'] != 'DIANTRIKAN' && list['currentState'] != 'DIPROSES' && list['_collaboratorDataFilter'].length > 0?Column(
                               crossAxisAlignment: CrossAxisAlignment.start,
                               children: [
@@ -250,12 +404,11 @@ class _MobHistoryDetailPageState extends State<MobHistoryDetailPage> {
                                 list['currentState'] == 'DIBATALKAN'?'canceledBy'.tr():'servant'.tr(),
                                 list['currentState'] == 'DIBATALKAN'?list['servantNameCancel']??'-':list['currentState'] != 'DIANTRIKAN' && list['currentState'] != 'DIPROSES'?list['servantNameStart']??'-':'-'
                             ),
-                            SizedBox(height: 16),
+                            // SizedBox(height: 16),
                             divider(opacity: 0.05),
-                            SizedBox(height: 16),
+                            // SizedBox(height: 16),
                             Text('timeline'.tr(), style: TextStyle(color: textColor, fontSize: 14)),
-                            SizedBox(height: 16),
-
+                            // SizedBox(height: 16),
                             Column(
                               crossAxisAlignment: CrossAxisAlignment.start,
                               children: [
@@ -274,15 +427,15 @@ class _MobHistoryDetailPageState extends State<MobHistoryDetailPage> {
                             !list['autoResponse'] && (list['currentState'] == 'TUNTAS' || list['currentState'] == 'DISELESAIKAN') ? Column(
                               crossAxisAlignment: CrossAxisAlignment.start,
                               children: [
-                                SizedBox(height: 16),
+                                // SizedBox(height: 16),
                                 divider(opacity: 0.05),
-                                U.newServerVersion(1716187681) && list['action'] != null && list['action'].trim() != '' ? Column(
+                                list['action'] != null && list['action'].trim() != '' ? Column(
                                   children: [
                                     SizedBox(height: 16),
                                     textHorizontal('action'.tr(), list['action'])
                                   ],
                                 ) : Container(),
-                                SizedBox(height: 16),
+                                // SizedBox(height: 16),
                                 Row(
                                   children: [
                                     Text('rate'.tr(), style: TextStyle(color: textColor, fontSize: 14)),
@@ -407,7 +560,7 @@ class _MobHistoryDetailPageState extends State<MobHistoryDetailPage> {
       }
     }
 
-    return imageList.length > 0 ? Column(
+    return imageList.isNotEmpty ? Column(
       crossAxisAlignment: CrossAxisAlignment.start,
       children: [
         Text('image'.tr(), style: TextStyle(color: textColor)),
@@ -445,7 +598,7 @@ class _MobHistoryDetailPageState extends State<MobHistoryDetailPage> {
       }
     }
 
-    return imageList.length > 0 ? Column(
+    return imageList.isNotEmpty ? Column(
       crossAxisAlignment: CrossAxisAlignment.start,
       children: [
         SizedBox(height: 16),

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

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

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

@@ -260,7 +260,7 @@ class _MobHistoryPageState extends State<MobHistoryPage> with TickerProviderStat
     return SingleChildScrollView(
       child: Column(
         children: [
-          U.newServerVersion(1709864293) && !U.getInternetStatus() ? Column(
+          !U.getInternetStatus() ? Column(
             children: List.generate(dataPending.length, (i) {
               return GestureDetector(
                 child: Container(
@@ -486,11 +486,11 @@ class _MobHistoryPageState extends State<MobHistoryPage> with TickerProviderStat
                                   child: Text('rateReq'.tr(), style: TextStyle(color: secondaryColor, fontSize: 14), overflow: TextOverflow.ellipsis),
                                 ),
                                 onTap: () {
-                                  U.newServerVersion(1716279633) ? navigateTo(context, MobHistoryRatingPage(historyModule.dataRequests()[i])).then((tempRating) {
+                                  navigateTo(context, MobHistoryRatingPage(historyModule.dataRequests()[i])).then((tempRating) {
                                     if(tempRating != null){
                                       historyModule.setSatisfaction(i, tempRating);
                                     }
-                                  }) : rateMission(context, historyModule.dataRequests()[i], i);
+                                  });
                                 },
                               ) : !historyFunction.isAutoResponse(dataRequest[i]) ? Row(
                                 children: [

+ 7 - 33
lib/src/layouts/mobile/menu_home.dart

@@ -65,10 +65,7 @@ class _MobHomePageState extends State<MobHomePage> with WidgetsBindingObserver {
   }
 
   checkCompatibility() async{
-    var isCompatible = await U.isCompatibleWith(VersionKey.multiBahasa);
-    if(isCompatible) {
-      homeFunc.getContactCenter(context);
-    }
+    homeFunc.getContactCenter(context);
   }
 
   @override
@@ -97,7 +94,7 @@ class _MobHomePageState extends State<MobHomePage> with WidgetsBindingObserver {
       showTopMenu = true;
     }
 
-    _localeIndex = U.newServerVersion(1754624839) ? U.getLangIndex(context.locale.toString()) : context.locale.toString();
+    _localeIndex = U.getLangIndex(context.locale.toString());
 
     return userModuleListen.user().isNotEmpty ? Scaffold(
       backgroundColor: backgroundColor,
@@ -117,27 +114,10 @@ class _MobHomePageState extends State<MobHomePage> with WidgetsBindingObserver {
                       Text(name, style: TextStyle(color: Colors.white, fontSize: 18), overflow: TextOverflow.ellipsis),
                       Row(
                         children: [
-                          //TODO: tambah pengecekan server version disini
-                          FutureBuilder<bool>(
-                            future: U.isCompatibleWith(VersionKey.multiBahasa),
-                            builder: (context, snapshot) {
-                              if (!snapshot.hasData) {
-                                return SizedBox();
-                              }
-
-                              final isCompatible = snapshot.data!;
-                              final hasContactCenter = serviceModule.contactCenter().toString().isNotEmpty;
-
-                              if (isCompatible && hasContactCenter) {
-                                return GestureDetector(
-                                    onTap: () => launchUrl(Uri.parse(serviceModule.contactCenter().toString())),
-                                    child: U.iconsax('phone-number', color: Colors.white, size: 26.0)
-                                );
-                              } else {
-                                return SizedBox(); // or nothing
-                              }
-                            },
-                          ),
+                          serviceModule.contactCenter().toString().isNotEmpty ? GestureDetector(
+                              onTap: () => launchUrl(Uri.parse(serviceModule.contactCenter().toString())),
+                              child: U.iconsax('phone-number', color: Colors.white, size: 26.0)
+                          ) : SizedBox.shrink(),
                           SizedBox(width: 8),
                           GestureDetector(
                             child: Stack(
@@ -268,13 +248,7 @@ class _MobHomePageState extends State<MobHomePage> with WidgetsBindingObserver {
                                         
                                                       var profile = userModule.profile();
                                                       if(profile['topMenu']['show'] != null && profile['topMenu']['show'] == true) {
-                                                        if(U.newServerVersion(1709864293)){
-                                                          homeFunc.getTopMenuNew();
-                                                        }
-                                                        else{
-                                                          homeFunc.getTopMenu();
-                                                          homeFunc.getReqGroup();
-                                                        }
+                                                        homeFunc.getTopMenuNew();
                                                       }
                                                       if(profile['specialOffer'] != null && profile['specialOffer']['show'] == true) homeFunc.getSpecialOffer(context);
                                                       if(profile['frequentlyRequested'] != null && profile['frequentlyRequested']['show'] == true) homeFunc.getFrequentlyRequested();

+ 0 - 1
lib/src/layouts/mobile/message_chat.dart

@@ -184,7 +184,6 @@ class _MobMessageChatPageState extends State<MobMessageChatPage> {
   }
 
   deleteCollection() {
-    debugPrint("popped");
     FirebaseFirestore.instance.collection("tmMessages").doc('messages').collection(idChat!).get().then((value) {
       for (DocumentSnapshot ds in value.docs) {
         ds.reference.delete();

+ 1 - 8
lib/src/layouts/mobile/message_list.dart

@@ -289,14 +289,7 @@ class _MobMessageListPageState extends State<MobMessageListPage> {
     return Scaffold(
       backgroundColor: Colors.white,
       appBar: appBarTemplate(context: context, title: 'message'.tr()),
-      body: FutureBuilder(future: U.isCompatibleWith(VersionKey.multiBahasa), builder: (context, snapshot){
-        if (!snapshot.hasData) {
-          return chat(); // or a loading spinner
-        } else {
-          return bodyForum();
-        }
-      }),
-      // U.isCompatibleWith(VersionKey.multiBahasa) ? bodyForum() : chat(),
+      body: bodyForum(),
       floatingActionButton: Provider.of<MessageModule>(context).user().isNotEmpty &&
           Provider.of<MessageModule>(context).user()['canSendMessage'] &&
           Provider.of<MessageModule>(context).activeTab() == 0 ? FloatingActionButton(

+ 219 - 0
lib/src/layouts/mobile/pickup_asset.dart

@@ -0,0 +1,219 @@
+import 'package:easy_localization/easy_localization.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+import 'package:equatable/equatable.dart';
+import 'package:telnow_mobile_new/src/layouts/components/template.dart';
+import 'package:telnow_mobile_new/src/utils/U.dart';
+
+import '../../api/api_auth_provider.dart';
+import '../../cubit/pickup_asset_cubit.dart';
+import '../../utils/extensions.dart';
+import '../components/widgets.dart';
+
+class PickupAsset extends StatefulWidget {
+  final bool web;
+  const PickupAsset({super.key, required this.web});
+
+  @override
+  State<PickupAsset> createState() => _PickupAssetState();
+}
+
+class _PickupAssetState extends State<PickupAsset> {
+  final ScrollController _scrollController = ScrollController();
+
+  @override
+  initState() {
+    super.initState();
+    _scrollController.addListener(_onScroll);
+  }
+  void _onScroll(){
+    if (_scrollController.position.pixels == _scrollController.position.maxScrollExtent) {
+      context.read<AssetCubit>().loadNextPage();
+    }
+  }
+  @override
+  dispose() {
+    _scrollController.dispose();
+    _scrollController.removeListener(_onScroll);
+    super.dispose();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    var result = [];
+    EdgeInsets padding = EdgeInsets.symmetric(vertical: 10.0);
+    if (widget.web) padding = EdgeInsets.symmetric(vertical: 25.0, horizontal: 100.0);
+
+    return Scaffold(
+      appBar: !widget.web ? appBarTemplate(context: context, title: "assetList".tr()) : PreferredSize(preferredSize: Size.fromHeight(0), child: AppBar(elevation: 0, backgroundColor: primaryColor)),
+      body: SafeArea(
+        child: Column(
+          children: [
+            if(widget.web) Container(
+              padding: EdgeInsets.symmetric(vertical: 25, horizontal: 100),
+              child: Row(
+                mainAxisAlignment: MainAxisAlignment.spaceBetween,
+                children: [
+                  Text('assetList'.tr(), style: TextStyle(color: textColor, fontSize: 17, fontWeight: FontWeight.w500), overflow: TextOverflow.ellipsis),
+                  GestureDetector(
+                    child: Text('buttonBack'.tr(), style: TextStyle(color: primaryColor, fontSize: 14)),
+                    onTap: ()=>navigateBack(context),
+                  ).withHover()
+                ],
+              ),
+            ),
+            divider(),
+            Expanded(
+              child: BlocBuilder<AssetCubit, AssetState>(
+                builder: (context, state) {
+                  result = state.result;
+                  return Column(
+                    children: [
+                      Container(
+                        color: Colors.white,
+                        child: Padding(
+                          padding: padding,
+                          child: WidgetComponent.searchBar(initialValue: state.keyword, onSearch: (val) {
+                            context.read<AssetCubit>().search(val);
+                          }),
+                        ),
+                      ),
+                      if(state.isLoading) Expanded(child: Center(child: const CircularProgressIndicator(),)),
+                      if(state.data.isEmpty && state.page == 0 && !state.isLoading) Center(child: Text('noDataText'.tr()),),
+                      if(state.data.isNotEmpty) Expanded(
+                        child: Padding(
+                          padding: padding,
+                          child: ListView.builder(
+                              controller: _scrollController,
+                              shrinkWrap: true,
+                              itemCount: state.data.length,
+                              itemBuilder: (context, index) {
+                                final asset = state.data[index];
+                                String imgUrl = asset['image'] != null ? asset['_mobileImage'] : '';
+
+                                return ImageRadioTile(
+                                  title: asset['name'],
+                                  description: asset['description'] ?? '-',
+                                  imageUrl: imgUrl,
+                                  isSelected: asset['id'] == state.idSelected,
+                                  onTap: () => context.read<AssetCubit>().toggleSelection(asset['id']),
+                                );
+                              }
+                          ),
+                        ),
+                      ),
+                    ],
+                  );
+                },
+              ),
+            ),
+            Container(
+              child: WidgetComponent.bottomButtonGroup(
+                actionSave: () {
+                  if(result.isNotEmpty) {
+                    Navigator.pop(context, result);
+                  } else {
+                    WidgetComponent.alert('noDataSelected'.tr(), true, context);
+                  }
+                },
+                actionCancel: () => Navigator.pop(context),
+                submitLabel: 'selectAsset'.tr(),
+                cancelLabel: 'textCancel'.tr(),
+                padding: widget.web ? EdgeInsets.symmetric(horizontal: 100, vertical: 15) : EdgeInsets.symmetric(horizontal: 15, vertical: 15)
+              ),
+            ),
+          ],
+        ),
+      ),
+    );
+  }
+}
+
+
+// Here ImageRadioTile
+class ImageRadioTile extends StatelessWidget {
+  final String title;
+  final String description;
+  final String imageUrl;
+  final bool isSelected;
+  final VoidCallback onTap;
+
+  const ImageRadioTile({
+    super.key,
+    required this.title,
+    required this.description,
+    required this.imageUrl,
+    required this.isSelected,
+    required this.onTap,
+  });
+
+  @override
+  Widget build(BuildContext context) {
+    return Column(
+      spacing: 5,
+      children: [
+        GestureDetector(
+          onTap: onTap,
+          child: Container(
+            decoration: BoxDecoration(
+                color: Colors.white
+            ),
+            padding: const EdgeInsets.all(15.0),
+            child: Row(
+              children: [
+                ClipRRect(
+                  borderRadius: BorderRadius.circular(12.0),
+                  child: imageUrl != '' ? Image.network(
+                    imageUrl,
+                    width: 80,
+                    height: 64,
+                    fit: BoxFit.cover,
+                    errorBuilder: (context, error, stackTrace) =>
+                    const Icon(Icons.broken_image, size: 60, color: Colors.grey),
+                    loadingBuilder: (context, child, loadingProgress) {
+                      if (loadingProgress == null) return child;
+                      return const SizedBox(
+                        width: 80,
+                        height: 64,
+                        child: Center(child: CupertinoActivityIndicator()),
+                      );
+                    },
+                  ) : const Icon(Icons.broken_image, size: 80, color: Colors.grey),
+                ),
+                const SizedBox(width: 12),
+                Expanded(
+                  child: Column(
+                    crossAxisAlignment: CrossAxisAlignment.start,
+                    children: [
+                      Text(
+                        title,
+                        style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w500),
+                        maxLines: 1,
+                        overflow: TextOverflow.ellipsis,
+                      ),
+                      const SizedBox(height: 4),
+                      Text(
+                        description,
+                        style: TextStyle(fontSize: 14, color: Colors.grey.shade600),
+                        maxLines: 2,
+                        overflow: TextOverflow.ellipsis,
+                      ),
+                    ],
+                  ),
+                ),
+                const SizedBox(width: 12),
+                Icon(
+                  isSelected ? Icons.radio_button_checked : Icons.radio_button_unchecked,
+                  color: isSelected ? primaryColor : Colors.grey.shade400,
+                ),
+              ],
+            ),
+          ),
+        ).withHover(),
+        SizedBox(height: 5,),
+        // WidgetComponent.boxSeparator(),
+      ],
+    );
+  }
+}

+ 160 - 46
lib/src/layouts/mobile/request_create.dart

@@ -1,7 +1,9 @@
 import 'package:cached_network_image/cached_network_image.dart';
 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_bloc/flutter_bloc.dart';
 import 'package:flutter_cache_manager/flutter_cache_manager.dart';
 import 'package:flutter_datetime_picker_plus/flutter_datetime_picker_plus.dart';
 import 'package:image_picker/image_picker.dart';
@@ -9,8 +11,10 @@ import 'package:loading_indicator/loading_indicator.dart';
 import 'package:provider/provider.dart';
 import 'package:searchfield/searchfield.dart';
 import 'package:telnow_mobile_new/src/injector/injector.dart';
+import 'package:telnow_mobile_new/src/layouts/components/widgets.dart';
 import 'package:telnow_mobile_new/src/layouts/functions/request.dart';
 import 'package:telnow_mobile_new/src/layouts/components/template.dart';
+import 'package:telnow_mobile_new/src/layouts/mobile/pickup_asset.dart';
 import 'package:telnow_mobile_new/src/storage/sharedpreferences/shared_preferences_manager.dart';
 import 'package:telnow_mobile_new/src/utils/U.dart';
 import 'package:telnow_mobile_new/src/utils/cache_manager.dart';
@@ -18,6 +22,8 @@ import 'package:telnow_mobile_new/src/utils/provider.dart';
 // import 'package:flutter_barcode_scanner/flutter_barcode_scanner.dart';
 import 'package:toggle_switch/toggle_switch.dart';
 
+import '../../cubit/pickup_asset_cubit.dart';
+
 class MobReqCreatePage extends StatefulWidget {
   final Map<String, dynamic> user;
   final Map<String, dynamic> request;
@@ -43,16 +49,17 @@ class _MobReqCreatePageState extends State<MobReqCreatePage> {
   final RequestFunction reqFunc = RequestFunction();
   final SharedPreferencesManager sharedPreferencesManager = locator<SharedPreferencesManager>();
 
-  TextEditingController controllerDate = new TextEditingController()..text = '';
-  TextEditingController controllerDateString = new TextEditingController()..text = '';
-  TextEditingController controllerNote = new TextEditingController()..text = '';
-  TextEditingController controllerLocation = new TextEditingController()..text = '';
-  TextEditingController controllerUserId = new TextEditingController()..text = '';
-  TextEditingController controllerReferenceNumber = new TextEditingController()..text = '';
+  TextEditingController controllerDate = TextEditingController()..text = '';
+  TextEditingController controllerDateString = TextEditingController()..text = '';
+  TextEditingController controllerNote = TextEditingController()..text = '';
+  TextEditingController controllerLocation = TextEditingController()..text = '';
+  TextEditingController controllerUserId = TextEditingController()..text = '';
+  TextEditingController controllerReferenceNumber = TextEditingController()..text = '';
 
   FocusNode focusNodeLocation = new FocusNode();
   double _currentSliderValue = 0;
   Color sliderColor = getColorScheme(0);
+  Map<String, dynamic> asset = {};
 
   @override
   void initState() {
@@ -80,6 +87,7 @@ class _MobReqCreatePageState extends State<MobReqCreatePage> {
   Widget build(BuildContext context) {
     final FocusNode inputIdFocusNode = FocusNode();
     var imageWidth = ((U.bodyWidth(context)-32)/5)-5;
+
     return Scaffold(
       backgroundColor: backgroundColor,
       appBar: appBarTemplate(context: context, exc: false, title: widget.request[U.langColumn(context, 'subject')]),
@@ -115,6 +123,10 @@ class _MobReqCreatePageState extends State<MobReqCreatePage> {
                       padding: EdgeInsets.all(16),
                       margin: EdgeInsets.only(bottom: 21),
                       width: double.infinity,
+                      decoration: BoxDecoration(
+                          border: Border.all(color: textColor.withValues(alpha: 0.15)),
+                          borderRadius: BorderRadius.all(Radius.circular(12))
+                      ),
                       child: Column(
                         crossAxisAlignment: CrossAxisAlignment.start,
                         children: [
@@ -123,10 +135,6 @@ class _MobReqCreatePageState extends State<MobReqCreatePage> {
                           Text(widget.request[U.langColumn(context, 'subjectDescription')], style: TextStyle(color: textColor, fontSize: 13, fontWeight: FontWeight.w300), maxLines: 3, overflow: TextOverflow.ellipsis)
                         ],
                       ),
-                      decoration: BoxDecoration(
-                          border: Border.all(color: textColor.withValues(alpha: 0.15)),
-                          borderRadius: BorderRadius.all(Radius.circular(12))
-                      ),
                     ),
 
                     widget.request['autoResponse'] ? infoContainer('autoResponseText'.tr()) : Column(
@@ -138,6 +146,11 @@ class _MobReqCreatePageState extends State<MobReqCreatePage> {
                           child: Container(
                             margin: EdgeInsets.only(top: 8),
                             padding: EdgeInsets.symmetric(vertical: 12, horizontal: 15),
+                            decoration: BoxDecoration(
+                                color: Provider.of<CreateSerModule>(context).locationType()==1?primaryColor.withValues(alpha: 0.15):Colors.white,
+                                border: Border.all(color: Provider.of<CreateSerModule>(context).locationType()==1?primaryColor:textColor.withValues(alpha: 0.15)),
+                                borderRadius: BorderRadius.only(topLeft: Radius.circular(12), topRight: Radius.circular(12))
+                            ),
                             child: Row(
                               crossAxisAlignment: CrossAxisAlignment.center,
                               children: [
@@ -153,11 +166,6 @@ class _MobReqCreatePageState extends State<MobReqCreatePage> {
                                 ))
                               ],
                             ),
-                            decoration: BoxDecoration(
-                                color: Provider.of<CreateSerModule>(context).locationType()==1?primaryColor.withValues(alpha: 0.15):Colors.white,
-                                border: Border.all(color: Provider.of<CreateSerModule>(context).locationType()==1?primaryColor:textColor.withValues(alpha: 0.15)),
-                                borderRadius: BorderRadius.only(topLeft: Radius.circular(12), topRight: Radius.circular(12))
-                            ),
                           ),
                           onTap: (){
                             if(!widget.request['scanToRequest']) Provider.of<CreateSerModule>(context, listen: false).setLocationType(1);
@@ -248,6 +256,7 @@ class _MobReqCreatePageState extends State<MobReqCreatePage> {
                               Row(
                                 children: [
                                   Container(
+                                    decoration: BoxDecoration(color: Provider.of<CreateSerModule>(context).others() == 0 ? disabledColor : primaryColor, borderRadius: BorderRadius.all(Radius.circular(20))),
                                     child: ToggleSwitch(
                                       cornerRadius: 20,
                                       minWidth: 20,
@@ -267,7 +276,6 @@ class _MobReqCreatePageState extends State<MobReqCreatePage> {
                                         Provider.of<CreateSerModule>(context, listen: false).setOthers(index);
                                       },
                                     ),
-                                    decoration: BoxDecoration(color: Provider.of<CreateSerModule>(context).others() == 0 ? disabledColor : primaryColor, borderRadius: BorderRadius.all(Radius.circular(20))),
                                   ),
                                   SizedBox(width: 8),
                                   Expanded(child: Text(Provider.of<CreateSerModule>(context).others() == 0 ? 'reqForMySelf'.tr() : 'reqForOthers'.tr(), style: TextStyle(color: textColor, fontSize: 12), maxLines: 2, overflow: TextOverflow.ellipsis))
@@ -344,7 +352,7 @@ class _MobReqCreatePageState extends State<MobReqCreatePage> {
                           children: [
                             Text('addImage'.tr(), style: TextStyle(color: textColor, fontWeight: FontWeight.w600)),
                             SizedBox(height: 8),
-                            Provider.of<CreateSerModule>(context).images().length > 0 ? Row(
+                            Provider.of<CreateSerModule>(context).images().isNotEmpty ? Row(
                               children: [
                                 Row(
                                   children: List.generate(Provider.of<CreateSerModule>(context).images().length, (i){
@@ -352,21 +360,21 @@ class _MobReqCreatePageState extends State<MobReqCreatePage> {
                                         child: Container(
                                           width: imageWidth, height: imageWidth, alignment: Alignment.topRight,
                                           margin: EdgeInsets.only(right: i == 4 ? 0 : 6),
+                                          decoration: BoxDecoration(
+                                              color: Colors.black12, borderRadius: BorderRadius.all(Radius.circular(5)), border: Border.all(color: Colors.black26, width: 0.5),
+                                              image: DecorationImage(image: MemoryImage(Provider.of<CreateSerModule>(context).images()[i]), fit: BoxFit.cover)
+                                          ),
                                           child: Transform.translate(
                                             offset: Offset(3, -3),
                                             child: GestureDetector(
                                               child: Container(
                                                 padding: EdgeInsets.all(3),
-                                                child: Icon(Icons.close_rounded, color: Colors.white, size: 18),
                                                 decoration: BoxDecoration(color: Colors.black54, border: Border.all(color: Colors.white, width: 2), borderRadius: BorderRadius.all(Radius.circular(50))),
+                                                child: Icon(Icons.close_rounded, color: Colors.white, size: 18),
                                               ),
                                               onTap: ()=>Provider.of<CreateSerModule>(context, listen: false).removeImages(i),
                                             ),
                                           ),
-                                          decoration: BoxDecoration(
-                                              color: Colors.black12, borderRadius: BorderRadius.all(Radius.circular(5)), border: Border.all(color: Colors.black26, width: 0.5),
-                                              image: DecorationImage(image: MemoryImage(Provider.of<CreateSerModule>(context).images()[i]), fit: BoxFit.cover)
-                                          ),
                                         ),
                                         onTap: ()=>navigateTo(context, PhotoPreviewGallery(title: 'image'.tr(), imageList: Provider.of<CreateSerModule>(context, listen: false).images(), startIndex: i, isUrl: false))
                                     );
@@ -375,6 +383,7 @@ class _MobReqCreatePageState extends State<MobReqCreatePage> {
                                 Provider.of<CreateSerModule>(context).images().length < 5 ? GestureDetector(
                                   child: Container(
                                     width: imageWidth, height: imageWidth, alignment: Alignment.center,
+                                    decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.all(Radius.circular(5)), border: Border.all(color: Colors.black26, width: 2)),
                                     child:  Provider.of<CreateSerModule>(context).setLoadingEffect() ? SizedBox(
                                       height: 30,
                                       child: LoadingIndicator(
@@ -385,7 +394,6 @@ class _MobReqCreatePageState extends State<MobReqCreatePage> {
                                         pathBackgroundColor: Colors.black,
                                       ),
                                     ) : Icon(Icons.add_rounded, color: Colors.black26, size: 40),
-                                    decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.all(Radius.circular(5)), border: Border.all(color: Colors.black26, width: 2)),
                                   ),
                                   onTap: ()=>pickupImageNew(),
                                 ) : Container(),
@@ -404,7 +412,7 @@ class _MobReqCreatePageState extends State<MobReqCreatePage> {
                               ),
                               onTap: ()=>pickupImageNew(),
                             ),
-                            U.newServerVersion(1736473802) ? Column(
+                            Column(
                               crossAxisAlignment: CrossAxisAlignment.start,
                               children: [
                                 SizedBox(height: 32),
@@ -465,8 +473,8 @@ class _MobReqCreatePageState extends State<MobReqCreatePage> {
                                     )
                                 )
                               ],
-                            ) : SizedBox(),
-                            U.newServerVersion(1741166029) ? Column(
+                            ),
+                            Column(
                               crossAxisAlignment: CrossAxisAlignment.start,
                               children: [
                                 SizedBox(height: 32),
@@ -493,7 +501,113 @@ class _MobReqCreatePageState extends State<MobReqCreatePage> {
                                   ),
                                 )
                               ],
-                            ) : SizedBox(),
+                            ),
+                            Column(
+                              crossAxisAlignment: CrossAxisAlignment.start,
+                              children: [
+                                SizedBox(height: 32),
+                                Text(asset.isEmpty ? 'addAsset'.tr() : 'asset'.tr(), style: TextStyle(color: textColor, fontWeight: FontWeight.w600)),
+                                SizedBox(height: 8),
+                                asset.isEmpty ? GestureDetector(
+                                  onTap: () async {
+                                    final res = await Navigator.push(
+                                      context, MaterialPageRoute(
+                                        builder: (_) => BlocProvider(
+                                          create: (_) => AssetCubit()..getData(),
+                                          child: PickupAsset(web: false),
+                                        ),
+                                      ),
+                                    );
+
+                                    if(res != null) {
+                                      setState(() {
+                                        for (var item in res) {
+                                          asset['_mobileImage'] = item['_mobileImage']+'?bridge-cache=true';
+                                          asset['name'] = item['name'];
+                                          asset['code'] = item['code'];
+                                          asset['description'] = item['description'];
+                                        }
+                                      });
+                                    }
+                                  },
+                                  child: Container(
+                                    padding: EdgeInsets.symmetric(horizontal: 13, vertical: 12),
+                                    decoration: BoxDecoration(
+                                      borderRadius: BorderRadius.circular(12),
+                                      border: Border.all(color: Color(0xff262626).withValues(alpha: 0.5))
+                                    ),
+                                    child: Row(
+                                      spacing: 12,
+                                      children: [
+                                        Icon(Icons.widgets_outlined,),
+                                        Text("selectAsset".tr(), style: TextStyle(color: Color(0xff262626).withValues(alpha: 0.5)),),
+                                      ],
+                                    ),
+                                  ),
+                                ) : Container(
+                                  decoration: BoxDecoration(
+                                    border: Border.all(color: Color(0xff262626).withValues(alpha: 0.5)),
+                                    borderRadius: BorderRadius.circular(12),
+                                  ),
+                                  child: Padding(
+                                    padding: EdgeInsets.symmetric(vertical: 0),
+                                    child: Row(
+                                      spacing: 12,
+                                      children: [
+                                        ClipRRect(
+                                          borderRadius: BorderRadius.circular(12.0),
+                                          child: Image.network(
+                                            asset['_mobileImage'],
+                                            width: 80,
+                                            height: 64,
+                                            fit: BoxFit.cover,
+                                            errorBuilder: (context, error, stackTrace) =>
+                                            const Icon(Icons.broken_image, size: 60, color: Colors.grey),
+                                            loadingBuilder: (context, child, loadingProgress) {
+                                              if (loadingProgress == null) return child;
+                                              return const SizedBox(
+                                                width: 80,
+                                                height: 64,
+                                                child: Center(child: CupertinoActivityIndicator()),
+                                              );
+                                            },
+                                          ),
+                                        ),
+                                        Expanded(
+                                          child: Column(
+                                            crossAxisAlignment: CrossAxisAlignment.start,
+                                            spacing: 4,
+                                            children: [
+                                              Text(asset['name'],
+                                                maxLines: 1,
+                                                overflow: TextOverflow.ellipsis,
+                                                style: TextStyle(
+                                                  color: textColor,
+                                                  fontSize: 14,
+                                                  fontWeight: FontWeight.w600,
+                                                ),),
+                                              Text(asset['description'],
+                                                maxLines: 2,
+                                                overflow: TextOverflow.ellipsis,
+                                                style: TextStyle(color: textColor, fontSize: 14)),
+                                            ],
+                                          ),
+                                        ),
+                                        GestureDetector(
+                                          onTap: () => setState(() {
+                                            asset = {};
+                                          }),
+                                          child: Padding(
+                                            padding: const EdgeInsets.all(12.0),
+                                            child: Icon(Icons.delete_rounded, size: 24, color: Colors.red.withValues(alpha: 0.85),),
+                                          ),
+                                        )
+                                      ],
+                                    ),
+                                  ),
+                                )
+                              ],
+                            ),
                           ],
                         ),
                       ],
@@ -556,7 +670,7 @@ class _MobReqCreatePageState extends State<MobReqCreatePage> {
                         } else if (controllerDateString.text.trim().isNotEmpty && widget.request['noteFormat'] == 'DATE'){
                           dialogSendLater();
                         } else {
-                          reqFunc.sendRequest(context, widget, controllerNote, controllerReferenceNumber, controllerLocation, controllerDateString, _currentSliderValue);
+                          reqFunc.sendRequest(context, widget, controllerNote, controllerReferenceNumber, controllerLocation, controllerDateString, _currentSliderValue, asset['code']);
                         }
                       } else {
                         showError(context, 'lengthMax'.tr());
@@ -592,14 +706,6 @@ class _MobReqCreatePageState extends State<MobReqCreatePage> {
                   child: GestureDetector(
                     child: Container(
                       padding: EdgeInsets.symmetric(vertical: 20),
-                      child: Column(
-                        mainAxisSize: MainAxisSize.min,
-                        children: [
-                          U.iconsax('timer-start', color: Colors.white, size: 30),
-                          SizedBox(height: 9),
-                          Text('scheduled'.tr(), style: TextStyle(color: Colors.white, fontSize: 14))
-                        ],
-                      ),
                       decoration: BoxDecoration(
                           borderRadius: BorderRadius.all(Radius.circular(12)),
                           gradient: LinearGradient(
@@ -609,11 +715,19 @@ class _MobReqCreatePageState extends State<MobReqCreatePage> {
                               ]
                           )
                       ),
+                      child: Column(
+                        mainAxisSize: MainAxisSize.min,
+                        children: [
+                          U.iconsax('timer-start', color: Colors.white, size: 30),
+                          SizedBox(height: 9),
+                          Text('scheduled'.tr(), style: TextStyle(color: Colors.white, fontSize: 14))
+                        ],
+                      ),
                     ),
                     onTap: (){
                       navigateBack(contexts);
                       Provider.of<CreateSerModule>(context, listen: false).setSendLater(true);
-                      reqFunc.sendRequest(context, widget, controllerNote, controllerReferenceNumber, controllerLocation, controllerDateString, _currentSliderValue);
+                      reqFunc.sendRequest(context, widget, controllerNote, controllerReferenceNumber, controllerLocation, controllerDateString, _currentSliderValue, asset['code']);
                     },
                   ),
                 ),
@@ -622,14 +736,6 @@ class _MobReqCreatePageState extends State<MobReqCreatePage> {
                   child: GestureDetector(
                     child: Container(
                       padding: EdgeInsets.symmetric(vertical: 20),
-                      child: Column(
-                        mainAxisSize: MainAxisSize.min,
-                        children: [
-                          U.iconsax('star-1', color: Colors.white, size: 30),
-                          SizedBox(height: 9),
-                          Text('sendNow'.tr(), style: TextStyle(color: Colors.white, fontSize: 14))
-                        ],
-                      ),
                       decoration: BoxDecoration(
                           borderRadius: BorderRadius.all(Radius.circular(12)),
                           gradient: LinearGradient(
@@ -639,10 +745,18 @@ class _MobReqCreatePageState extends State<MobReqCreatePage> {
                               ]
                           )
                       ),
+                      child: Column(
+                        mainAxisSize: MainAxisSize.min,
+                        children: [
+                          U.iconsax('star-1', color: Colors.white, size: 30),
+                          SizedBox(height: 9),
+                          Text('sendNow'.tr(), style: TextStyle(color: Colors.white, fontSize: 14))
+                        ],
+                      ),
                     ),
                     onTap: (){
                       navigateBack(contexts);
-                      reqFunc.sendRequest(context, widget, controllerNote, controllerReferenceNumber, controllerLocation, controllerDateString, _currentSliderValue);
+                      reqFunc.sendRequest(context, widget, controllerNote, controllerReferenceNumber, controllerLocation, controllerDateString, _currentSliderValue, asset['code']);
                     },
                   ),
                 ),

+ 2 - 2
lib/src/layouts/web/banner_detail.dart

@@ -22,7 +22,7 @@ class _WebBannerDetailPageState extends State<WebBannerDetailPage> {
   @override
   void initState() {
     if(mounted){
-      if(U.newServerVersion(1719194415) && widget.data['videoId'] != null){
+      if(widget.data['videoId'] != null){
         _controller = YoutubePlayerController.fromVideoId(
           videoId: widget.data['videoId'],
           autoPlay: true,
@@ -69,7 +69,7 @@ class _WebBannerDetailPageState extends State<WebBannerDetailPage> {
               child: Column(
                 crossAxisAlignment: CrossAxisAlignment.start,
                 children: [
-                  U.newServerVersion(1719194415) && widget.data['videoId'] != null ? YoutubePlayer(
+                  widget.data['videoId'] != null ? YoutubePlayer(
                     controller: _controller,
                     aspectRatio: 16 / 9,
                   ) : widget.data['image'] != null ? ClipRRect(

File diff suppressed because it is too large
+ 901 - 58
lib/src/layouts/web/history_detail.dart


+ 157 - 0
lib/src/layouts/web/menu-history/build_filter.dart

@@ -0,0 +1,157 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+
+import '../../../cubit/history_menu_cubit.dart';
+import '../../../cubit/history_tab_cubit.dart';
+import '../../../utils/U.dart';
+import '../../../utils/extensions.dart';
+
+class BuildFilter extends StatelessWidget {
+  const BuildFilter({super.key});
+
+  @override
+  Widget build(BuildContext context) {
+    return BlocBuilder<MenuHistoryCubit, MenuHistoryState>(
+        builder: (context, state) {
+          HistoryTab tab = state.activeTab;
+          List currentFilters = tab.filters;
+
+          return SingleChildScrollView(
+            scrollDirection: Axis.horizontal,
+            child: tab == HistoryTab.ongoing
+                ? _ongoingFilter(currentFilters)
+                : _doneFilter(currentFilters),
+          );
+        }
+    );
+  }
+
+  _ongoingFilter(List<dynamic> currentFilters) {
+    return BlocBuilder<OngoingCubit, TabState>(
+      builder: (context, state) {
+        return Row(
+          children: List.generate(currentFilters.length, (i) {
+            return GestureDetector(
+              child: _filterItem(state, currentFilters, i),
+              onTap: () {
+                String currentFilter = '';
+
+                if (state.filter != currentFilters[i]['value']) {
+                  currentFilter = currentFilters[i]['value'];
+                } else {
+                  currentFilter = 'none';
+                }
+                context.read<OngoingCubit>().setFilter(currentFilter);
+                // context.read<OngoingCubit>().loadOngoing();
+              },
+            ).withHover();
+          }),
+        );
+      }
+    );
+  }
+
+  _doneFilter(List<dynamic> currentFilters) {
+    return BlocBuilder<DoneCubit, TabState>(
+      builder: (context, state) {
+        return Row(
+          children: List.generate(currentFilters.length, (i) {
+            return GestureDetector(
+              child: _filterItem(state, currentFilters, i),
+              onTap: () {
+                String currentFilter = '';
+
+                if (state.filter != currentFilters[i]['value']) {
+                  currentFilter = currentFilters[i]['value'];
+                } else {
+                  currentFilter = 'none';
+                }
+                context.read<DoneCubit>().setFilter(currentFilter);
+                // context.read<DoneCubit>().loadDone();
+              },
+            ).withHover();
+          }),
+        );
+      }
+    );
+  }
+
+  Widget? _filterItem(TabState state, List<dynamic> currentFilters, int i) {
+    return Container(
+      margin: EdgeInsets.only(left: 16),
+      padding: EdgeInsets.symmetric(vertical: 8, horizontal: 16),
+      decoration: BoxDecoration(
+          color: state.filter == currentFilters[i]['value']
+              ? primaryColor
+              : Color(0xffF2F8F7),
+          border: Border.all(
+              color: state.filter == currentFilters[i]['value']
+                  ? primaryColor
+                  : Color(0xffBEC1C1)),
+          borderRadius: BorderRadius.all(Radius.circular(50))),
+      child: Text(currentFilters[i]['title'], style: TextStyle(
+          color: state.filter == currentFilters[i]['value'] ? Colors
+              .white : textColor, fontSize: 16)),
+    );
+  }
+}
+
+class FilterItem extends StatelessWidget {
+  final TabState state;
+  final List<dynamic> currentFilters;
+  final int i;
+
+  const FilterItem({super.key, required this.state, required this.currentFilters, required this.i});
+
+  @override
+  Widget build(BuildContext context) {
+    return Container(
+      margin: EdgeInsets.only(left: 16),
+      padding: EdgeInsets.symmetric(vertical: 8, horizontal: 16),
+      decoration: BoxDecoration(
+          color: state.filter == currentFilters[i]['value']
+              ? primaryColor
+              : Color(0xffF2F8F7),
+          border: Border.all(
+              color: state.filter == currentFilters[i]['value']
+                  ? primaryColor
+                  : Color(0xffBEC1C1)),
+          borderRadius: BorderRadius.all(Radius.circular(50))),
+      child: Text(currentFilters[i]['title'], style: TextStyle(
+          color: state.filter == currentFilters[i]['value'] ? Colors
+              .white : textColor, fontSize: 16)),
+    );
+  }
+}
+
+class OngoingFilter extends StatelessWidget {
+  final List<dynamic> currentFilters;
+
+  const OngoingFilter({super.key, this.currentFilters = const []});
+
+  @override
+  Widget build(BuildContext context) {
+    return BlocBuilder<OngoingCubit, TabState>(
+        builder: (context, state) {
+          return Row(
+            children: List.generate(currentFilters.length, (i) {
+              return GestureDetector(
+                child: FilterItem(state: state, currentFilters: currentFilters, i: i),
+                onTap: () {
+                  String currentFilter = '';
+
+                  if (state.filter != currentFilters[i]['value']) {
+                    currentFilter = currentFilters[i]['value'];
+                  } else {
+                    currentFilter = 'none';
+                  }
+                  context.read<OngoingCubit>().setFilter(currentFilter);
+                  // context.read<OngoingCubit>().loadOngoing();
+                },
+              ).withHover();
+            }),
+          );
+        }
+    );
+  }
+}

+ 70 - 0
lib/src/layouts/web/menu-history/build_tab.dart

@@ -0,0 +1,70 @@
+import 'package:easy_localization/easy_localization.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+
+import '../../../cubit/history_menu_cubit.dart';
+import '../../../utils/U.dart';
+import '../../../utils/extensions.dart';
+
+class BuildTab extends StatelessWidget {
+  final TabController controller;
+  const BuildTab({super.key, required this.controller});
+
+  @override
+  Widget build(BuildContext context) {
+    return BlocBuilder<MenuHistoryCubit, MenuHistoryState>(
+        builder: (context, state) {
+      return Row(
+        children: [
+          GestureDetector(
+            child: Container(
+              margin: EdgeInsets.only(left: 16),
+              padding: EdgeInsets.symmetric(vertical: 5, horizontal: 16),
+              decoration: BoxDecoration(
+                  color: Colors.white,
+                  border: Border(
+                      bottom: BorderSide(
+                          color: state.activeTab.name == "ongoing"
+                              ? primaryColor
+                              : primaryColor.withValues(alpha: 0.3),
+                          width: state.activeTab.name == "ongoing" ? 2 : 1))),
+              child: Text('ongoing'.tr(),
+                  style: TextStyle(
+                      color: state.activeTab.name == "ongoing"
+                          ? textColor
+                          : textColor.withValues(alpha: 0.65),
+                      fontSize: 16)),
+            ),
+            onTap: () {
+              controller.animateTo(0);
+              context.read<MenuHistoryCubit>().setActiveTab(HistoryTab.ongoing);
+            },
+          ).withHover(),
+          GestureDetector(
+            child: Container(
+              padding: EdgeInsets.symmetric(vertical: 5, horizontal: 16),
+              decoration: BoxDecoration(
+                  color: Colors.white,
+                  border: Border(
+                      bottom: BorderSide(
+                          color: state.activeTab.name == "done"
+                              ? primaryColor
+                              : primaryColor.withValues(alpha: 0.3),
+                          width: state.activeTab.name == "done" ? 2 : 1))),
+              child: Text('done'.tr(),
+                  style: TextStyle(
+                      color: state.activeTab.name == "done"
+                          ? textColor
+                          : textColor.withValues(alpha: 0.65),
+                      fontSize: 16)),
+            ),
+            onTap: () {
+              controller.animateTo(1);
+              context.read<MenuHistoryCubit>().setActiveTab(HistoryTab.done);
+            },
+          ).withHover(),
+        ],
+      );
+    });
+  }
+}

+ 109 - 0
lib/src/layouts/web/menu-history/done_container.dart

@@ -0,0 +1,109 @@
+import 'package:easy_localization/easy_localization.dart';
+import 'package:easy_refresh/easy_refresh.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+import 'package:lazy_load_scrollview/lazy_load_scrollview.dart';
+import 'package:provider/provider.dart';
+import 'package:telnow_mobile_new/src/layouts/web/menu-history/history_item_widget.dart';
+import '../../../cubit/history_tab_cubit.dart';
+import '../../../utils/U.dart';
+import '../../../utils/provider.dart';
+import '../../components/template.dart';
+
+class DoneContainer extends StatefulWidget {
+  const DoneContainer({super.key});
+
+  @override
+  State<DoneContainer> createState() => _DoneContainerState();
+}
+
+class _DoneContainerState extends State<DoneContainer>
+    with SingleTickerProviderStateMixin, AutomaticKeepAliveClientMixin {
+  late AnimationController _animationController;
+
+  @override
+  bool get wantKeepAlive => true;
+
+  @override
+  void initState() {
+    _animationController = AnimationController(
+      vsync: this,
+      duration: const Duration(milliseconds: 800),
+    )..repeat(reverse: true);
+    super.initState();
+  }
+
+  @override
+  void dispose() {
+    _animationController.dispose();
+    super.dispose();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    super.build(context);
+
+    List<dynamic> rating = [
+      {
+        'key': 1,
+        'image': "assets/image/icon/very_dissatisfied.png",
+        'label': 'disatisfied'.tr()
+      },
+      {
+        'key': 2,
+        'image': "assets/image/icon/dissatisfied.png",
+        'label': 'lessSatisfied'.tr()
+      },
+      {
+        'key': 3,
+        'image': "assets/image/icon/neutral.png",
+        'label': 'satisfied'.tr()
+      },
+      {
+        'key': 4,
+        'image': "assets/image/icon/satisfied.png",
+        'label': 'verySatisfied'.tr()
+      },
+      {
+        'key': 5,
+        'image': "assets/image/icon/very_satisfied.png",
+        'label': 'reallyPleased'.tr()
+      },
+    ];
+
+    return BlocBuilder<DoneCubit, TabState>(
+      builder: (context, state) {
+        UserModule userModule = Provider.of<UserModule>(context, listen: false);
+        var data = state.data;
+
+        if (state.isLoading) {
+          return loadingTemplateNoVoid();
+        } else if (data.isEmpty) {
+          return NoDataPage();
+        }
+
+        return EasyRefresh(
+          header: MaterialHeader(clamping: true, color: primaryColor),
+          onRefresh: () => context.read<DoneCubit>().reloadPage(),
+          child: LazyLoadScrollView(
+            onEndOfPage: () => context.read<DoneCubit>().loadNextPage(),
+            scrollOffset: 300,
+            child: ListView.builder(
+                itemCount: data.length,
+                itemBuilder: (context, i) {
+                  return HistoryItemWidget(
+                    tab: 'done',
+                    state: state,
+                    index: i,
+                    item: data[i],
+                    userModule: userModule,
+                    rating: rating,
+                    animationController: _animationController,
+                  );
+                }),
+          ),
+        );
+      },
+    );
+  }
+}

+ 318 - 0
lib/src/layouts/web/menu-history/history_item_widget.dart

@@ -0,0 +1,318 @@
+import 'package:easy_localization/easy_localization.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+import 'package:telnow_mobile_new/src/cubit/history_detail_cubit.dart';
+import 'package:telnow_mobile_new/src/cubit/history_menu_cubit.dart' hide HistoryTab;
+
+import '../../../cubit/history_tab_cubit.dart';
+import '../../../cubit/user_data_cubit.dart';
+import '../../../repository/history_repository.dart';
+import '../../../utils/U.dart';
+import '../../../utils/extensions.dart';
+import '../../../utils/provider.dart';
+import '../../components/rate_mission.dart';
+import '../../components/template.dart';
+import '../history_detail.dart';
+import '../request_create.dart';
+
+class HistoryItemWidget extends StatelessWidget {
+  final Map<String, dynamic> item;
+  final UserModule userModule;
+  final List<dynamic> rating;
+  final AnimationController animationController;
+  final int index;
+  final TabState state;
+  final String tab;
+
+  const HistoryItemWidget({
+    super.key,
+    required this.item,
+    required this.userModule,
+    required this.rating,
+    required this.animationController,
+    required this.index,
+    required this.state,
+    required this.tab,
+  });
+
+  @override
+  Widget build(BuildContext context) {
+    return GestureDetector(
+      onTap: () {
+        if (context.read<MenuHistoryCubit>().state.multiSelectMode && tab == 'done') {
+          context.read<MenuHistoryCubit>().selectIndex(index);
+        } else {
+          navigateTo(
+            context,
+            BlocProvider<HistoryDetailCubit>(
+              create: (_) => HistoryDetailCubit()..getData(item['ticketNo'], context.locale.toString()),
+              child: WebHistoryDetailPage(
+                index: index,
+                locale: context.locale.toString(),
+              ),
+            ),
+          );
+        }
+      },
+      onLongPress: () => tab == 'done' && !context.read<MenuHistoryCubit>().state.multiSelectMode
+          ? context.read<MenuHistoryCubit>().selectIndex(index) : null,
+      child: Container(
+        width: double.infinity,
+        padding: const EdgeInsets.all(15),
+        margin: const EdgeInsets.only(bottom: 15),
+        decoration: BoxDecoration(
+          color: context.read<MenuHistoryCubit>().state.selectedIndex.contains(index)
+              ? primaryColor.withValues(alpha: 0.15) : Colors.white,
+          border: Border.all(color: textColor.withValues(alpha: 0.15)),
+          borderRadius: const BorderRadius.all(Radius.circular(12)),
+        ),
+        child: Column(
+          spacing: 10,
+          children: [
+            _buildHeader(context),
+            _buildBody(context),
+            _buildFooter(context),
+          ],
+        ),
+      ),
+    ).withHover();
+  }
+
+  Widget _buildHeader(BuildContext context) {
+    return Row(
+      children: [
+        Text(
+          convertDate(item['datetimeRequest'], context.locale.toString()),
+          style: const TextStyle(color: primaryColor, fontSize: 14),
+        ),
+        const SizedBox(width: 15),
+        Expanded(
+          child: Text(
+            '${'ticketNumber'.tr()}: ${item['ticketNo']}',
+            style: const TextStyle(color: textColor, fontSize: 14),
+            overflow: TextOverflow.ellipsis,
+          ),
+        ),
+        _renderStatus(item['currentState'])
+      ],
+    );
+  }
+
+  Widget _buildBody(BuildContext context) {
+    return Column(
+      children: [
+        divider(),
+        const SizedBox(height: 10),
+        Row(
+          children: [
+            imageTiles(imageUrl: item['_requestImage'] ?? "null", width: 150, height: 120),
+            const SizedBox(width: 25),
+            Expanded(
+              child: Column(
+                crossAxisAlignment: CrossAxisAlignment.start,
+                children: [
+                  Text(item[U.langColumn(context, 'requestGroupDescription')],
+                      style: const TextStyle(color: textColor, fontSize: 16),
+                      overflow: TextOverflow.ellipsis),
+                  const SizedBox(height: 10),
+                  Text(item[U.langColumn(context, 'requestSubject')],
+                      style: const TextStyle(color: textColor, fontWeight: FontWeight.w600),
+                      overflow: TextOverflow.ellipsis),
+                  const SizedBox(height: 5),
+                  Text(item[U.langColumn(context, '_subjectDescription')] ?? '',
+                      style: const TextStyle(color: textColor),
+                      overflow: TextOverflow.ellipsis),
+                  dashed(top: 10, bottom: 10),
+                  _renderRequested(userModule, item),
+                  Text('${'location'.tr()}: ${item['ipphoneExtLocation']}',
+                      style: const TextStyle(color: textColor, fontSize: 14),
+                      overflow: TextOverflow.ellipsis),
+                ],
+              ),
+            )
+          ],
+        ),
+      ],
+    );
+  }
+
+  Widget _buildFooter(BuildContext context) {
+    bool doneStatus = item['currentState'] == 'DISELESAIKAN' ||
+        item['currentState'] == 'TUNTAS' ||
+        item['currentState'] == 'DIBATALKAN';
+
+    final rowChildren = <Widget>[
+      if ((item['satisfactionRate'] == 0 && item['servantGroup'] != "#autoresponse") && doneStatus)
+        GestureDetector(
+          child: Container(
+            padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 16),
+            decoration: BoxDecoration(
+              color: Colors.white,
+              border: Border.all(color: secondaryColor),
+              borderRadius: const BorderRadius.all(Radius.circular(50)),
+            ),
+            child: Text('rateReq'.tr(),
+                style: const TextStyle(color: secondaryColor, fontSize: 14),
+                overflow: TextOverflow.ellipsis),
+          ),
+          onTap: () {
+            showDialog(
+              context: context,
+              builder: (_) => RateMission(
+                parentContext: context,
+                list: item,
+                index: index,
+                rating: rating,
+                state: state,
+              ),
+            );
+          },
+        ).withHover()
+      else if (item['satisfactionRate'] > 0)
+        Row(
+          mainAxisAlignment: MainAxisAlignment.end,
+          children: [
+            Text(rating[item['satisfactionRate']-1]['label'].toString(), style: TextStyle(color: textColor, fontSize: 14), overflow: TextOverflow.ellipsis),
+            SizedBox(width: 5),
+            Image(image: AssetImage(rating[item['satisfactionRate']-1]['image'].toString()), width: 25),
+          ],
+        )
+      else
+        SizedBox(),
+
+      if(item['_hasForum']) _message(item['_hasForum'], item['_forumMsg'] ?? "null"),
+
+      if(doneStatus) GestureDetector(
+        child: Container(
+          padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 16),
+          decoration: BoxDecoration(
+            color: Colors.white,
+            border: Border.all(color: primaryColor),
+            borderRadius: const BorderRadius.all(Radius.circular(50)),
+          ),
+          child: Text('reqAgain'.tr(),
+              style: const TextStyle(color: primaryColor, fontSize: 14)),
+        ),
+        // onTap: () => navigateTo(context,
+        //     WebReqCreatePage(user: {}, request: {})
+        // )
+        onTap: () async{
+          var menuHistoryCubit = context.read<MenuHistoryCubit>();
+          Map<String, dynamic> user = context.read<UserCubit>().state.user;
+
+          menuHistoryCubit.setMultiSelectMode(false);
+
+          try {
+            String tenant = '';
+            String filter = '';
+
+            if ((item['requestGroupCode']).split(" ").length != 1) {
+              tenant = ',{"f":["tenantCode","EQ","${(item['requestGroupCode']).split(" ").first}"]}';
+            }
+            filter = '{"and":[{"f":["code","EQ","${item['requestCode']}"]}$tenant]}';
+
+            var res = await HistoryRepository().checkRequest(filter);
+            if (res.isNotEmpty) {
+              if (res.containsKey('_embedded')) {
+                navigateTo(context, WebReqCreatePage(user: user, request: res['_embedded']['requests'][0],));
+              } else {
+                menuHistoryCubit.showError('reqCodeNotFound'.tr());
+              }
+            }
+          } catch (e) {
+            menuHistoryCubit.showError('reqCodeNotFound'.tr());
+          }
+        }
+      ).withHover()
+    ];
+
+    // kalau rowChildren kosong → return shrink
+    if (rowChildren.isEmpty) {
+      return const SizedBox.shrink();
+    }
+
+    return Column(
+      children: [
+        divider(),
+        const SizedBox(height: 10),
+        Row(
+          mainAxisAlignment: MainAxisAlignment.spaceBetween,
+          children: rowChildren,
+        ),
+      ],
+    );
+  }
+
+
+  Widget _renderStatus(String currentState) {
+    Map<String, Map<String, dynamic>> states = {
+      'DIMULAI': {'text': 'onProgress'.tr(), 'color': Color(0xffCCA600).withValues(alpha: 0.2)},
+      'HOLD': {'text': 'hold'.tr(), 'color': Color(0xffD3D3D3)},
+      'DIPROSES': {'text': 'queued'.tr(), 'color': Color(0xff02C539).withValues(alpha: 0.2)},
+      'DIANTRIKAN': {'text': 'queued'.tr(), 'color': Color(0xff02C539).withValues(alpha: 0.2)},
+      'DISELESAIKAN': {'text': 'stateFinish'.tr(), 'color': primaryColor.withValues(alpha: 0.4)},
+      'TUNTAS': {'text': 'stateFinish'.tr(), 'color': primaryColor.withValues(alpha: 0.4)},
+      'DIBATALKAN': {'text': 'stateCancel'.tr(), 'color': const Color(0xffD81010).withValues(alpha: 0.4)},
+    };
+    
+    Color color = states[currentState]?['color'] ?? Colors.transparent;
+    final text = states[currentState]?['text'] ?? '';
+  
+    return Container(
+      padding: const EdgeInsets.symmetric(vertical: 3, horizontal: 10),
+      margin: const EdgeInsets.only(left: 10),
+      decoration: BoxDecoration(color: color, borderRadius: const BorderRadius.all(Radius.circular(3))),
+      child: Text(text, style: const TextStyle(fontSize: 12, color: textColor)),
+    );
+  }
+
+  Widget _renderRequested(userModule, list) {
+    if (list['receptionistId'] != null) {
+      var user = userModule.user();
+      if (user['roomAttendant'] &&
+          user['userId'] != list['informantUserId'] &&
+          user['userId'] == list['receptionistId']) {
+        return Column(
+          crossAxisAlignment: CrossAxisAlignment.start,
+          children: [
+            Text('${'requestedFor'.tr()}: ${list['informantName'] ?? '-'}',
+                style: const TextStyle(color: textColor, fontSize: 13, fontWeight: FontWeight.w300)),
+            const SizedBox(height: 6),
+          ],
+        );
+      }
+
+      if (user['userId'] == list['informantUserId'] &&
+          user['userId'] != list['receptionistId']) {
+        return Column(
+          crossAxisAlignment: CrossAxisAlignment.start,
+          children: [
+            Text('${'requestedBy'.tr()}: ${list['receptionistName'] ?? ''}',
+                style: const TextStyle(color: textColor, fontSize: 13, fontWeight: FontWeight.w300)),
+            const SizedBox(height: 6),
+          ],
+        );
+      }
+    }
+
+    return Container();
+  }
+
+  Widget _message(bool hasForum, String forumMsg) {
+    if (hasForum) {
+      return Row(
+        children: [
+          FadeTransition(
+            opacity: animationController,
+            child: U.iconsax('messages-3', color: primaryColor),
+          ),
+          const SizedBox(width: 8),
+          Text('“$forumMsg”',
+              style: TextStyle(color: textColor.withValues(alpha: 0.75), fontSize: 14, fontStyle: FontStyle.italic),
+              overflow: TextOverflow.ellipsis),
+        ],
+      );
+    }
+    return const SizedBox();
+  }
+}

+ 138 - 0
lib/src/layouts/web/menu-history/ongoing_container.dart

@@ -0,0 +1,138 @@
+import 'package:easy_refresh/easy_refresh.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+import 'package:lazy_load_scrollview/lazy_load_scrollview.dart';
+import 'package:provider/provider.dart';
+import 'package:telnow_mobile_new/src/layouts/components/template.dart';
+import 'package:telnow_mobile_new/src/layouts/web/menu-history/history_item_widget.dart';
+
+import '../../../cubit/history_menu_cubit.dart';
+import '../../../cubit/history_tab_cubit.dart';
+import '../../../utils/U.dart';
+import '../../../utils/provider.dart';
+
+class OngoingContainer extends StatefulWidget {
+  const OngoingContainer({super.key});
+
+  @override
+  State<StatefulWidget> createState() => _OngoingContainerState();
+}
+
+class _OngoingContainerState extends State<OngoingContainer>
+    with TickerProviderStateMixin, AutomaticKeepAliveClientMixin {
+  late AnimationController _animationController;
+
+  @override
+  bool get wantKeepAlive => true;
+
+  @override
+  void initState() {
+    _animationController = AnimationController(
+      vsync: this,
+      duration: const Duration(milliseconds: 800),
+    )..repeat(reverse: true);
+    // TODO: implement initState
+    super.initState();
+  }
+
+  @override
+  void dispose() {
+    _animationController.dispose();
+    super.dispose();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    super.build(context);
+    return BlocBuilder<OngoingCubit, TabState>(
+        builder: (BuildContext context, state) {
+      UserModule userModule = Provider.of<UserModule>(context, listen: false);
+      var pendingData = context.read<MenuHistoryCubit>().state.pendingData;
+      List<dynamic> rating = [];
+
+      if (state.isLoading) {
+        return loadingTemplateNoVoid();
+      }
+
+      if (!U.getInternetStatus() && pendingData.isNotEmpty) {
+        return ListView.builder(
+            itemCount: state.data.length,
+            itemBuilder: (context, i) {
+              return HistoryItemWidget(
+                  tab: 'ongoing',
+                  state: state,
+                  index: i,
+                  item: pendingData[i],
+                  userModule: userModule,
+                  rating: rating,
+                  animationController: _animationController);
+            });
+      }
+
+      if (state.data.isEmpty) {
+        return NoDataPage();
+      }
+
+      return EasyRefresh(
+        header: MaterialHeader(clamping: true, color: primaryColor),
+        onRefresh: () => context.read<OngoingCubit>().reloadPage(),
+        child: LazyLoadScrollView(
+          onEndOfPage: () => context.read<OngoingCubit>().loadNextPage(),
+          scrollOffset: 300,
+          child: ListView.builder(
+              itemCount: state.data.length,
+              itemBuilder: (context, i) {
+                var dataRequest = state.data;
+
+                return HistoryItemWidget(
+                    tab: 'ongoing',
+                    state: state,
+                    index: i,
+                    item: dataRequest[i],
+                    userModule: userModule,
+                    rating: rating,
+                    animationController: _animationController);
+              }),
+        ),
+      );
+    });
+  }
+
+  // renderStatus(text, color){
+  //   return Container(
+  //     padding: EdgeInsets.symmetric(vertical: 3, horizontal: 10),
+  //     margin: EdgeInsets.only(left: 10),
+  //     decoration: BoxDecoration(
+  //         color: color, borderRadius: BorderRadius.all(Radius.circular(3))
+  //     ),
+  //     child: Text(text, style: TextStyle(fontSize: 12, color: textColor)),
+  //   );
+  // }
+  //
+  // Widget renderRequested(list){
+  //   if(list['receptionistId'] != null){
+  //     var user = userModule.user();
+  //     if(user['roomAttendant'] && user['userId'] != list['informantUserId'] && user['userId'] == list['receptionistId']){
+  //       return Column(
+  //         crossAxisAlignment: CrossAxisAlignment.start,
+  //         children: [
+  //           Text('${'requestedFor'.tr()}: ${list['informantName']??'-'}' ,style: TextStyle(color: textColor, fontSize: 13, fontWeight: FontWeight.w300)),
+  //           SizedBox(height: 6),
+  //         ],
+  //       );
+  //     }
+  //
+  //     if(user['userId'] == list['informantUserId'] && user['userId'] != list['receptionistId']){
+  //       return Column(
+  //         crossAxisAlignment: CrossAxisAlignment.start,
+  //         children: [
+  //           Text('${'requestedBy'.tr()}: ${list['receptionistName']??''}' ,style: TextStyle(color: textColor, fontSize: 13, fontWeight: FontWeight.w300)),
+  //           SizedBox(height: 6),
+  //         ],
+  //       );
+  //     }
+  //   }
+  //
+  //   return Container();
+  // }
+}

+ 80 - 76
lib/src/layouts/web/menu_account.dart

@@ -1,6 +1,7 @@
 import 'package:app_settings/app_settings.dart';
 import 'package:auto_route/auto_route.dart';
 import 'package:easy_localization/easy_localization.dart';
+import 'package:flutter/foundation.dart';
 import 'package:flutter/material.dart';
 import 'package:page_transition/page_transition.dart';
 import 'package:provider/provider.dart';
@@ -10,6 +11,7 @@ import 'package:telnow_mobile_new/src/layouts/functions/account.dart';
 import 'package:telnow_mobile_new/src/layouts/components/template.dart';
 import 'package:telnow_mobile_new/src/layouts/web/password.dart';
 import 'package:telnow_mobile_new/src/utils/U.dart';
+import 'package:telnow_mobile_new/src/utils/extensions.dart';
 import 'package:telnow_mobile_new/src/utils/provider.dart';
 import 'package:permission_handler/permission_handler.dart';
 import 'package:telnow_mobile_new/src/utils/ui_service.dart';
@@ -57,11 +59,7 @@ class _WebAccountPageState extends State<WebAccountPage> {
 
   setToggle() async{
     var license = await U.getLicense();
-    if(await U.isCompatibleWith(VersionKey.multiBahasa)){
-      lang = license['_validLang'] ?? [];
-    } else {
-      lang = license['languages'] != null ? license['languages'].split(',') : [];
-    }
+    lang = license['_validLang'] ?? [];
     setState(() {
       serDis = U.servantDisplay();
       autoTranslate = U.autoTranslate();
@@ -103,7 +101,7 @@ class _WebAccountPageState extends State<WebAccountPage> {
                     context.router.removeLast();
                     context.navigateToPath("/app/$pid/menu");
                   },
-                )
+                ).withHover()
               ],
             ),
           ),
@@ -213,7 +211,7 @@ class _WebAccountPageState extends State<WebAccountPage> {
                                         ],
                                       ),
                                     ),
-                                  ),
+                                  ).withHover(),
                                 ],
                               )
                             ],
@@ -254,7 +252,7 @@ class _WebAccountPageState extends State<WebAccountPage> {
                                         }
                                       });
                                     },
-                                  ),
+                                  ).withHover(),
                                 ],
                               )
                             ],
@@ -281,7 +279,7 @@ class _WebAccountPageState extends State<WebAccountPage> {
                                   ),
                                 ),
                                 onTap: () => changeLang(context, Provider.of<UserModule>(context, listen: false).user()),
-                              ),
+                              ).withHover(),
                               divider(),
                               Container(
                                 color: Colors.white,
@@ -319,7 +317,7 @@ class _WebAccountPageState extends State<WebAccountPage> {
                                           }
                                         });
                                       },
-                                    ),
+                                    ).withHover(),
                                   ],
                                 ),
                               ),
@@ -343,7 +341,7 @@ class _WebAccountPageState extends State<WebAccountPage> {
                                   value??false;
                                   if (value) UIService.showSuccess('messagePassChanged'.tr());
                                 }),
-                              ),
+                              ).withHover(),
                               divider(),
                               GestureDetector(
                                 child: Container(
@@ -380,7 +378,7 @@ class _WebAccountPageState extends State<WebAccountPage> {
                                     },
                                   );
                                 },
-                              ),
+                              ).withHover(),
                             ],
                           ),
                           separator(),
@@ -427,22 +425,24 @@ class _WebAccountPageState extends State<WebAccountPage> {
                                 },
                               );
                             },
-                          ),
-                          isDeniedNotifPermission ? Padding(padding: EdgeInsets.symmetric(vertical: 16), child: separator()) : Container(),
-                          isDeniedNotifPermission ? GestureDetector(
-                            child: Column(
-                              crossAxisAlignment: CrossAxisAlignment.start,
-                              children: [
-                                Text("not_allow_permission".tr()),
-                                SizedBox(height: 8,),
-                                Text("tap_here".tr(), style: TextStyle(color: Color(0xFF198AF2)),),
-                              ],
-                            ),
-                            onTap: () => AppSettings.openAppSettings(type: AppSettingsType.notification).then((value) async {
-                              // print("after open setting");
-                              // checkPermission(2);
-                            }),
-                          ) : Container(),
+                          ).withHover(),
+                          if(isDeniedNotifPermission && !kIsWeb) ...[
+                            GestureDetector(
+                              child: Column(
+                                crossAxisAlignment: CrossAxisAlignment.start,
+                                children: [
+                                  Text("not_allow_permission".tr()),
+                                  SizedBox(height: 8,),
+                                  Text("tap_here".tr(), style: TextStyle(color: Color(0xFF198AF2)),),
+                                ],
+                              ),
+                              onTap: () => AppSettings.openAppSettings(type: AppSettingsType.notification).then((value) async {
+                                // print("after open setting");
+                                // checkPermission(2);
+                              }),
+                            ).withHover(),
+                            Padding(padding: EdgeInsets.symmetric(vertical: 16), child: separator()),
+                          ]
                         ],
                       ),
                     ),
@@ -456,7 +456,7 @@ class _WebAccountPageState extends State<WebAccountPage> {
     ) : userModule.resetData() ? RefreshPage(() {
       Provider.of<UserModule>(context, listen: false).setResetData(false);
       accFunc.getUser(context);
-    }) : _timeLimit ? showButton(context) : loadingTemplate(() {if(mounted) setState(()=>_timeLimit=true);},);
+    }) : _timeLimit ? showButton(context) : loadingTemplate( (){ if(mounted) setState(()=>_timeLimit=true); }, );
   }
 
   changeLang(context, user) {
@@ -486,52 +486,56 @@ class _WebAccountPageState extends State<WebAccountPage> {
   }
 
   listOfLang(user, cd){
-    return !mounted ? SizedBox() : SafeArea(
-      child: Column(
-        crossAxisAlignment: CrossAxisAlignment.start,
-        children: [
-          ListTile(
-            title: Text('bahasa'.tr(), style: TextStyle(color: textColor, fontSize: 14)),
-            trailing: Icon(context.locale.toString()=='id'?Icons.radio_button_checked:Icons.radio_button_off, color: primaryColor, size: 18),
-            onTap: context.locale.toString() != 'id' ? () async {
-              accFunc.switchLang('id', user);
-              Navigator.of(cd).pop();
-            } : null,
-          ),
-          ListTile(
-            title: Text('english'.tr(), style: TextStyle(color: textColor, fontSize: 14)),
-            trailing: Icon(context.locale.toString()=='en'?Icons.radio_button_checked:Icons.radio_button_off, color: primaryColor, size: 18),
-            onTap: context.locale.toString() != 'en' ? () async {
-              accFunc.switchLang('en', user);
-              Navigator.of(cd).pop();
-            } : null,
-          ),
-          lang.length - 1 > 1 ? ListTile(
-            title: Text(codeOflang[lang[2]], style: TextStyle(color: textColor, fontSize: 14)),
-            trailing: Icon(context.locale.toString()==lang[2]?Icons.radio_button_checked:Icons.radio_button_off, color: primaryColor, size: 18),
-            onTap: context.locale.toString() != lang[2] ? () async {
-              accFunc.switchLang(1, user);
-              Navigator.of(cd).pop();
-            } : null,
-          ) : Container(),
-          lang.length - 1 > 2 ? ListTile(
-            title: Text(codeOflang[lang[3]], style: TextStyle(color: textColor, fontSize: 14)),
-            trailing: Icon(context.locale.toString()==lang[3]?Icons.radio_button_checked:Icons.radio_button_off, color: primaryColor, size: 18),
-            onTap: context.locale.toString() != lang[3] ? () async {
-              accFunc.switchLang(2, user);
-              Navigator.of(cd).pop();
-            } : null,
-          ) : Container(),
-          lang.length - 1 > 3 ? ListTile(
-            title: Text(codeOflang[lang[4]], style: TextStyle(color: textColor, fontSize: 14)),
-            trailing: Icon(context.locale.toString()==lang[4]?Icons.radio_button_checked:Icons.radio_button_off, color: primaryColor, size: 18),
-            onTap: context.locale.toString() != lang[4] ? () async {
-              accFunc.switchLang(3, user);
-              Navigator.of(cd).pop();
-            } : null,
-          ) : Container(),
-        ],
-      ),
-    );
+    if(mounted) {
+      return SafeArea(
+        child: Column(
+          crossAxisAlignment: CrossAxisAlignment.start,
+          children: [
+            ListTile(
+              title: Text('bahasa'.tr(), style: TextStyle(color: textColor, fontSize: 14)),
+              trailing: Icon(context.locale.toString()=='id'?Icons.radio_button_checked:Icons.radio_button_off, color: primaryColor, size: 18),
+              onTap: context.locale.toString() != 'id' ? () async {
+                accFunc.switchLang('id', user);
+                Navigator.of(cd).pop();
+              } : null,
+            ),
+            ListTile(
+              title: Text('english'.tr(), style: TextStyle(color: textColor, fontSize: 14)),
+              trailing: Icon(context.locale.toString()=='en'?Icons.radio_button_checked:Icons.radio_button_off, color: primaryColor, size: 18),
+              onTap: context.locale.toString() != 'en' ? () async {
+                accFunc.switchLang('en', user);
+                Navigator.of(cd).pop();
+              } : null,
+            ),
+            if(lang.length - 1 > 1) ListTile(
+              title: Text(codeOflang[lang[2]], style: TextStyle(color: textColor, fontSize: 14)),
+              trailing: Icon(context.locale.toString()==lang[2]?Icons.radio_button_checked:Icons.radio_button_off, color: primaryColor, size: 18),
+              onTap: context.locale.toString() != lang[2] ? () async {
+                accFunc.switchLang(1, user);
+                Navigator.of(cd).pop();
+              } : null,
+            ),
+            if(lang.length - 1 > 2) ListTile(
+              title: Text(codeOflang[lang[3]], style: TextStyle(color: textColor, fontSize: 14)),
+              trailing: Icon(context.locale.toString()==lang[3]?Icons.radio_button_checked:Icons.radio_button_off, color: primaryColor, size: 18),
+              onTap: context.locale.toString() != lang[3] ? () async {
+                accFunc.switchLang(2, user);
+                Navigator.of(cd).pop();
+              } : null,
+            ),
+            if(lang.length - 1 > 3) ListTile(
+              title: Text(codeOflang[lang[4]], style: TextStyle(color: textColor, fontSize: 14)),
+              trailing: Icon(context.locale.toString()==lang[4]?Icons.radio_button_checked:Icons.radio_button_off, color: primaryColor, size: 18),
+              onTap: context.locale.toString() != lang[4] ? () async {
+                accFunc.switchLang(3, user);
+                Navigator.of(cd).pop();
+              } : null,
+            ),
+          ],
+        ),
+      );
+    } else {
+      return SizedBox.shrink();
+    }
   }
 }

+ 157 - 763
lib/src/layouts/web/menu_history.dart

@@ -1,15 +1,22 @@
 import 'package:auto_route/auto_route.dart';
 import 'package:easy_localization/easy_localization.dart';
-import 'package:easy_refresh/easy_refresh.dart';
 import 'package:flutter/material.dart';
-import 'package:lazy_load_scrollview/lazy_load_scrollview.dart';
-import 'package:provider/provider.dart';
-import 'package:telnow_mobile_new/src/api/api_auth_provider.dart';
-import 'package:telnow_mobile_new/src/layouts/functions/history.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+import 'package:telnow_mobile_new/src/cubit/history_menu_cubit.dart';
+import 'package:telnow_mobile_new/src/cubit/user_data_cubit.dart';
 import 'package:telnow_mobile_new/src/layouts/components/template.dart';
-import 'package:telnow_mobile_new/src/layouts/web/history_detail.dart';
+import 'package:telnow_mobile_new/src/layouts/web/request_create.dart';
 import 'package:telnow_mobile_new/src/utils/U.dart';
-import 'package:telnow_mobile_new/src/utils/provider.dart';
+import 'package:telnow_mobile_new/src/utils/dio_logging_interceptors.dart';
+
+import '../../cubit/history_tab_cubit.dart';
+import '../../utils/extensions.dart';
+import '../../utils/ui_service.dart';
+import '../mobile/request_create.dart';
+import 'menu-history/build_filter.dart';
+import 'menu-history/build_tab.dart';
+import 'menu-history/done_container.dart';
+import 'menu-history/ongoing_container.dart';
 
 class WebHistoryPage extends StatefulWidget {
   const WebHistoryPage({super.key});
@@ -19,10 +26,8 @@ class WebHistoryPage extends StatefulWidget {
 }
 
 class _WebHistoryPageState extends State<WebHistoryPage> with TickerProviderStateMixin {
-  final HistoryFunction hisFunc = HistoryFunction();
   late AnimationController _animationController;
-  late final HistoryModule historyModule = Provider.of<HistoryModule>(context, listen: false);
-  late final UserModule userModule = Provider.of<UserModule>(context, listen: false);
+  late TabController _tabController;
 
   var rating = [
     {'key': 1, 'image': "assets/image/icon/very_dissatisfied.png", 'label': 'disatisfied'.tr()},
@@ -35,794 +40,183 @@ class _WebHistoryPageState extends State<WebHistoryPage> with TickerProviderStat
 
   @override
   void initState() {
-    // print(U.newServerVersion(1716279633));
-    historyModule.reset();
     _animationController = AnimationController(vsync: this, duration: Duration(seconds: 1));
     _animationController.repeat(reverse: true);
+    _tabController = TabController(
+      length: 2,
+      vsync: this,
+      initialIndex: context.read<MenuHistoryCubit>().state.activeIndex,
+    );
 
     WidgetsBinding.instance.addPostFrameCallback((_) {
-      hisFunc.getActiveForum();
+      context.read<UserCubit>().getUser();
     });
     // TODO: implement initState
+    _tabController.addListener(() {
+      if (_tabController.indexIsChanging) {
+        if (_tabController.index == 0) {
+          context.read<MenuHistoryCubit>().setActiveTab(HistoryTab.ongoing);
+        } else {
+          context.read<MenuHistoryCubit>().setActiveTab(HistoryTab.done);
+        }
+      }
+    });
     super.initState();
   }
 
   @override
   void dispose() {
     _animationController.dispose();
+    _tabController.dispose();
     super.dispose();
   }
 
   @override
   Widget build(BuildContext context) {
-    final HistoryModule historyModuleListen = Provider.of<HistoryModule>(context);
-    final UserModule userModuleListen = Provider.of<UserModule>(context);
-    return userModuleListen.resetData() ? RefreshPage(() {
-      userModule.setResetData(false);
-      hisFunc.getActiveForum();
-    }) : Scaffold(
-      backgroundColor: backgroundColor,
-      appBar: PreferredSize(preferredSize: Size.fromHeight(0), child: AppBar(elevation: 0, backgroundColor: primaryColor)),
-      body: Column(
-        children: [
-          Container(
-            padding: EdgeInsets.symmetric(vertical: 25, horizontal: 100),
-            child: Row(
-              mainAxisAlignment: MainAxisAlignment.spaceBetween,
-              children: [
-                Text('history'.tr(), style: TextStyle(color: textColor, fontSize: 17, fontWeight: FontWeight.w500), overflow: TextOverflow.ellipsis),
-                historyModuleListen.multiSelectMode() ? GestureDetector(
-                  child: Container(
-                    padding: EdgeInsets.fromLTRB(16, 9, 16, 9),
-                    decoration: BoxDecoration(color: primaryColor.withValues(alpha: 0.1), border: Border.all(color: primaryColor), borderRadius: BorderRadius.all(Radius.circular(50))),
-                    child: Row(
-                      children: [
-                        Text('delete'.tr(), style: TextStyle(color: primaryColor, fontSize: 14)),
-                        SizedBox(width: 5),
-                        U.iconsax('trash', color: primaryColor, size: 20)
-                      ],
-                    ),
-                  ),
-                  onTap: () => hisFunc.deleteData(context),
-                ) : GestureDetector(
-                  child: Text('buttonBack'.tr(), style: TextStyle(color: primaryColor, fontSize: 14)),
-                  onTap: (){
-                    var pid = U.getPidFromUrl(context.router.currentUrl);
-                    context.router.removeLast();
-                    context.navigateToPath("/app/$pid/menu");
-                  },
-                )
-              ],
+    final userCubit = context.read<UserCubit>();
+
+    eventBus.on().listen((event){
+      debugPrint(event.toString());
+    });
+
+    if (userCubit.state.reset) {
+      return RefreshPage(() {
+      userCubit.setReset(false);
+    });
+    } else {
+      if (_timeLimit) {
+        return showButton(context);
+      } else {
+        return MultiBlocProvider(
+          providers: [
+            BlocProvider(
+              create: (context) => MenuHistoryCubit()..init(),
             ),
-          ),
-          divider(),
-          Container(
-            padding: EdgeInsets.symmetric(vertical: 25, horizontal: 100),
-            child: Column(
-              crossAxisAlignment: CrossAxisAlignment.start,
-              children: [
-                Row(
-                  children: [
-                    GestureDetector(
-                      child: Container(
-                        padding: EdgeInsets.symmetric(vertical: 5, horizontal: 16),
-                        decoration: BoxDecoration(color: Colors.white, border: Border(bottom: BorderSide(color: historyModuleListen.activeTab() == 1 ? primaryColor : primaryColor.withValues(alpha: 0.3), width: historyModuleListen.activeTab() == 1 ? 2 : 1))),
-                        child: Text('ongoing'.tr(), style: TextStyle(color: historyModuleListen.activeTab() == 1 ? textColor : textColor.withValues(alpha: 0.65), fontSize: 16)),
-                      ),
-                      onTap: () {
-                        if (!historyModule.isLoadHistory()) {
-                          historyModule.setSelectedFilter(0);
-                          historyModule.setActiveTab(HistoryTab.ongoing);
-                          hisFunc.onRefresh();
-                        }
-                      },
-                    ),
-                    GestureDetector(
-                      child: Container(
-                        padding: EdgeInsets.symmetric(vertical: 5, horizontal: 16),
-                        decoration: BoxDecoration(color: Colors.white, border: Border(bottom: BorderSide(color: historyModuleListen.activeTab() == 0 ? primaryColor : primaryColor.withValues(alpha: 0.3), width: historyModuleListen.activeTab() == 0 ? 2 : 1))),
-                        child: Text('done'.tr(), style: TextStyle(color: historyModuleListen.activeTab() == 0 ? textColor : textColor.withValues(alpha: 0.65), fontSize: 16)),
-                      ),
-                      onTap: () {
-                        if (!historyModule.isLoadHistory()) {
-                          historyModule.setSelectedFilter(0);
-                          historyModule.setActiveTab(HistoryTab.done);
-                          hisFunc.onRefresh();
-                        }
-                      },
-                    ),
-                  ],
-                ),
-                SizedBox(height: 20),
-                historyModuleListen.activeTab() == 0 ? doneFilter() : ongoingFilter(),
-              ],
+            BlocProvider(
+              create: (context) => OngoingCubit()..loadOngoing(),
             ),
-          ),
-          Expanded(
-            child: userModuleListen.user().isNotEmpty ? Container(
-              width: double.infinity,
-              padding: EdgeInsets.symmetric(horizontal: 100),
-              child: LazyLoadScrollView(
-                onEndOfPage: () => hisFunc.getMission(),
-                scrollOffset: 500,
-                child: EasyRefresh(
-                  header: MaterialHeader(clamping: true, color: primaryColor),
-                  onRefresh: ()=>hisFunc.onRefresh(),
-                  child: historyModuleListen.activeTab() == 0 ? doneContainer() : ongoingContainer(),
-                ),
-              ),
-            ) : userModuleListen.resetData() ? Container() : _timeLimit ? showButton(context) : loadingTemplate(() {if(mounted) setState(()=>_timeLimit=true);},),
-          )
-        ],
-      ),
-    );
-  }
-
-  Widget ongoingFilter() {
-    final HistoryModule historyModuleListen = Provider.of<HistoryModule>(context);
-    return SingleChildScrollView(
-      scrollDirection: Axis.horizontal,
-      child: Row(
-        children: List.generate(hisFunc.ongoingList.length, (i) {
-          return GestureDetector(
-            child: Container(
-              margin: EdgeInsets.only(right: 16),
-              padding: EdgeInsets.symmetric(vertical: 8, horizontal: 16),
-              decoration: BoxDecoration(
-                  color: historyModuleListen.checkSelectedFilter(hisFunc.ongoingList[i]['value']) ? primaryColor : Color(0xffF2F8F7),
-                  border: Border.all(color: historyModuleListen.checkSelectedFilter(hisFunc.ongoingList[i]['value']) ? primaryColor : Color(0xffBEC1C1)),
-                  borderRadius: BorderRadius.all(Radius.circular(50))),
-              child: Text(hisFunc.ongoingList[i]['title'], style: TextStyle(color: historyModuleListen.checkSelectedFilter(hisFunc.ongoingList[i]['value']) ? Colors.white : textColor, fontSize: 16)),
+            BlocProvider(
+              create: (context) => DoneCubit()..loadDone(),
             ),
-            onTap: () {
-              if (!historyModule.isLoadHistory()) {
-                if (historyModule.checkSelectedFilter(hisFunc.ongoingList[i]['value'])) {
-                  historyModule.setSelectedFilter(0);
-                  hisFunc.onRefresh();
-                } else {
-                  historyModule.setSelectedFilter(hisFunc.ongoingList[i]['value']);
-                  hisFunc.onRefresh();
+          ],
+          child: Scaffold(
+            backgroundColor: backgroundColor,
+            body: BlocConsumer<MenuHistoryCubit, MenuHistoryState>(
+              listener: (context, state) {
+                if(state is TabChanged){
+                  _tabController.index = state.index;
                 }
-              }
-            },
-          );
-        }),
-      ),
-    );
-  }
-
-  Widget ongoingContainer() {
-    final HistoryModule historyModuleListen = Provider.of<HistoryModule>(context);
-    return SingleChildScrollView(
-      child: Column(
-        children: [
-          U.newServerVersion(1709864293) && !U.getInternetStatus() ? Column(
-            children: List.generate(historyModuleListen.dataPending().length, (i) {
-              return GestureDetector(
-                child: Container(
-                  width: double.infinity,
-                  padding: EdgeInsets.all(15),
-                  margin: EdgeInsets.only(bottom: 15),
-                  decoration: BoxDecoration(color: Colors.white, border: Border.all(color: textColor.withValues(alpha: 0.15)), borderRadius: BorderRadius.all(Radius.circular(12))),
-                  child: Column(
-                    children: [
-                      Row(
+                if(state is ReloadPage){
+                  context.read<MenuHistoryCubit>().setActiveTab(HistoryTab.done);
+                  context.read<DoneCubit>().reloadPage();
+                }
+                if(state is CreateNewRequest){
+                  var user = context.read<UserCubit>().state.user;
+                  var request = state.request;
+                  navigateTo(context,
+                      U.webView(context) ?
+                      WebReqCreatePage(user: user, request: request) :
+                      MobReqCreatePage(user: user, request: request)
+                  );
+                }
+                if(state is ShowError){
+                  UIService.showError(state.error);
+                }
+              },
+              builder: (context, state){
+                return Column(
+                  children: [
+                    Container(
+                      padding: EdgeInsets.symmetric(vertical: 25, horizontal: 100),
+                      child: Row(
                         mainAxisAlignment: MainAxisAlignment.spaceBetween,
                         children: [
-                          Text(convertDate(historyModuleListen.dataPending()[i]['datetimeRequest'], context.locale.toString()), style: TextStyle(color: primaryColor, fontSize: 14)),
-                          renderStatus('sending'.tr(), Color(0xff02C539).withValues(alpha: 0.2))
-                        ],
-                      ),
-                      SizedBox(height: 10),
-                      divider(),
-                      SizedBox(height: 10),
-                      Row(
-                        children: [
-                          imageTiles(imageUrl: historyModuleListen.dataPending()[i]['image'] ?? "null"),
-                          SizedBox(width: 25),
-                          Expanded(
-                            child: Column(
-                              crossAxisAlignment: CrossAxisAlignment.start,
-                              children: [
-                                Text(historyModuleListen.dataPending()[i]['title'], style: TextStyle(color: textColor, fontWeight: FontWeight.w500), overflow: TextOverflow.ellipsis),
-                                SizedBox(height: 10),
-                                Text(historyModuleListen.dataPending()[i][U.langColumn(context, 'sub')], style: TextStyle(color: textColor), overflow: TextOverflow.ellipsis),
-                                SizedBox(height: 5),
-                                Text(historyModuleListen.dataPending()[i][U.langColumn(context, 'desc')], style: TextStyle(color: textColor), overflow: TextOverflow.ellipsis),
-                                dashed(top: 10, bottom: 10),
-                                Row(
-                                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
-                                  children: [
-                                    Text('${'location'.tr()}: ${historyModuleListen.dataPending()[i]['location']}', style: TextStyle(color: textColor, fontSize: 14), overflow: TextOverflow.ellipsis),
-                                    Row(
-                                      children: [
-                                        Container(
-                                          width: 25, height: 25,
-                                          decoration: BoxDecoration(image: DecorationImage(image: AssetImage('assets/image/general/Hourglass.png'), fit: BoxFit.cover)),
-                                        ),
-                                        SizedBox(width: 8),
-                                        Text('pending_info_tiles'.tr(), style: TextStyle(color: textColor, fontSize: 14))
-                                      ],
-                                    )
-                                  ],
-                                )
-                              ],
-                            ),
-                          )
-                        ],
-                      )
-                    ],
-                  ),
-                ),
-                onTap: () {
-                  if(!U.getInternetStatus()){
-                    // navigateTo(context, MobHistoryDetailPendingPage(data: historyModule.dataPending()[i])).then((val) {
-                    //   val = val??false;
-                    //   if(val) hisFunc.onRefresh(context);
-                    // });
-                  }
-                  else{
-                    hisFunc.onRefresh();
-                  }
-                },
-              );
-            }),
-          ) : Container(),
-
-          Column(
-            children: List.generate(historyModuleListen.dataRequests().length, (i) {
-              return GestureDetector(
-                child: Container(
-                  width: double.infinity,
-                  padding: EdgeInsets.all(15),
-                  margin: EdgeInsets.only(bottom: 15),
-                  decoration: BoxDecoration(color: Colors.white, border: Border.all(color: textColor.withValues(alpha: 0.15)), borderRadius: BorderRadius.all(Radius.circular(12))),
-                  child: Column(
-                    children: [
-                      Row(
-                        children: [
-                          Text(convertDate(historyModuleListen.dataRequests()[i]['datetimeRequest'], context.locale.toString()), style: TextStyle(color: primaryColor, fontSize: 14)),
-                          SizedBox(width: 15),
-                          Expanded(
-                            child: Text('${'ticketNumber'.tr()}: ${historyModuleListen.dataRequests()[i]['ticketNo']}', style: TextStyle(color: textColor, fontSize: 14), overflow: TextOverflow.ellipsis),
-                          ),
-                          historyModuleListen.dataRequests()[i]['currentState'] == 'DIMULAI' ? Row(
-                            children: [
-                              Container(
-                                width: 25, height: 25,
-                                decoration: BoxDecoration(
-                                    border: Border.all(color: primaryColor), borderRadius: BorderRadius.all(Radius.circular(25)),
-                                    image: DecorationImage(image: AssetImage('assets/image/general/Avatar.jpg'), fit: BoxFit.cover)
-                                ),
+                          Text('history'.tr(), style: TextStyle(color: textColor, fontSize: 17, fontWeight: FontWeight.w500), overflow: TextOverflow.ellipsis),
+                          state.multiSelectMode ? GestureDetector(
+                            child: Container(
+                              padding: EdgeInsets.fromLTRB(16, 9, 16, 9),
+                              decoration: BoxDecoration(color: primaryColor.withValues(alpha: 0.1), border: Border.all(color: primaryColor), borderRadius: BorderRadius.all(Radius.circular(50))),
+                              child: Row(
+                                children: [
+                                  Text('delete'.tr(), style: TextStyle(color: primaryColor, fontSize: 14)),
+                                  SizedBox(width: 5),
+                                  U.iconsax('trash', color: primaryColor, size: 20)
+                                ],
                               ),
-                              SizedBox(width: 8),
-                              Text(historyModuleListen.dataRequests()[i]['servantNameStart'] + 'isWorking'.tr(), style: TextStyle(color: textColor, fontSize: 14), overflow: TextOverflow.ellipsis)
-                            ],
-                          ) : Container(),
-                          historyModuleListen.dataRequests()[i]['_activeHoldRequest'] != null?renderStatus('hold'.tr(), Color(0xffD3D3D3)):historyModuleListen.dataRequests()[i]['currentState'] == 'DIMULAI'?renderStatus('onProgress'.tr(), Color(0xffCCA600).withValues(alpha: 0.2)):renderStatus('queued'.tr(), Color(0xff02C539).withValues(alpha: 0.2))
+                            ),
+                            onTap: () {
+                              showDialog(
+                                context: context,
+                                builder: (BuildContext contexts) {
+                                  return AlertDialog(
+                                    title: Text("deleteHistory".tr(), style: TextStyle(fontSize: 18),
+                                    ),
+                                    content: Text("deleteHistoryConfirm".tr()),
+                                    actions: <Widget>[
+                                      TextButton(
+                                        child: Text("buttonNo".tr()),
+                                        onPressed: () {
+                                          Navigator.of(contexts).pop();
+                                        },
+                                      ),
+                                      TextButton(
+                                          onPressed: () async {
+                                            Navigator.of(contexts).pop();
+                                            // context.read<MenuHistoryCubit>().setLoading(true);
+                                            var dataRequest = context.read<DoneCubit>().state.data;
+
+                                            context.read<MenuHistoryCubit>().deleteData(dataRequest);
+                                          },
+                                          child: Text("buttonYes".tr())),
+                                    ],
+                                  );
+                                },
+                              );
+                            },
+                          ).withHover() : GestureDetector(
+                            child: Text('buttonBack'.tr(), style: TextStyle(color: primaryColor, fontSize: 14)),
+                            onTap: (){
+                              var pid = U.getPidFromUrl(context.router.currentUrl);
+                              context.router.removeLast();
+                              context.navigateToPath("/app/$pid/menu");
+                            },
+                          ).withHover()
                         ],
                       ),
-                      SizedBox(height: 10),
-                      divider(),
-                      SizedBox(height: 10),
-                      Row(
+                    ),
+                    divider(),
+                    Container(
+                      padding: EdgeInsets.symmetric(horizontal: 100),
+                      child: Column(
+                        crossAxisAlignment: CrossAxisAlignment.start,
                         children: [
-                          imageTiles(imageUrl: historyModuleListen.dataRequests()[i]['_requestImage'] ?? "null", width: 150, height: 120),
-                          SizedBox(width: 25),
-                          Expanded(
-                            child: Column(
-                              crossAxisAlignment: CrossAxisAlignment.start,
-                              children: [
-                                Text(historyModuleListen.dataRequests()[i][U.langColumn(context, 'requestGroupDescription')], style: TextStyle(color: textColor, fontSize: 16), overflow: TextOverflow.ellipsis),
-                                SizedBox(height: 10),
-                                Text(historyModuleListen.dataRequests()[i][U.langColumn(context, 'requestSubject')], style: TextStyle(color: textColor, fontWeight: FontWeight.w600), overflow: TextOverflow.ellipsis),
-                                SizedBox(height: 5),
-                                Text(historyModuleListen.dataRequests()[i][U.langColumn(context, '_subjectDescription')]??'', style: TextStyle(color: textColor), overflow: TextOverflow.ellipsis),
-                                dashed(top: 10, bottom: 10),
-                                renderRequested(historyModuleListen.dataRequests()[i]),
-                                Row(
-                                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
-                                  crossAxisAlignment: CrossAxisAlignment.center ,
-                                  children: [
-                                    Text('${'location'.tr()}: ${historyModuleListen.dataRequests()[i]['ipphoneExtLocation']}', style: TextStyle(color: textColor, fontSize: 14), overflow: TextOverflow.ellipsis),
-                                    historyModuleListen.dataRequests()[i]['_activeHoldRequest'] != null ? Row(
-                                      children: [
-                                        Container(
-                                          width: 25, height: 25,
-                                          decoration: BoxDecoration(image: DecorationImage(image: AssetImage('assets/image/general/Watch.png'), fit: BoxFit.cover)),
-                                        ),
-                                        SizedBox(width: 8),
-                                        Text(historyModuleListen.dataRequests()[i]['_activeHoldRequest']['description'], style: TextStyle(color: textColor, fontSize: 14))
-                                      ],
-                                    ) : historyModuleListen.dataRequests()[i]['_hasForum'] && historyModuleListen.dataRequests()[i]['_forumMsg'] != null ? ConstrainedBox(
-                                      constraints: BoxConstraints(minWidth: 10),
-                                      child: Row(
-                                        children: [
-                                          FadeTransition(opacity: _animationController, child: U.iconsax('messages-3', color: primaryColor)),
-                                          SizedBox(width: 8),
-                                          Text('“${historyModuleListen.dataRequests()[i]['_forumMsg']}”', style: TextStyle(color: textColor.withValues(alpha: 0.75), fontSize: 14, fontStyle: FontStyle.italic))
-                                        ],
-                                      ),
-                                    ) : Container(),
-                                  ],
-                                ),
-                              ],
-                            ),
-                          )
+                          SizedBox(height: 16),
+                          BuildTab(controller: _tabController),
+                          SizedBox(height: 20),
+                          BuildFilter(),
                         ],
                       ),
-                    ],
-                  ),
-                ),
-                onTap: () => navigateTo(context, WebHistoryDetailPage(index: i)).then((val) {
-                  val = val??false;
-                  if(val) historyModule.cancelMisi(i);
-                }),
-              );
-            }),
-          ),
-          !historyModuleListen.stopLoadHistory() || (historyModuleListen.isLoadHistory() && historyModuleListen.page() > 0)
-              ? Container(margin: EdgeInsets.only(top: historyModuleListen.page() > 0 ? 0 : 50), child: loadingTemplateNoVoid())
-              : historyModuleListen.dataRequests().isEmpty && historyModuleListen.dataPending().isEmpty
-              ? NoDataPage()
-              : Container(),
-        ],
-      ),
-    );
-  }
-
-  Widget doneFilter() {
-    final HistoryModule historyModuleListen = Provider.of<HistoryModule>(context);
-    return Row(
-      children: List.generate(hisFunc.doneList.length, (i) {
-        return GestureDetector(
-          child: Container(
-            margin: EdgeInsets.only(right: 16),
-            padding: EdgeInsets.symmetric(vertical: 8, horizontal: 16),
-            decoration: BoxDecoration(
-                color: historyModuleListen.checkSelectedFilter(hisFunc.doneList[i]['value']) ? primaryColor : Color(0xffF2F8F7),
-                border: Border.all(color: historyModuleListen.checkSelectedFilter(hisFunc.doneList[i]['value']) ? primaryColor : Color(0xffBEC1C1)),
-                borderRadius: BorderRadius.all(Radius.circular(50))),
-            child: Text(hisFunc.doneList[i]['title'], style: TextStyle(color: historyModuleListen.checkSelectedFilter(hisFunc.doneList[i]['value']) ? Colors.white : textColor, fontSize: 16)),
-          ),
-          onTap: () {
-            if (!historyModule.isLoadHistory()) {
-              if (historyModule.checkSelectedFilter(hisFunc.doneList[i]['value'])) {
-                historyModule.setSelectedFilter(0);
-                hisFunc.onRefresh();
-              } else {
-                historyModule.setSelectedFilter(hisFunc.doneList[i]['value']);
-                hisFunc.onRefresh();
-              }
-            }
-          },
-        );
-      }),
-    );
-  }
-
-  Widget doneContainer() {
-    final HistoryModule historyModuleListen = Provider.of<HistoryModule>(context);
-    return SingleChildScrollView(
-      child: Column(
-        children: [
-          Column(
-              children: List.generate(historyModuleListen.dataRequests().length, (i) {
-                return GestureDetector(
-                  child: Container(
-                    width: double.infinity,
-                    padding: EdgeInsets.all(15),
-                    margin: EdgeInsets.only(bottom: 15),
-                    decoration: BoxDecoration(color: Colors.white, border: Border.all(color: textColor.withValues(alpha: 0.15)), borderRadius: BorderRadius.all(Radius.circular(12))),
-                    child: Column(
-                      children: [
-                        Row(
-                          children: [
-                            Text(convertDate(historyModuleListen.dataRequests()[i]['datetimeRequest'], context.locale.toString()), style: TextStyle(color: primaryColor, fontSize: 14)),
-                            SizedBox(width: 15),
-                            Expanded(
-                              child: Text('${'ticketNumber'.tr()}: ${historyModuleListen.dataRequests()[i]['ticketNo']}', style: TextStyle(color: textColor, fontSize: 14), overflow: TextOverflow.ellipsis),
-                            ),
-                            historyModuleListen.dataRequests()[i]['currentState'] == 'DISELESAIKAN' || historyModuleListen.dataRequests()[i]['currentState'] == 'TUNTAS' ? renderStatus('stateFinish'.tr(), primaryColor.withValues(alpha: 0.4)) : renderStatus('stateCancel'.tr(), Color(0xffD81010).withValues(alpha: 0.4))
-                          ],
-                        ),
-                        SizedBox(height: 10),
-                        divider(),
-                        SizedBox(height: 10),
-                        Row(
-                          children: [
-                            imageTiles(imageUrl: historyModuleListen.dataRequests()[i]['_requestImage'] ?? "null", width: 150, height: 120),
-                            SizedBox(width: 25),
-                            Expanded(
-                              child: Column(
-                                crossAxisAlignment: CrossAxisAlignment.start,
-                                children: [
-                                  Text(historyModuleListen.dataRequests()[i][U.langColumn(context, 'requestGroupDescription')], style: TextStyle(color: textColor, fontSize: 16), overflow: TextOverflow.ellipsis),
-                                  SizedBox(height: 10),
-                                  Text(historyModuleListen.dataRequests()[i][U.langColumn(context, 'requestSubject')], style: TextStyle(color: textColor, fontWeight: FontWeight.w600), overflow: TextOverflow.ellipsis),
-                                  SizedBox(height: 5),
-                                  Text(historyModuleListen.dataRequests()[i][U.langColumn(context, '_subjectDescription')]??'', style: TextStyle(color: textColor), overflow: TextOverflow.ellipsis),
-                                  dashed(top: 10, bottom: 10),
-                                  renderRequested(historyModuleListen.dataRequests()[i]),
-                                  Text('${'location'.tr()}: ${historyModuleListen.dataRequests()[i]['ipphoneExtLocation']}', style: TextStyle(color: textColor, fontSize: 14), overflow: TextOverflow.ellipsis),
-                                ],
-                              ),
-                            )
-                          ],
-                        ),
-                        SizedBox(height: 10),
-                        divider(),
-                        SizedBox(height: 10),
-                        Row(
-                          mainAxisAlignment: MainAxisAlignment.spaceBetween,
-                          children: [
-                            !historyModuleListen.dataRequests()[i]['autoResponse'] && historyModuleListen.dataRequests()[i]['servantIdentityStart'] != '#system' && (historyModuleListen.dataRequests()[i]['currentState'] == 'TUNTAS' || historyModuleListen.dataRequests()[i]['currentState'] == 'DISELESAIKAN') ? Container(
-                              child: hisFunc.askForRate(Provider.of<HistoryModule>(context, listen: true).dataRequests()[i]) ? GestureDetector(
-                                child: Container(
-                                  padding: EdgeInsets.symmetric(vertical: 4, horizontal: 16),
-                                  decoration: BoxDecoration(color: Colors.white, border: Border.all(color: secondaryColor), borderRadius: BorderRadius.all(Radius.circular(50))),
-                                  child: Text('rateReq'.tr(), style: TextStyle(color: secondaryColor, fontSize: 14), overflow: TextOverflow.ellipsis),
-                                ),
-                                onTap: () {
-                                  U.newServerVersion(1716279633) ? rateMissionNew(context, historyModule.dataRequests()[i], i) : rateMission(context, historyModule.dataRequests()[i], i);
-                                },
-                              ) : !hisFunc.isAutoResponse(historyModuleListen.dataRequests()[i]) ? Row(
-                                children: [
-                                  Image(image: AssetImage(rating[historyModuleListen.dataRequests()[i]['satisfactionRate'] - 1]['image'].toString()), width: 25),
-                                  SizedBox(width: 5),
-                                  Text(rating[historyModuleListen.dataRequests()[i]['satisfactionRate'] - 1]['label'].toString(), style: TextStyle(color: textColor, fontSize: 14), overflow: TextOverflow.ellipsis),
-                                ],
-                              ) : Container(),
-                            ) : message(historyModuleListen.dataRequests()[i]['_hasForum'], historyModuleListen.dataRequests()[i]['_forumMsg'] ?? "null"),
-                            GestureDetector(
-                              child: Container(
-                                padding: EdgeInsets.symmetric(vertical: 4, horizontal: 16),
-                                decoration: BoxDecoration(color: Colors.white, border: Border.all(color: primaryColor), borderRadius: BorderRadius.all(Radius.circular(50))),
-                                child: Text('reqAgain'.tr(), style: TextStyle(color: primaryColor, fontSize: 14)),
-                              ),
-                              onTap: () => hisFunc.requestAgainAction(i),
-                            )
-                          ],
-                        ),
-                      ],
                     ),
-                  ),
-                  onTap: () {
-                    if (historyModule.multiSelectMode()) {
-                      hisFunc.selectedController(context, i);
-                    } else {
-                      navigateTo(context, WebHistoryDetailPage(index: i));
-                    }
-                  },
-                  onLongPress: () => hisFunc.selectedController(context, i),
-                );
-              })
-          ),
-          !historyModuleListen.stopLoadHistory() || (historyModuleListen.isLoadHistory() && historyModuleListen.page() > 0)
-              ? Container(margin: EdgeInsets.only(top: historyModuleListen.page() > 0 ? 0 : 50), child: loadingTemplateNoVoid())
-              : historyModuleListen.dataRequests().isEmpty ? NoDataPage() : Container(),
-        ],
-      ),
-    );
-  }
-
-  Widget renderRequested(list){
-    if(list['receptionistId'] != null){
-      var user = userModule.user();
-      if(user['roomAttendant'] && user['userId'] != list['informantUserId'] && user['userId'] == list['receptionistId']){
-        return Column(
-          crossAxisAlignment: CrossAxisAlignment.start,
-          children: [
-            Text('${'requestedFor'.tr()}: ${list['informantName']??'-'}' ,style: TextStyle(color: textColor, fontSize: 13), overflow: TextOverflow.ellipsis),
-            SizedBox(height: 5),
-          ],
-        );
-      }
-
-      if(user['userId'] == list['informantUserId'] && user['userId'] != list['receptionistId']){
-        return Column(
-          crossAxisAlignment: CrossAxisAlignment.start,
-          children: [
-            Text('${'requestedBy'.tr()}: ${list['receptionistName']??''}' ,style: TextStyle(color: textColor, fontSize: 13), overflow: TextOverflow.ellipsis),
-            SizedBox(height: 5),
-          ],
-        );
-      }
-    }
-
-    return Container();
-  }
-
-  Widget message(bool hasForum, String forumMsg, {double top = 0}) {
-    return hasForum ? Container(
-      margin: EdgeInsets.only(top: top),
-      child: Row(
-        children: [
-          FadeTransition(opacity: _animationController, child: U.iconsax('messages-3', color: primaryColor)),
-          SizedBox(width: 8),
-          Text('“$forumMsg”', style: TextStyle(color: textColor.withValues(alpha: 0.75), fontSize: 14, fontStyle: FontStyle.italic), overflow: TextOverflow.ellipsis),
-        ],
-      ),
-    ) : Container();
-  }
-
-  renderStatus(text, color){
-    return Container(
-      padding: EdgeInsets.symmetric(vertical: 3, horizontal: 10),
-      margin: EdgeInsets.only(left: 10),
-      decoration: BoxDecoration(
-        color: color, borderRadius: BorderRadius.all(Radius.circular(3))
-      ),
-      child: Text(text, style: TextStyle(fontSize: 12, color: textColor)),
-    );
-  }
-
-  rateMission(BuildContext context, list, index) {
-    showDialog(
-      context: context,
-        builder: (contexts) {
-          int tempRating = 0;
-          String description = '';
-          return AlertDialog(
-            backgroundColor: Colors.transparent,
-            contentPadding: EdgeInsets.all(0),
-            content: StatefulBuilder(
-              builder: (contextt, setStates) {
-                return Container(
-                  decoration: BoxDecoration(color: secondaryColor, borderRadius: BorderRadius.all(Radius.circular(25))),
-                  child: Column(
-                    mainAxisSize: MainAxisSize.min,
-                    crossAxisAlignment: CrossAxisAlignment.start,
-                    children: [
-                      Padding(
-                        padding: EdgeInsets.symmetric(vertical: 12, horizontal: 16),
-                        child: Column(
-                          crossAxisAlignment: CrossAxisAlignment.start,
-                          children: [
-                            Text(list[U.langColumn(context, 'requestSubject')], style: TextStyle(color: Colors.white, fontSize: 14, fontWeight: FontWeight.w600)),
-                            SizedBox(height: 4),
-                            Row(
-                              mainAxisAlignment: MainAxisAlignment.spaceBetween,
-                              children: [
-                                Text('ticketNumber'.tr()+': '+list['ticketNo'], style: TextStyle(color: Colors.white, fontSize: 12, fontWeight: FontWeight.w300)),
-                                Text(convertDate(list['datetimeRequest'], context.locale.toString()), style: TextStyle(color: Colors.white, fontSize: 12, fontWeight: FontWeight.w300)),
-                              ],
-                            ),
-                          ],
-                        ),
-                      ),
-                      Container(
-                        padding: EdgeInsets.fromLTRB(30, 15, 30, 15),
-                        decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.all(Radius.circular(25))),
-                        child: Column(
-                          children: [
-                            Text('satisfactionAsk'.tr(), style: TextStyle(fontSize: 16)),
-                            SizedBox(height: 12),
-                            Row(
-                              mainAxisAlignment: MainAxisAlignment.center,
-                              children: List.generate(rating.length, (i) {
-                                return Expanded(
-                                  child: GestureDetector(
-                                    child: Image(
-                                      image: AssetImage(rating[i]['image'].toString()),
-                                      color: Colors.white.withValues(alpha: tempRating == rating[i]['key'] ? 1 : 0.3),
-                                      colorBlendMode: BlendMode.modulate,
-                                    ),
-                                    // child: Icon(rating[i]['icon'] as IconData, color: tempRating == rating[i]['key']?rating[i]['color'] as Color:Colors.grey),
-                                    onTap: () {
-                                      setStates(() {
-                                        tempRating = rating[i]['key'] as int;
-                                        description = rating[i]['label'] as String;
-                                      });
-                                    },
-                                  ),
-                                );
-                              }),
-                            ),
-                            SizedBox(height: 6),
-                            Text(description, style: TextStyle(color: textColor, fontSize: 14, fontWeight: FontWeight.w300), textAlign: TextAlign.center),
-                            SizedBox(height: 20),
-                            Opacity(
-                              opacity: tempRating > 0 ? 1 : 0,
-                              child: Row(
-                                mainAxisAlignment: MainAxisAlignment.center,
-                                children: [
-                                  Expanded(child: buttonTemplate(text: 'textCancel'.tr(), backgroundColor: Colors.black12, borderColor: Colors.black12, textColor: textColor, height: 40, action: (){
-                                    navigateBack(contexts);
-                                  })),
-                                  SizedBox(width: 20),
-                                  Expanded(child: buttonTemplate(text: 'save_rating'.tr(), backgroundColor: primaryColor, borderColor: primaryColor, height: 40, action: ()async{
-                                    if (tempRating > 0) {
-                                      var data = {"ticketNo": list['ticketNo'], "rateSatisfy": tempRating};
-
-                                      var res = await ApiAuthProvider() .postData('/api/requestHistories/rateSatisfy', null, data);
-                                      if (res != null) {
-                                        historyModule.setSatisfaction(index, tempRating);
-                                        navigateBack(contexts);
-                                      }
-                                    }
-                                  }))
-                                ],
-                              ),
-                            )
-                          ],
-                        ),
-                      )
-                    ],
-                  ),
-                );
-              },
-            ),
-          );
-        }
-    );
-  }
-
-  rateMissionNew(BuildContext context, list, index) {
-    String locale = context.locale.toString();
-
-    showDialog(
-        context: context,
-        builder: (contexts) {
-          int tempRating = 0;
-          String description = '';
-          String ratingAspect = '';
-          TextEditingController controllerOptOther = new TextEditingController();
-          List aspectList = list['_ratingAspect${locale[0].toUpperCase()}${locale[1]}'] != null && list['_ratingAspect'+locale[0].toUpperCase()+locale[1]].trim() != '' ? list['_ratingAspect'+locale[0].toUpperCase()+locale[1]].split(';') : [];
-          if(aspectList.isNotEmpty){
-            aspectList.add('OTHER_OPTION');
-          }
-          else{
-            ratingAspect = 'OTHER_OPTION';
-          }
-
-          return AlertDialog(
-            backgroundColor: Colors.transparent,
-            contentPadding: EdgeInsets.all(0),
-            content: StatefulBuilder(
-              builder: (contextt, setStates) {
-                return Container(
-                  decoration: BoxDecoration(color: secondaryColor, borderRadius: BorderRadius.all(Radius.circular(25))),
-                  child: Column(
-                    mainAxisSize: MainAxisSize.min,
-                    crossAxisAlignment: CrossAxisAlignment.start,
-                    children: [
-                      Padding(
-                        padding: EdgeInsets.symmetric(vertical: 12, horizontal: 16),
-                        child: Column(
-                          crossAxisAlignment: CrossAxisAlignment.start,
+                    Expanded(
+                      child: Padding(
+                        padding: const EdgeInsets.fromLTRB(100, 20, 100, 0),
+                        child: TabBarView(
+                          controller: _tabController,
+                          physics: const NeverScrollableScrollPhysics(),
                           children: [
-                            Text(list[U.langColumn(context, 'requestSubject')], style: TextStyle(color: Colors.white, fontSize: 14, fontWeight: FontWeight.w600)),
-                            SizedBox(height: 4),
-                            Row(
-                              mainAxisAlignment: MainAxisAlignment.spaceBetween,
-                              children: [
-                                Text('${'ticketNumber'.tr()}: '+list['ticketNo'], style: TextStyle(color: Colors.white, fontSize: 12, fontWeight: FontWeight.w300)),
-                                Text(convertDate(list['datetimeRequest'], context.locale.toString()), style: TextStyle(color: Colors.white, fontSize: 12, fontWeight: FontWeight.w300)),
-                              ],
-                            ),
+                            OngoingContainer(),
+                            DoneContainer(),
                           ],
                         ),
                       ),
-                      Container(
-                        padding: EdgeInsets.fromLTRB(30, 15, 30, 15),
-                        decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.all(Radius.circular(25))),
-                        child: Column(
-                          children: [
-                            Text('satisfactionAsk'.tr(), style: TextStyle(fontSize: 16)),
-                            SizedBox(height: 12),
-                            Row(
-                              mainAxisAlignment: MainAxisAlignment.center,
-                              children: List.generate(rating.length, (i) {
-                                return Expanded(
-                                  child: GestureDetector(
-                                    child: Image(
-                                      image: AssetImage(rating[i]['image'].toString()),
-                                      color: Colors.white.withValues(alpha: tempRating == rating[i]['key'] ? 1 : 0.3),
-                                      colorBlendMode: BlendMode.modulate,
-                                    ),
-                                    onTap: () {
-                                      setStates(() {
-                                        tempRating = rating[i]['key'] as int;
-                                        description = rating[i]['label'] as String;
-                                      });
-                                    },
-                                  ),
-                                );
-                              }),
-                            ),
-                            SizedBox(height: 6),
-                            Text(description, style: TextStyle(color: textColor, fontSize: 14, fontWeight: FontWeight.w300), textAlign: TextAlign.center),
-                            tempRating != 0 ? SizedBox(height: 20) : Container(),
-                            tempRating != 0 ? separator() : Container(),
-                            tempRating != 0 ? SizedBox(height: 20) : Container(),
-                            tempRating != 0 ? Column(
-                              crossAxisAlignment: CrossAxisAlignment.start,
-                              children: [
-                                Text('${'whatMakesYou'.tr()} $description?', style: TextStyle(fontSize: 16)),
-                                SizedBox(height: 12),
-                                Wrap(
-                                  runSpacing: 10, spacing: 10,
-                                  children: List.generate(aspectList.length, (i){
-                                    return GestureDetector(
-                                      child: Container(
-                                        padding: EdgeInsets.symmetric(vertical: 5, horizontal: 10),
-                                        child: Text(aspectList[i]=='OTHER_OPTION'?'letMeWrite'.tr():aspectList[i], style: TextStyle(color: textColor)),
-                                        decoration: BoxDecoration(
-                                            color: aspectList[i] == ratingAspect ? primaryColor.withValues(alpha: 0.3) : Colors.white,
-                                            border: Border.all(color: aspectList[i] == ratingAspect ? primaryColor : textColor),
-                                            borderRadius: BorderRadius.all(Radius.circular(50))
-                                        ),
-                                      ),
-                                      onTap: (){
-                                        setStates(() {
-                                          ratingAspect = ratingAspect == aspectList[i]?'':aspectList[i];
-                                        });
-                                      },
-                                    );
-                                  }),
-                                ),
-                                aspectList.isNotEmpty ? SizedBox(height: 10) : Container(),
-                                ratingAspect == 'OTHER_OPTION' ? TextFormField(
-                                  maxLines: 1, maxLength: 50,
-                                  autofocus: true,
-                                  controller: controllerOptOther,
-                                  style: TextStyle(fontSize: 14, color: Colors.black),
-                                  decoration: InputDecoration(
-                                    counterText: '',
-                                    counterStyle: TextStyle(fontSize: 0),
-                                    hintText: 'writeHere'.tr(),
-                                    hintStyle: TextStyle(color: textColor.withValues(alpha: 0.5), fontSize: 14),
-                                    filled: true, fillColor: Colors.white,
-                                    isDense: true,
-                                    contentPadding: EdgeInsets.all(13),
-                                    prefixIcon: Padding(padding: EdgeInsets.only(left: 13, right: 13), child: U.iconsax('edit-2', color: textColor, size: 22)),
-                                    enabledBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(12), borderSide: BorderSide(color: Color(0xff262626).withValues(alpha: 0.5))),
-                                    focusedBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(12), borderSide: BorderSide(color: primaryColor)),
-                                  ),
-                                ) : Container(),
-                              ],
-                            ) : Container(),
-                            tempRating != 0 ? SizedBox(height: 20) : Container(),
-                            Opacity(
-                              opacity: tempRating > 0 ? 1 : 0,
-                              child: Row(
-                                mainAxisAlignment: MainAxisAlignment.center,
-                                children: [
-                                  Expanded(child: buttonTemplate(text: 'textCancel'.tr(), backgroundColor: Colors.black12, borderColor: Colors.black12, textColor: textColor, height: 40, action: (){
-                                    navigateBack(contexts);
-                                  })),
-                                  SizedBox(width: 20),
-                                  Expanded(child: buttonTemplate(text: 'save_rating'.tr(), backgroundColor: primaryColor, borderColor: primaryColor, height: 40, action: ()async{
-                                    if (tempRating > 0) {
-                                      var data = {"ticketNo": list['ticketNo'], "rateSatisfy": tempRating};
-                                      if(ratingAspect != 'OTHER_OPTION'){
-                                        data['aspect'] = ratingAspect;
-                                      }
-                                      else if(ratingAspect == 'OTHER_OPTION' && controllerOptOther.text.isNotEmpty){
-                                        data['aspect'] = controllerOptOther.text;
-                                      }
-
-                                      var res = await ApiAuthProvider() .postData('/api/requestHistories/rateSatisfy', null, data);
-                                      if (res != null) {
-                                        historyModule.setSatisfaction(index, tempRating);
-                                        navigateBack(contexts);
-                                      }
-                                    }
-                                  }))
-                                ],
-                              ),
-                            )
-                          ],
-                        ),
-                      )
-                    ],
-                  ),
+                    )
+                  ],
                 );
               },
             ),
-          );
-        }
-    );
+          )
+        );
+      }
+    }
   }
-}
+}

+ 135 - 161
lib/src/layouts/web/menu_home.dart

@@ -19,6 +19,7 @@ import 'package:telnow_mobile_new/src/layouts/web/request_select.dart';
 import 'package:telnow_mobile_new/src/storage/sharedpreferences/shared_preferences_manager.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/extensions.dart';
 import 'package:telnow_mobile_new/src/utils/provider.dart';
 import 'package:url_launcher/url_launcher.dart';
 
@@ -58,10 +59,7 @@ class _WebHomePageState extends State<WebHomePage> {
   bool _timeLimit = false;
 
   checkCompatibility() async{
-    var isCompatible = await U.isCompatibleWith(VersionKey.multiBahasa);
-    if(isCompatible) {
-      homeFunc.getContactCenter(context);
-    }
+    homeFunc.getContactCenter(context);
   }
 
   @override
@@ -102,40 +100,17 @@ class _WebHomePageState extends State<WebHomePage> {
                                 val = val??true;
                                 if(val) homeFunc.getFrequentlyRequested();
                               }),
-                            ),
+                            ).withHover(),
                           ),
                           SizedBox(width: 30),
-                          FutureBuilder(future: U.isCompatibleWith(VersionKey.multiBahasa), builder: (context, snapshot){
-                            if(!snapshot.hasData){
-                              return SizedBox();
-                            }
-                            final isCompatible = snapshot.data!;
-                            final hasContactCenter = Provider.of<ServiceModule>(context, listen: false)
-                                .contactCenter()
-                                .toString()
-                                .isNotEmpty;
-
-                            if (isCompatible && hasContactCenter) {
-                              return 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)
-                                ),
-                              ); // replace with the widget you want to show
-                            } else {
-                              return SizedBox(); // or nothing
-                            }
-                          }),
-                          // 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(),
+                          Provider.of<ServiceModule>(context, listen: false).contactCenter().toString().isNotEmpty ? 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)
+                            ).withHover(),
+                          ) : SizedBox(),
                           SizedBox(width: 10),
                           GestureDetector(
                             child: Container(
@@ -145,17 +120,17 @@ class _WebHomePageState extends State<WebHomePage> {
                                 alignment: Alignment.topRight,
                                 children: [
                                   U.iconsax('sms-notification', color: primaryColor),
-                                  Provider.of<ServiceModule>(context).unreadMessage() ? Container(
+                                  if(Provider.of<ServiceModule>(context).unreadMessage()) Container(
                                     width: 9, height: 9, margin: EdgeInsets.only(top: 1.3),
                                     decoration: BoxDecoration(color: Colors.red, borderRadius: BorderRadius.all(Radius.circular(50))),
-                                  ):Container()
+                                  ),
                                 ],
                               ),
                             ),
                             onTap: ()=>navigateTo(context, WebMessageListPage(Provider.of<UserModule>(context, listen: false).user())).then((_){
                               homeFunc.getUnreadMessages(context);
                             }),
-                          ),
+                          ).withHover(),
                           SizedBox(width: 10),
                           GestureDetector(
                             child: Container(
@@ -168,7 +143,7 @@ class _WebHomePageState extends State<WebHomePage> {
                               context.router.removeLast();
                               context.navigateToPath("/app/$pid/menu/history");
                             },
-                          ),
+                          ).withHover(),
                           SizedBox(width: 10),
                           GestureDetector(
                             child: Container(
@@ -181,13 +156,13 @@ class _WebHomePageState extends State<WebHomePage> {
                               context.router.removeLast();
                               context.navigateToPath("/app/$pid/menu/account");
                             },
-                          )
+                          ).withHover()
                         ],
                       ),
-                      Provider.of<UserModule>(context).profile()['greeting'][context.locale.toString()] != null ? Padding(
+                      if(Provider.of<UserModule>(context).profile()['greeting'][context.locale.toString()] != null) Padding(
                         padding: EdgeInsets.fromLTRB(15, 5, 15, 0),
                         child: Text(Provider.of<UserModule>(context).profile()['greeting'][context.locale.toString()], style: TextStyle(color: Colors.white, fontSize: 14), overflow: TextOverflow.ellipsis),
-                      ) : Container(),
+                      ),
                     ],
                   ),
                 ),
@@ -197,90 +172,85 @@ class _WebHomePageState extends State<WebHomePage> {
                   children: [
                     Text('${Provider.of<UserModule>(context).user()['name']}${(Provider.of<UserModule>(context).user()['guestName']!=null&&Provider.of<UserModule>(context).user()['guestName']!=''?' - ${Provider.of<UserModule>(context).user()['guestName']}':'')}', style: TextStyle(color: Colors.white, fontSize: 18), overflow: TextOverflow.ellipsis),
                     SizedBox(height: 10),
-                    Container(
-                      child: Row(
-                        children: [
-                          GestureDetector(child: Icon(Icons.info_outline, color: Colors.white, size: 20), onTap: () => showSuccess(context, "scopeDesc".tr()),),
-                          SizedBox(width: 8),
-                          Text('scope'.tr(), style: TextStyle(color: Colors.white, fontSize: 14)),
-                          SizedBox(width: 16),
-                          GestureDetector(
-                            child: Container(
-                              padding: EdgeInsets.fromLTRB(16, 4, 16, 4),
-                              decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.all(Radius.circular(50))),
-                              child: Row(
-                                children: [
-                                  Text(Provider.of<ServiceModule>(context).scoopeName(), style: TextStyle(color: primaryColor, fontSize: 14)),
-                                  SizedBox(width: 8),
-                                  U.iconsax('arrow-down-1', color: primaryColor, size: 14),
-                                ],
-                              ),
+                    Row(
+                      children: [
+                        GestureDetector(
+                          child: Icon(Icons.info_outline, color: Colors.white, size: 20),
+                          onTap: () => showSuccess(context, "scopeDesc".tr()),
+                        ).withHover(),
+                        SizedBox(width: 8),
+                        Text('scope'.tr(), style: TextStyle(color: Colors.white, fontSize: 14)),
+                        SizedBox(width: 16),
+                        GestureDetector(
+                          child: Container(
+                            padding: EdgeInsets.fromLTRB(16, 4, 16, 4),
+                            decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.all(Radius.circular(50))),
+                            child: Row(
+                              children: [
+                                Text(Provider.of<ServiceModule>(context).scoopeName(), style: TextStyle(color: primaryColor, fontSize: 14)),
+                                SizedBox(width: 8),
+                                U.iconsax('arrow-down-1', color: primaryColor, size: 14),
+                              ],
                             ),
-                            onTap: (){
-                              if(Provider.of<ServiceModule>(context, listen: false).scoope().isNotEmpty){
-                                showDialog(
-                                  context: context,
-                                  builder: (contexts) {
-                                    return AlertDialog(
-                                      contentPadding: EdgeInsets.symmetric(vertical: 0, horizontal: 10),
-                                      content: Column(
-                                        mainAxisSize: MainAxisSize.min,
-                                        children: [
-                                          Container(
-                                            margin: EdgeInsets.symmetric(vertical: 16),
-                                            child: Text('changeScope'.tr(), style: TextStyle(color: textColor, fontSize: 14), textAlign: TextAlign.center),
-                                          ),
-                                          divider(),
-                                          SizedBox(height: 16),
-                                          Column(
-                                            children: List.generate(Provider.of<ServiceModule>(context).getScoopeLength(), (i){
-                                              return GestureDetector(
-                                                  child: Container(
-                                                    color: Colors.white,
-                                                    padding: EdgeInsets.symmetric(vertical: 16, horizontal: 16),
-                                                    child: Row(
-                                                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
-                                                      children: [
-                                                        Text(Provider.of<ServiceModule>(context).scoope()[i]['value'], style: TextStyle(color: textColor, fontSize: 14)),
-                                                        Icon(Provider.of<ServiceModule>(context).checkScoope(Provider.of<ServiceModule>(context).scoope()[i]['key'])?Icons.radio_button_checked:Icons.radio_button_off, color: Provider.of<ServiceModule>(context).checkScoope(Provider.of<ServiceModule>(context).scoope()[i]['key'])?primaryColor:Colors.black45, size: 22),
-                                                      ],
-                                                    ),
+                          ),
+                          onTap: (){
+                            if(Provider.of<ServiceModule>(context, listen: false).scoope().isNotEmpty){
+                              showDialog(
+                                context: context,
+                                builder: (contexts) {
+                                  return AlertDialog(
+                                    contentPadding: EdgeInsets.symmetric(vertical: 0, horizontal: 10),
+                                    content: Column(
+                                      mainAxisSize: MainAxisSize.min,
+                                      children: [
+                                        Container(
+                                          margin: EdgeInsets.symmetric(vertical: 16),
+                                          child: Text('changeScope'.tr(), style: TextStyle(color: textColor, fontSize: 14), textAlign: TextAlign.center),
+                                        ),
+                                        divider(),
+                                        SizedBox(height: 16),
+                                        Column(
+                                          children: List.generate(Provider.of<ServiceModule>(context).getScoopeLength(), (i){
+                                            return GestureDetector(
+                                                child: Container(
+                                                  color: Colors.white,
+                                                  padding: EdgeInsets.symmetric(vertical: 16, horizontal: 16),
+                                                  child: Row(
+                                                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
+                                                    children: [
+                                                      Text(Provider.of<ServiceModule>(context).scoope()[i]['value'], style: TextStyle(color: textColor, fontSize: 14)),
+                                                      Icon(Provider.of<ServiceModule>(context).checkScoope(Provider.of<ServiceModule>(context).scoope()[i]['key'])?Icons.radio_button_checked:Icons.radio_button_off, color: Provider.of<ServiceModule>(context).checkScoope(Provider.of<ServiceModule>(context).scoope()[i]['key'])?primaryColor:Colors.black45, size: 22),
+                                                    ],
                                                   ),
-                                                  onTap: () async{
-                                                    await sharedPreferencesManager.putString(SharedPreferencesManager.keyScoope, Provider.of<ServiceModule>(context, listen: false).scoope()[i]['key']);
-                                                    Provider.of<ServiceModule>(context, listen: false).setScoopeValue(Provider.of<ServiceModule>(context, listen: false).scoope()[i]['key']);
-                                                    Provider.of<ServiceModule>(context, listen: false).setScoopeName(Provider.of<ServiceModule>(context, listen: false).scoope()[i]['value']);
-                                                    Navigator.of(contexts).pop();
+                                                ),
+                                                onTap: () async{
+                                                  await sharedPreferencesManager.putString(SharedPreferencesManager.keyScoope, Provider.of<ServiceModule>(context, listen: false).scoope()[i]['key']);
+                                                  Provider.of<ServiceModule>(context, listen: false).setScoopeValue(Provider.of<ServiceModule>(context, listen: false).scoope()[i]['key']);
+                                                  Provider.of<ServiceModule>(context, listen: false).setScoopeName(Provider.of<ServiceModule>(context, listen: false).scoope()[i]['value']);
+                                                  Navigator.of(contexts).pop();
 
-                                                    var profile = Provider.of<UserModule>(context, listen: false).profile();
-                                                    if(profile['topMenu']['show'] != null && profile['topMenu']['show'] == true) {
-                                                      if(U.newServerVersion(1709864293)){
-                                                        homeFunc.getTopMenuNew();
-                                                      }
-                                                      else{
-                                                        homeFunc.getTopMenu();
-                                                        homeFunc.getReqGroup();
-                                                      }
-                                                    }
-                                                    if(profile['specialOffer'] != null && profile['specialOffer']['show'] == true) homeFunc.getSpecialOffer(context);
-                                                    if(profile['frequentlyRequested'] != null && profile['frequentlyRequested']['show'] == true) homeFunc.getFrequentlyRequested();
-                                                    if(profile['banner'] != null && profile['banner']['show'] == true) homeFunc.getBanner(context);
-                                                    if(profile['quickAction'] != null && profile['quickAction']['show'] == true) homeFunc.getQuickAction(context);
+                                                  var profile = Provider.of<UserModule>(context, listen: false).profile();
+                                                  if(profile['topMenu']['show'] != null && profile['topMenu']['show'] == true) {
+                                                    homeFunc.getTopMenuNew();
                                                   }
-                                              );
-                                            }),
-                                          ),
-                                          SizedBox(height: 16),
-                                        ],
-                                      ),
-                                    );
-                                  },
-                                );
-                              }
-                            },
-                          )
-                        ],
-                      ),
+                                                  if(profile['specialOffer'] != null && profile['specialOffer']['show'] == true) homeFunc.getSpecialOffer(context);
+                                                  if(profile['frequentlyRequested'] != null && profile['frequentlyRequested']['show'] == true) homeFunc.getFrequentlyRequested();
+                                                  if(profile['banner'] != null && profile['banner']['show'] == true) homeFunc.getBanner(context);
+                                                  if(profile['quickAction'] != null && profile['quickAction']['show'] == true) homeFunc.getQuickAction(context);
+                                                }
+                                            ).withHover();
+                                          }),
+                                        ),
+                                        SizedBox(height: 16),
+                                      ],
+                                    ),
+                                  );
+                                },
+                              );
+                            }
+                          },
+                        ).withHover()
+                      ],
                     ),
                   ],
                 )
@@ -325,7 +295,6 @@ class _WebHomePageState extends State<WebHomePage> {
                                     Expanded(
                                       child: Container(
                                         width: double.infinity, height: double.infinity,
-                                        child: Provider.of<ServiceModule>(context).banner()[i]['image'] != null ? null : Center(child: Text("noImage".tr(), style: TextStyle(fontStyle: FontStyle.italic, color: Colors.black38), textAlign: TextAlign.center)),
                                         decoration: BoxDecoration(
                                           color: textColor.withValues(alpha: 0.1),
                                           borderRadius: BorderRadius.all(Radius.circular(12)),
@@ -334,6 +303,7 @@ class _WebHomePageState extends State<WebHomePage> {
                                             fit: BoxFit.cover,
                                           ):null,
                                         ),
+                                        child: Provider.of<ServiceModule>(context).banner()[i]['image'] != null ? null : Center(child: Text("noImage".tr(), style: TextStyle(fontStyle: FontStyle.italic, color: Colors.black38), textAlign: TextAlign.center)),
                                       ),
                                     ),
                                     Container(
@@ -375,12 +345,12 @@ class _WebHomePageState extends State<WebHomePage> {
                                 val = val??true;
                                 if(val) homeFunc.getFrequentlyRequested();
                               }),
-                            ),
+                            ).withHover(),
                           ),
                         ) : Container(),
                       ):Container(),
 
-                      Provider.of<UserModule>(context).profile()['topMenu']['show'] != null && Provider.of<UserModule>(context).profile()['topMenu']['show'] == true ? Container(
+                      if(Provider.of<UserModule>(context).profile()['topMenu']['show'] != null && Provider.of<UserModule>(context).profile()['topMenu']['show'] == true) Container(
                         margin: EdgeInsets.only(top: 25, bottom: 25),
                         padding: EdgeInsets.only(top: 20, bottom: 10),
                         decoration: BoxDecoration(color: Colors.white, border: Border.all(color: textColor.withValues(alpha: 0.15)), borderRadius: BorderRadius.all(Radius.circular(12))),
@@ -392,7 +362,7 @@ class _WebHomePageState extends State<WebHomePage> {
                                 double minHeight = 135;
                                 return Row(
                                   children: [
-                                    Provider.of<ServiceModule>(context).topMenu() != null ? Row(
+                                    if(Provider.of<ServiceModule>(context).topMenu() != null) Row(
                                       children: List.generate(Provider.of<ServiceModule>(context).topMenu()!.length+1, (i) {
                                         bool hideOther = i == Provider.of<ServiceModule>(context).topMenu()!.length && U.servantDisplay() && Provider.of<ServiceModule>(context).reqGroup()!.length == 0;
                                         return ConstrainedBox(
@@ -408,18 +378,18 @@ class _WebHomePageState extends State<WebHomePage> {
                                                   hideOther ? Container(width: size/1.8) : i == Provider.of<ServiceModule>(context).topMenu()!.length ? Container(
                                                     child: Container(
                                                       padding: EdgeInsets.all(5),
-                                                      child: SizedBox(width: size/1.8, height: size/1.8, child: U.iconsax('category', color: Color(0xff564F4F), size: 34)),
                                                       decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.all(Radius.circular(20)), boxShadow: [BoxShadow(color: Colors.grey.withValues(alpha: 0.3), blurRadius: 3, offset: Offset(0, 1))]),
+                                                      child: SizedBox(width: size/1.8, height: size/1.8, child: U.iconsax('category', color: Color(0xff564F4F), size: 34)),
                                                     ),
                                                   ) : Container(
                                                     padding: EdgeInsets.all(5),
-                                                    child: Image(image: CachedNetworkImageProvider(Provider.of<ServiceModule>(context).topMenu()![i]['iconUrl']+'?bridge-cache=true', cacheManager: CacheManager(CacheMan.config(Provider.of<ServiceModule>(context).topMenu()![i]['iconUrl']+'?bridge-cache=true'))), width: size/1.8, height: size/1.8),
                                                     decoration: BoxDecoration(
                                                         color: Colors.white,
                                                         borderRadius: BorderRadius.all(Radius.circular(20)),
                                                         border: Border.all(width: 0.2, color: Colors.black12),
                                                         boxShadow: [BoxShadow(color: Colors.grey.withValues(alpha: 0.3), blurRadius: 2, offset: Offset(0, 2))]
                                                     ),
+                                                    child: Image(image: CachedNetworkImageProvider(Provider.of<ServiceModule>(context).topMenu()![i]['iconUrl']+'?bridge-cache=true', cacheManager: CacheManager(CacheMan.config(Provider.of<ServiceModule>(context).topMenu()![i]['iconUrl']+'?bridge-cache=true'))), width: size/1.8, height: size/1.8),
                                                   ),
                                                   SizedBox(height: hideOther ? 0:8),
                                                   Expanded(
@@ -440,16 +410,18 @@ class _WebHomePageState extends State<WebHomePage> {
                                                   });
                                                 }
                                               },
-                                            ),
+                                            ).withHover(),
                                           ),
                                         );
                                       }),
-                                    ) : Container(),
-                                    Provider.of<UserModule>(context).user()['checkedIn'] && Provider.of<UserModule>(context).houseKeeping() && Provider.of<UserModule>(context).dndStatus() ? GestureDetector(
+                                    ),
+                                    if(Provider.of<UserModule>(context).user()['checkedIn'] && Provider.of<UserModule>(context).houseKeeping() && Provider.of<UserModule>(context).dndStatus()) GestureDetector(
                                       child: Container(
                                         width: size*2, padding: EdgeInsets.symmetric(horizontal: 25),
+                                        decoration: BoxDecoration(border: Border(left: BorderSide(color: Colors.grey))),
                                         child: Container(
                                           padding: EdgeInsets.all(10),
+                                          decoration: BoxDecoration(color: Color(0xffD81010).withValues(alpha: 0.15), borderRadius: BorderRadius.all(Radius.circular(10)), border: Border.all(color: Color(0xffD81010))),
                                           child: Column(
                                             children: [
                                               Icon(Icons.remove_circle, color: Color(0xffD81010), size: 18),
@@ -457,9 +429,7 @@ class _WebHomePageState extends State<WebHomePage> {
                                               Text('info_dnd'.tr(), style: TextStyle(color: textColor, fontSize: 14))
                                             ],
                                           ),
-                                          decoration: BoxDecoration(color: Color(0xffD81010).withValues(alpha: 0.15), borderRadius: BorderRadius.all(Radius.circular(10)), border: Border.all(color: Color(0xffD81010))),
                                         ),
-                                        decoration: BoxDecoration(border: Border(left: BorderSide(color: Colors.grey))),
                                       ),
                                       onTap: (){
                                         showDialog(
@@ -469,12 +439,12 @@ class _WebHomePageState extends State<WebHomePage> {
                                           ),
                                         );
                                       }
-                                    ) : Container()
+                                    ).withHover(),
                                   ],
                                 );
                               },
                             ),
-                            Provider.of<ServiceModule>(context).expand() ? Column(
+                            if(Provider.of<ServiceModule>(context).expand()) Column(
                               children: [
                                 Padding(padding: EdgeInsets.symmetric(horizontal: 30, vertical: 15), child: divider()),
                                 Align(
@@ -483,14 +453,14 @@ class _WebHomePageState extends State<WebHomePage> {
                                     child: Container(
                                       padding: EdgeInsets.symmetric(horizontal: 16, vertical: 4),
                                       margin: EdgeInsets.only(right: 30),
-                                      child: Text('customize'.tr(), style: TextStyle(color: primaryColor, fontSize: 14)),
                                       decoration: BoxDecoration(
                                           color: primaryColor.withValues(alpha: 0.1),
                                           borderRadius: BorderRadius.all(Radius.circular(50))
                                       ),
+                                      child: Text('customize'.tr(), style: TextStyle(color: primaryColor, fontSize: 14)),
                                     ),
                                     onTap: ()=>navigateTo(context, WebMenuEditorPage(scope: Provider.of<ServiceModule>(context, listen: false).scoopeValue())),
-                                  ),
+                                  ).withHover(),
                                 ),
                                 SizedBox(height: 20),
                                 LayoutBuilder(
@@ -531,7 +501,7 @@ class _WebHomePageState extends State<WebHomePage> {
                                                   if(val) homeFunc.getFrequentlyRequested();
                                                 });
                                               },
-                                            ),
+                                            ).withHover(),
                                           ),
                                         );
                                       }),
@@ -539,13 +509,14 @@ class _WebHomePageState extends State<WebHomePage> {
                                   },
                                 )
                               ],
-                            ) : Container(),
+                            ),
                           ],
                         ),
-                      ) : Container(),
-                      Provider.of<UserModule>(context).profile()['topMenu']['show'] != null && Provider.of<UserModule>(context).profile()['topMenu']['show'] == true ? separator() : Container(),
+                      ),
 
-                      Provider.of<UserModule>(context).profile()['specialOffer'] != null && Provider.of<UserModule>(context).profile()['specialOffer']['show'] == true ? Container(
+                      if(Provider.of<UserModule>(context).profile()['topMenu']['show'] != null && Provider.of<UserModule>(context).profile()['topMenu']['show'] == true) separator(),
+
+                      if(Provider.of<UserModule>(context).profile()['specialOffer'] != null && Provider.of<UserModule>(context).profile()['specialOffer']['show'] == true) Container(
                         width: double.infinity,
                         margin: EdgeInsets.only(top: 25),
                         child: Column(
@@ -566,6 +537,7 @@ class _WebHomePageState extends State<WebHomePage> {
                                       constraints: BoxConstraints(minWidth: minWidth, minHeight: minHeight),
                                       child: Container(
                                         width: size, height: size*1.4,
+                                        decoration: BoxDecoration(color: Colors.white, border: Border.all(color: textColor.withValues(alpha: 0.15)), borderRadius: BorderRadius.all(Radius.circular(12))),
                                         child: Column(
                                           crossAxisAlignment: CrossAxisAlignment.start,
                                           children: [
@@ -584,19 +556,18 @@ class _WebHomePageState extends State<WebHomePage> {
                                             )
                                           ],
                                         ),
-                                        decoration: BoxDecoration(color: Colors.white, border: Border.all(color: textColor.withValues(alpha: 0.15)), borderRadius: BorderRadius.all(Radius.circular(12))),
                                       ),
                                     ),
                                     onTap: ()=>navigateTo(context, WebReqCreatePage(user: Provider.of<UserModule>(context, listen: false).user(), request: Provider.of<ServiceModule>(context, listen: false).specialOffer()[i])),
-                                  )),
+                                  ).withHover()),
                                 );
                               },
                             ) : emptyWidget()
                           ],
                         ),
-                      ) : Container(),
+                      ),
 
-                      Provider.of<UserModule>(context).profile()['frequentlyRequested'] != null && Provider.of<UserModule>(context).profile()['frequentlyRequested']['show'] == true ? Container(
+                      if(Provider.of<UserModule>(context).profile()['frequentlyRequested'] != null && Provider.of<UserModule>(context).profile()['frequentlyRequested']['show'] == true) Container(
                         width: double.infinity,
                         margin: EdgeInsets.only(top: 36, bottom: 25),
                         child: Column(
@@ -618,6 +589,7 @@ class _WebHomePageState extends State<WebHomePage> {
                                         constraints: BoxConstraints(minWidth: minWidth, minHeight: minHeight),
                                         child: Container(
                                           width: size, height: size*1.2,
+                                          decoration: BoxDecoration(color: Colors.white, border: Border.all(color: textColor.withValues(alpha: 0.15)), borderRadius: BorderRadius.all(Radius.circular(12))),
                                           child: Column(
                                             crossAxisAlignment: CrossAxisAlignment.start,
                                             children: [
@@ -635,21 +607,20 @@ class _WebHomePageState extends State<WebHomePage> {
                                               )
                                             ],
                                           ),
-                                          decoration: BoxDecoration(color: Colors.white, border: Border.all(color: textColor.withValues(alpha: 0.15)), borderRadius: BorderRadius.all(Radius.circular(12))),
                                         ),
                                       ),
                                       onTap: ()=>navigateTo(context, WebReqCreatePage(user: Provider.of<UserModule>(context, listen: false).user(), request: Provider.of<ServiceModule>(context, listen: false).data()[i])).then((val){
                                         val = val??true;
                                         if(val) homeFunc.getFrequentlyRequested();
                                       }),
-                                    );
+                                    ).withHover();
                                   }),
                                 );
                               },
                             ) : emptyWidget(),
                           ],
                         ),
-                      ):Container(),
+                      ),
 
                       Provider.of<UserModule>(context).profile()['quickAction'] != null && Provider.of<UserModule>(context).profile()['quickAction']['show'] == true ? separator() : Container(),
                       Provider.of<UserModule>(context).profile()['quickAction'] != null && Provider.of<UserModule>(context).profile()['quickAction']['show'] == true ? Container(
@@ -668,7 +639,12 @@ class _WebHomePageState extends State<WebHomePage> {
                                   children: List.generate(Provider.of<ServiceModule>(context).quickAct().length, (i) {
                                     return GestureDetector(
                                       child: Container(
-                                        width: size, child: Row(
+                                        width: size,
+                                        decoration: BoxDecoration(
+                                          color: Colors.white,
+                                          border: Border.all(color: textColor.withValues(alpha: 0.15)),
+                                          borderRadius: BorderRadius.all(Radius.circular(12))
+                                        ), child: Row(
                                           children: [
                                             imageTiles(imageUrl: Provider.of<ServiceModule>(context).quickAct()[i]['_mobileImage'] ?? "null", width: 110, height: 90),
                                             SizedBox(width: 20),
@@ -685,14 +661,9 @@ class _WebHomePageState extends State<WebHomePage> {
                                             Padding(padding: EdgeInsets.symmetric(horizontal: 20), child: U.iconsax('arrow-right-3', size: 16, color: textColor.withValues(alpha: 0.75)))
                                           ],
                                         ),
-                                        decoration: BoxDecoration(
-                                          color: Colors.white,
-                                          border: Border.all(color: textColor.withValues(alpha: 0.15)),
-                                          borderRadius: BorderRadius.all(Radius.circular(12))
-                                        ),
                                       ),
                                       onTap: ()=>navigateTo(context, WebReqCreatePage(user: Provider.of<UserModule>(context, listen: false).user(), request: Provider.of<ServiceModule>(context, listen: false).quickAct()[i])),
-                                    );
+                                    ).withHover();
                                   }),
                                 );
                               },
@@ -760,7 +731,7 @@ class _WebMenuEditorPageState extends State<WebMenuEditorPage> {
                 GestureDetector(
                   child: Text('buttonBack'.tr(), style: TextStyle(color: primaryColor, fontSize: 14)),
                   onTap: ()=>navigateBack(context),
-                )
+                ).withHover()
               ],
             ),
           ),
@@ -818,7 +789,7 @@ class _WebMenuEditorPageState extends State<WebMenuEditorPage> {
                                                       data.remove(data[i]);
                                                     });
                                                   },
-                                                ),
+                                                ).withHover(),
                                                 SizedBox(width: 40)
                                               ],
                                             ),
@@ -880,7 +851,7 @@ class _WebMenuEditorPageState extends State<WebMenuEditorPage> {
                                             showError(context, 'maxMenu'.tr());
                                           }
                                         },
-                                      ),
+                                      ).withHover(),
                                     ],
                                   ),
                                 );
@@ -932,13 +903,16 @@ class _WebMenuEditorPageState extends State<WebMenuEditorPage> {
   imageContainer(iconUrl){
     return Container(
       padding: EdgeInsets.all(5),
-      child: Image(image: CachedNetworkImageProvider(iconUrl+'?bridge-cache=true', cacheManager: CacheManager(CacheMan.config(iconUrl+'?bridge-cache=true'))), width: 50, height: 50),
       decoration: BoxDecoration(
           color: Colors.white,
           borderRadius: BorderRadius.all(Radius.circular(12)),
           border: Border.all(width: 0.2, color: Colors.black12),
           boxShadow: [BoxShadow(color: Colors.grey.withValues(alpha: 0.3), blurRadius: 2, offset: Offset(0, 2))]
       ),
+      child: Image(
+          image: CachedNetworkImageProvider(iconUrl+'?bridge-cache=true', cacheManager: CacheManager(CacheMan.config(iconUrl+'?bridge-cache=true'))),
+          width: 50, height: 50
+      ),
     );
   }
 }

+ 1 - 16
lib/src/layouts/web/message_list.dart

@@ -1308,22 +1308,7 @@ class _WebMessageListPageState extends State<WebMessageListPage> {
             ),
           ),
           divider(),
-          FutureBuilder(future: U.isCompatibleWith(VersionKey.multiBahasa), builder: (context, snapshot){
-            if (snapshot.connectionState != ConnectionState.done) {
-              return CircularProgressIndicator(); // atau loading spinner
-            }
-
-            if (snapshot.hasError) {
-              print("Error in isCompatibleWith: ${snapshot.error}");
-              return SizedBox(); // atau widget fallback
-            }
-
-            if (snapshot.data == true) {
-              return tabForum();
-            } else {
-              return SizedBox();
-            }
-          }),
+          tabForum(),
           Expanded(
             child: Container(
               width: double.infinity, height: double.infinity,

+ 3 - 2
lib/src/layouts/web/password.dart

@@ -9,6 +9,7 @@ import 'package:telnow_mobile_new/src/model/login/login_body.dart';
 import 'package:telnow_mobile_new/src/model/token/token.dart';
 import 'package:telnow_mobile_new/src/storage/sharedpreferences/shared_preferences_manager.dart';
 import 'package:telnow_mobile_new/src/utils/U.dart';
+import 'package:telnow_mobile_new/src/utils/extensions.dart';
 
 class WebPasswordPage extends StatefulWidget {
   final Map<String, dynamic> user;
@@ -43,7 +44,7 @@ class _WebPasswordPageState extends State<WebPasswordPage> {
                 GestureDetector(
                   child: Text('buttonBack'.tr(), style: TextStyle(color: primaryColor, fontSize: 14)),
                   onTap: ()=>navigateBack(context),
-                )
+                ).withHover(),
               ],
             ),
           ),
@@ -157,7 +158,7 @@ class _WebPasswordPageState extends State<WebPasswordPage> {
               border: InputBorder.none,
               prefixIcon: U.iconsax('bold/key', size: 24, color: iconColor),
               suffixIconConstraints: BoxConstraints(maxHeight: 40, maxWidth: 40, minHeight: 40, minWidth: 40),
-              suffixIcon: GestureDetector(child: U.iconsax(hidePass?'eye':'eye-slash', size: 24, color: textColor.withValues(alpha: 0.5)), onTap: ()=>fieldState(()=>hidePass=!hidePass)),
+              suffixIcon: GestureDetector(child: U.iconsax(hidePass?'eye':'eye-slash', size: 24, color: textColor.withValues(alpha: 0.5)), onTap: ()=>fieldState(()=>hidePass=!hidePass)).withHover(),
               enabledBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(12), borderSide: BorderSide(color: textColor.withValues(alpha: 0.5))),
               focusedBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(12), borderSide: BorderSide(color: textColor.withValues(alpha: 0.5))),
               isDense: true

+ 161 - 47
lib/src/layouts/web/request_create.dart

@@ -1,5 +1,7 @@
 import 'package:easy_localization/easy_localization.dart';
+import 'package:flutter/cupertino.dart';
 import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
 import 'package:flutter_datetime_picker_plus/flutter_datetime_picker_plus.dart';
 import 'package:image_picker/image_picker.dart';
 import 'package:loading_indicator/loading_indicator.dart';
@@ -10,9 +12,13 @@ import 'package:telnow_mobile_new/src/layouts/functions/request.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/U.dart';
+import 'package:telnow_mobile_new/src/utils/extensions.dart';
 import 'package:telnow_mobile_new/src/utils/provider.dart';
 import 'package:toggle_switch/toggle_switch.dart';
 
+import '../../cubit/pickup_asset_cubit.dart';
+import '../mobile/pickup_asset.dart';
+
 class WebReqCreatePage extends StatefulWidget {
   final Map<String, dynamic> user;
   final Map<String, dynamic> request;
@@ -24,7 +30,7 @@ class WebReqCreatePage extends StatefulWidget {
 }
 
 getColorScheme(val){
-  var color;
+  Color color;
   switch (val){
     case 0: color = Color(0xFF4FB66C); break;
     case 50: color = Color(0xFFFFA800); break;
@@ -38,16 +44,17 @@ class _WebReqCreatePageState extends State<WebReqCreatePage> {
   final RequestFunction reqFunc = RequestFunction();
   final SharedPreferencesManager sharedPreferencesManager = locator<SharedPreferencesManager>();
 
-  TextEditingController controllerDate = new TextEditingController()..text = '';
-  TextEditingController controllerDateString = new TextEditingController()..text = '';
-  TextEditingController controllerNote = new TextEditingController()..text = '';
-  TextEditingController controllerLocation = new TextEditingController()..text = '';
-  TextEditingController controllerUserId = new TextEditingController()..text = '';
-  TextEditingController controllerReferenceNumber = new TextEditingController()..text = '';
+  TextEditingController controllerDate = TextEditingController()..text = '';
+  TextEditingController controllerDateString = TextEditingController()..text = '';
+  TextEditingController controllerNote = TextEditingController()..text = '';
+  TextEditingController controllerLocation = TextEditingController()..text = '';
+  TextEditingController controllerUserId = TextEditingController()..text = '';
+  TextEditingController controllerReferenceNumber = TextEditingController()..text = '';
 
-  FocusNode focusNodeLocation = new FocusNode();
+  FocusNode focusNodeLocation = FocusNode();
   double _currentSliderValue = 0;
   Color sliderColor = getColorScheme(0);
+  Map<String, dynamic> asset = {};
 
   @override
   void initState() {
@@ -83,7 +90,7 @@ class _WebReqCreatePageState extends State<WebReqCreatePage> {
                 GestureDetector(
                   child: Text('buttonBack'.tr(), style: TextStyle(color: primaryColor, fontSize: 14)),
                   onTap: ()=>navigateBack(context),
-                )
+                ).withHover(),
               ],
             ),
           ),
@@ -131,6 +138,7 @@ class _WebReqCreatePageState extends State<WebReqCreatePage> {
                                     Row(
                                       children: [
                                         Container(
+                                          decoration: BoxDecoration(color: Provider.of<CreateSerModule>(context).others() == 0 ? disabledColor : primaryColor, borderRadius: BorderRadius.all(Radius.circular(20))),
                                           child: ToggleSwitch(
                                             cornerRadius: 20,
                                             minWidth: 20,
@@ -150,7 +158,6 @@ class _WebReqCreatePageState extends State<WebReqCreatePage> {
                                               context.read<CreateSerModule>().setOthers(index);
                                             },
                                           ),
-                                          decoration: BoxDecoration(color: Provider.of<CreateSerModule>(context).others() == 0 ? disabledColor : primaryColor, borderRadius: BorderRadius.all(Radius.circular(20))),
                                         ),
                                         SizedBox(width: 8),
                                         Expanded(child: Text(context.watch<CreateSerModule>().others() == 0 ? 'reqForMySelf'.tr() : 'reqForOthers'.tr(), style: TextStyle(color: textColor, fontSize: 12), maxLines: 2, overflow: TextOverflow.ellipsis))
@@ -240,29 +247,30 @@ class _WebReqCreatePageState extends State<WebReqCreatePage> {
                                                     child: Container(
                                                       width: imageWidth, height: imageWidth, alignment: Alignment.topRight,
                                                       margin: EdgeInsets.only(right: i == 4 ? 0 : 6),
+                                                      decoration: BoxDecoration(
+                                                          color: Colors.black12, borderRadius: BorderRadius.all(Radius.circular(5)), border: Border.all(color: Colors.black26, width: 0.5),
+                                                          image: DecorationImage(image: MemoryImage(context.read<CreateSerModule>().images()[i]), fit: BoxFit.cover)
+                                                      ),
                                                       child: Transform.translate(
                                                         offset: Offset(3, -3),
                                                         child: GestureDetector(
                                                           child: Container(
                                                             padding: EdgeInsets.all(3),
-                                                            child: Icon(Icons.close_rounded, color: Colors.white, size: 18),
                                                             decoration: BoxDecoration(color: Colors.black54, border: Border.all(color: Colors.white, width: 2), borderRadius: BorderRadius.all(Radius.circular(50))),
+                                                            child: Icon(Icons.close_rounded, color: Colors.white, size: 18),
                                                           ),
                                                           onTap: ()=>context.read<CreateSerModule>().removeImages(i),
-                                                        ),
-                                                      ),
-                                                      decoration: BoxDecoration(
-                                                          color: Colors.black12, borderRadius: BorderRadius.all(Radius.circular(5)), border: Border.all(color: Colors.black26, width: 0.5),
-                                                          image: DecorationImage(image: MemoryImage(context.read<CreateSerModule>().images()[i]), fit: BoxFit.cover)
+                                                        ).withHover(),
                                                       ),
                                                     ),
                                                     onTap: ()=>navigateTo(context, PhotoPreviewGallery(title: 'image'.tr(), imageList: context.read<CreateSerModule>().images(), startIndex: i, isUrl: false))
-                                                );
+                                                ).withHover();
                                               }),
                                             ),
                                             context.watch<CreateSerModule>().images().length < 5 ? GestureDetector(
                                               child: Container(
                                                 width: imageWidth, height: imageWidth, alignment: Alignment.center,
+                                                decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.all(Radius.circular(5)), border: Border.all(color: Colors.black26, width: 2)),
                                                 child:  context.watch<CreateSerModule>().setLoadingEffect() ? SizedBox(
                                                   height: 30,
                                                   child: LoadingIndicator(
@@ -273,10 +281,9 @@ class _WebReqCreatePageState extends State<WebReqCreatePage> {
                                                     pathBackgroundColor: Colors.black,
                                                   ),
                                                 ) : Icon(Icons.add_rounded, color: Colors.black26, size: 40),
-                                                decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.all(Radius.circular(5)), border: Border.all(color: Colors.black26, width: 2)),
                                               ),
                                               onTap: ()=>pickupImageNew(),
-                                            ) : Container(),
+                                            ).withHover() : Container(),
                                           ],
                                         );
                                       },
@@ -294,9 +301,9 @@ class _WebReqCreatePageState extends State<WebReqCreatePage> {
                                       ),
                                     ),
                                     onTap: ()=>pickupImageNew(),
-                                  ),
+                                  ).withHover(),
                                   // Text("MBUH ==> ${U.newServerVersion(1736473802)} X ${U.retServerVersion()}"),
-                                  U.newServerVersion(1736473802) ? Column(
+                                  Column(
                                     crossAxisAlignment: CrossAxisAlignment.start,
                                     children: [
                                       SizedBox(height: 32),
@@ -357,8 +364,8 @@ class _WebReqCreatePageState extends State<WebReqCreatePage> {
                                           )
                                       )
                                     ],
-                                  ) : SizedBox(),
-                                  U.newServerVersion(1741166029) ? Column(
+                                  ),
+                                  Column(
                                     crossAxisAlignment: CrossAxisAlignment.start,
                                     children: [
                                       SizedBox(height: 32),
@@ -385,7 +392,7 @@ class _WebReqCreatePageState extends State<WebReqCreatePage> {
                                         ),
                                       )
                                     ],
-                                  ) : SizedBox(),
+                                  ),
                                 ],
                               ),
                             ],
@@ -402,6 +409,113 @@ class _WebReqCreatePageState extends State<WebReqCreatePage> {
                         widget.request['autoResponse'] ? Container() : Column(
                           crossAxisAlignment: CrossAxisAlignment.start,
                           children: [
+                            Column(
+                              crossAxisAlignment: CrossAxisAlignment.start,
+                              children: [
+                                // SizedBox(height: 32),
+                                Text(asset.isEmpty ? 'addAsset'.tr() : 'asset'.tr(), style: TextStyle(color: textColor, fontWeight: FontWeight.w600)),
+                                SizedBox(height: 8),
+                                asset.isEmpty ? GestureDetector(
+                                  onTap: () async {
+                                    final res = await Navigator.push(
+                                      context, MaterialPageRoute(
+                                      builder: (_) => BlocProvider(
+                                        create: (_) => AssetCubit()..getData(),
+                                        child: PickupAsset(web: true),
+                                      ),
+                                    ),
+                                    );
+
+                                    if(res != null) {
+                                      setState(() {
+                                        for (var item in res) {
+                                          asset['_mobileImage'] = item['_mobileImage']+'?bridge-cache=true';
+                                          asset['name'] = item['name'];
+                                          asset['code'] = item['code'];
+                                          asset['description'] = item['description'];
+                                        }
+                                      });
+                                    }
+                                  },
+                                  child: Container(
+                                    padding: EdgeInsets.symmetric(horizontal: 13, vertical: 12),
+                                    decoration: BoxDecoration(
+                                        borderRadius: BorderRadius.circular(12),
+                                        border: Border.all(color: Color(0xff262626).withValues(alpha: 0.5))
+                                    ),
+                                    child: Row(
+                                      spacing: 12,
+                                      children: [
+                                        Icon(Icons.widgets_outlined,),
+                                        Text("selectAsset".tr(), style: TextStyle(color: Color(0xff262626).withValues(alpha: 0.5)),),
+                                      ],
+                                    ),
+                                  ),
+                                ).withHover() : Container(
+                                  decoration: BoxDecoration(
+                                    border: Border.all(color: Color(0xff262626).withValues(alpha: 0.5)),
+                                    borderRadius: BorderRadius.circular(12),
+                                  ),
+                                  child: Padding(
+                                    padding: EdgeInsets.symmetric(vertical: 0),
+                                    child: Row(
+                                      spacing: 12,
+                                      children: [
+                                        ClipRRect(
+                                          borderRadius: BorderRadius.circular(12.0),
+                                          child: Image.network(
+                                            asset['_mobileImage'],
+                                            width: 80,
+                                            height: 64,
+                                            fit: BoxFit.cover,
+                                            errorBuilder: (context, error, stackTrace) =>
+                                            const Icon(Icons.broken_image, size: 60, color: Colors.grey),
+                                            loadingBuilder: (context, child, loadingProgress) {
+                                              if (loadingProgress == null) return child;
+                                              return const SizedBox(
+                                                width: 80,
+                                                height: 64,
+                                                child: Center(child: CupertinoActivityIndicator()),
+                                              );
+                                            },
+                                          ),
+                                        ),
+                                        Expanded(
+                                          child: Column(
+                                            crossAxisAlignment: CrossAxisAlignment.start,
+                                            spacing: 4,
+                                            children: [
+                                              Text(asset['name'],
+                                                maxLines: 1,
+                                                overflow: TextOverflow.ellipsis,
+                                                style: TextStyle(
+                                                  color: textColor,
+                                                  fontSize: 14,
+                                                  fontWeight: FontWeight.w600,
+                                                ),),
+                                              Text(asset['description'],
+                                                  maxLines: 2,
+                                                  overflow: TextOverflow.ellipsis,
+                                                  style: TextStyle(color: textColor, fontSize: 14)),
+                                            ],
+                                          ),
+                                        ),
+                                        GestureDetector(
+                                          onTap: () => setState(() {
+                                            asset = {};
+                                          }),
+                                          child: Padding(
+                                            padding: const EdgeInsets.all(12.0),
+                                            child: Icon(Icons.delete_rounded, size: 24, color: Colors.red.withValues(alpha: 0.85),),
+                                          ),
+                                        ).withHover()
+                                      ],
+                                    ),
+                                  ),
+                                )
+                              ],
+                            ),
+                            SizedBox(height: 24,),
                             Text('yourLocation'.tr(), style: TextStyle(color: textColor, fontWeight: FontWeight.w600)),
                             !widget.request['scanToRequest'] ? GestureDetector(
                               child: Container(
@@ -431,7 +545,7 @@ class _WebReqCreatePageState extends State<WebReqCreatePage> {
                               onTap: (){
                                 if(!widget.request['scanToRequest']) Provider.of<CreateSerModule>(context, listen: false).setLocationType(1);
                               },
-                            ) : Container(),
+                            ).withHover() : Container(),
 
                             GestureDetector(
                               child: Container(
@@ -497,7 +611,7 @@ class _WebReqCreatePageState extends State<WebReqCreatePage> {
                               onTap: (){
                                 context.read<CreateSerModule>().setLocationType(2);
                               },
-                            ),
+                            ).withHover(),
                           ],
                         ),
                         widget.request['canNotCancel'] ? Padding(
@@ -545,7 +659,7 @@ class _WebReqCreatePageState extends State<WebReqCreatePage> {
                               } else if (controllerDateString.text.trim().isNotEmpty && widget.request['noteFormat'] == 'DATE'){
                                 dialogSendLater();
                               } else {
-                                reqFunc.sendRequest(context, widget, controllerNote, controllerReferenceNumber, controllerLocation, controllerDateString, _currentSliderValue);
+                                reqFunc.sendRequest(context, widget, controllerNote, controllerReferenceNumber, controllerLocation, controllerDateString, _currentSliderValue, asset['code']);
                               }
                             } else {
                               showError(context, 'lengthMax'.tr());
@@ -584,14 +698,6 @@ class _WebReqCreatePageState extends State<WebReqCreatePage> {
                   child: GestureDetector(
                     child: Container(
                       padding: EdgeInsets.symmetric(vertical: 20),
-                      child: Column(
-                        mainAxisSize: MainAxisSize.min,
-                        children: [
-                          U.iconsax('timer-start', color: Colors.white, size: 30),
-                          SizedBox(height: 9),
-                          Text('scheduled'.tr(), style: TextStyle(color: Colors.white, fontSize: 14))
-                        ],
-                      ),
                       decoration: BoxDecoration(
                           borderRadius: BorderRadius.all(Radius.circular(12)),
                           gradient: LinearGradient(
@@ -601,27 +707,27 @@ class _WebReqCreatePageState extends State<WebReqCreatePage> {
                               ]
                           )
                       ),
+                      child: Column(
+                        mainAxisSize: MainAxisSize.min,
+                        children: [
+                          U.iconsax('timer-start', color: Colors.white, size: 30),
+                          SizedBox(height: 9),
+                          Text('scheduled'.tr(), style: TextStyle(color: Colors.white, fontSize: 14))
+                        ],
+                      ),
                     ),
                     onTap: (){
                       navigateBack(contexts);
                       Provider.of<CreateSerModule>(context, listen: false).setSendLater(true);
-                      reqFunc.sendRequest(context, widget, controllerNote, controllerLocation, controllerReferenceNumber, controllerDateString, _currentSliderValue);
+                      reqFunc.sendRequest(context, widget, controllerNote, controllerLocation, controllerReferenceNumber, controllerDateString, _currentSliderValue, asset['code']);
                     },
-                  ),
+                  ).withHover(),
                 ),
                 SizedBox(width: 16),
                 Expanded(
                   child: GestureDetector(
                     child: Container(
                       padding: EdgeInsets.symmetric(vertical: 20),
-                      child: Column(
-                        mainAxisSize: MainAxisSize.min,
-                        children: [
-                          U.iconsax('star-1', color: Colors.white, size: 30),
-                          SizedBox(height: 9),
-                          Text('sendNow'.tr(), style: TextStyle(color: Colors.white, fontSize: 14))
-                        ],
-                      ),
                       decoration: BoxDecoration(
                           borderRadius: BorderRadius.all(Radius.circular(12)),
                           gradient: LinearGradient(
@@ -631,12 +737,20 @@ class _WebReqCreatePageState extends State<WebReqCreatePage> {
                               ]
                           )
                       ),
+                      child: Column(
+                        mainAxisSize: MainAxisSize.min,
+                        children: [
+                          U.iconsax('star-1', color: Colors.white, size: 30),
+                          SizedBox(height: 9),
+                          Text('sendNow'.tr(), style: TextStyle(color: Colors.white, fontSize: 14))
+                        ],
+                      ),
                     ),
                     onTap: (){
                       navigateBack(contexts);
-                      reqFunc.sendRequest(context, widget, controllerNote, controllerReferenceNumber, controllerLocation, controllerDateString, _currentSliderValue);
+                      reqFunc.sendRequest(context, widget, controllerNote, controllerReferenceNumber, controllerLocation, controllerDateString, _currentSliderValue, asset['code']);
                     },
-                  ),
+                  ).withHover(),
                 ),
               ],
             ),

+ 3 - 2
lib/src/layouts/web/request_select.dart

@@ -7,6 +7,7 @@ import 'package:telnow_mobile_new/src/layouts/functions/request.dart';
 import 'package:telnow_mobile_new/src/layouts/components/template.dart';
 import 'package:telnow_mobile_new/src/layouts/web/request_create.dart';
 import 'package:telnow_mobile_new/src/utils/U.dart';
+import 'package:telnow_mobile_new/src/utils/extensions.dart';
 import 'package:telnow_mobile_new/src/utils/provider.dart';
 
 class WebReqSelectPage extends StatefulWidget {
@@ -96,7 +97,7 @@ class _WebReqSelectPageState extends State<WebReqSelectPage> {
                 GestureDetector(
                   child: Text('buttonBack'.tr(), style: TextStyle(color: primaryColor, fontSize: 14)),
                   onTap: ()=>navigateBack(context),
-                )
+                ).withHover()
               ],
             ),
           ),
@@ -160,7 +161,7 @@ class _WebReqSelectPageState extends State<WebReqSelectPage> {
                             ),
                           ),
                           onTap: ()=>navigateTo(context, WebReqCreatePage(user: widget.user, request: Provider.of<RequestModule>(context, listen: false).data()[i], fromSearch: true)),
-                        );
+                        ).withHover();
                       }),
                     );
                   },

+ 78 - 8
lib/src/layouts/web/request_success.dart

@@ -2,6 +2,7 @@ import 'dart:convert';
 import 'dart:io';
 
 import 'package:easy_localization/easy_localization.dart';
+import 'package:flutter/cupertino.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter_linkify/flutter_linkify.dart';
 import 'package:open_file/open_file.dart';
@@ -10,6 +11,8 @@ import 'package:telnow_mobile_new/src/layouts/components/template.dart';
 import 'package:telnow_mobile_new/src/utils/U.dart';
 import 'package:url_launcher/url_launcher.dart';
 
+import '../functions/detail.dart';
+
 class WebReqSuccessPage extends StatefulWidget {
   final Map<String, dynamic> user;
   final String ticketNo;
@@ -22,8 +25,11 @@ class WebReqSuccessPage extends StatefulWidget {
 
 class _WebReqSuccessPageState extends State<WebReqSuccessPage> {
   final ApiAuthProvider apiAuthProvider = ApiAuthProvider();
+  final DetailFunction detFunc = DetailFunction();
 
   Map<String, dynamic> list = {};
+  String baseUrl = '';
+
 
   @override
   void initState() {
@@ -33,7 +39,8 @@ class _WebReqSuccessPageState extends State<WebReqSuccessPage> {
   }
 
   getMission() async{
-    var data = await apiAuthProvider.getData('/api/requestHistories/'+widget.ticketNo, null);
+    baseUrl = await detFunc.getBaseUrl();
+    var data = await apiAuthProvider.getData('/api/requestHistories/${widget.ticketNo}', null);
     if(data != null) {
       if (data['datetimeScheduled'] != null && data['datetimeScheduled'] != '' && data['noteFormat'] == 'DATE') {
         var date = data['datetimeScheduled'];
@@ -43,7 +50,7 @@ class _WebReqSuccessPageState extends State<WebReqSuccessPage> {
       if (data['noteStart'] == 'escalationNoteBySystem'){
         data['noteStart'] = 'escalationNoteBySystem'.tr();
       }
-
+// data.forEach((k,v)=>debugPrint("$k : $v"));
       setState((){
         list = data;
       });
@@ -52,7 +59,7 @@ class _WebReqSuccessPageState extends State<WebReqSuccessPage> {
 
   backAction(){
     int count = 0;
-    int page = widget.fromSearch ? 3 : 2;
+    int page = widget.fromSearch ? 3 : 1;
     Navigator.of(context).popUntil((_) => count++ >= page);
   }
 
@@ -187,6 +194,69 @@ class _WebReqSuccessPageState extends State<WebReqSuccessPage> {
                         child: Column(
                           crossAxisAlignment: CrossAxisAlignment.start,
                           children: [
+                            if(list['_asset'] != null) ...[
+                              Column(
+                                spacing: 6,
+                                crossAxisAlignment: CrossAxisAlignment.start,
+                                children: [
+                                  Text('asset'.tr(), style: TextStyle(color: textColor, fontWeight: FontWeight.w600,),),
+                                  Container(
+                                    decoration: BoxDecoration(
+                                      border: Border.all(color: Color(0xff262626).withValues(alpha: 0.1)),
+                                      borderRadius: BorderRadius.circular(12),
+                                    ),
+                                    child: Padding(
+                                      padding: EdgeInsets.symmetric(vertical: 0),
+                                      child: Row(
+                                        spacing: 12,
+                                        children: [
+                                          ClipRRect(
+                                            borderRadius: BorderRadius.circular(12.0),
+                                            child: Image.network(
+                                              baseUrl + list['_asset']['image'],
+                                              width: 80,
+                                              height: 64,
+                                              fit: BoxFit.cover,
+                                              errorBuilder: (context, error, stackTrace) =>
+                                              const Icon(Icons.broken_image, size: 60, color: Colors.grey),
+                                              loadingBuilder: (context, child, loadingProgress) {
+                                                if (loadingProgress == null) return child;
+                                                return const SizedBox(
+                                                  width: 80,
+                                                  height: 64,
+                                                  child: Center(child: CupertinoActivityIndicator()),
+                                                );
+                                              },
+                                            ),
+                                          ),
+                                          Expanded(
+                                            child: Column(
+                                              crossAxisAlignment: CrossAxisAlignment.start,
+                                              spacing: 4,
+                                              children: [
+                                                Text(list['_asset']['name'],
+                                                  maxLines: 1,
+                                                  overflow: TextOverflow.ellipsis,
+                                                  style: TextStyle(
+                                                    color: textColor,
+                                                    fontSize: 14,
+                                                    fontWeight: FontWeight.w600,
+                                                  ),),
+                                                Text(list['_asset']['description'],
+                                                    maxLines: 2,
+                                                    overflow: TextOverflow.ellipsis,
+                                                    style: TextStyle(color: textColor, fontSize: 14)),
+                                              ],
+                                            ),
+                                          ),
+                                        ],
+                                      ),
+                                    ),
+                                  ),
+                                ],
+                              ),
+                              SizedBox(height: 24,),
+                            ],
                             infoContainer('reqSuccessMsg'.tr()),
                             SizedBox(height: 16),
                             buttonTemplate(text: 'btnWait'.tr(), action: ()=>backAction(), width: double.infinity)
@@ -356,6 +426,11 @@ class _WebReqSuccessPendingPageState extends State<WebReqSuccessPendingPage> {
                               Container(
                                 width: double.infinity,
                                 padding: EdgeInsets.all(12),
+                                decoration: BoxDecoration(
+                                    color: Colors.red.withValues(alpha: 0.1),
+                                    border: Border.all(color: Colors.red),
+                                    borderRadius: BorderRadius.all(Radius.circular(12))
+                                ),
                                 child: Column(
                                   crossAxisAlignment: CrossAxisAlignment.center,
                                   children: [
@@ -364,11 +439,6 @@ class _WebReqSuccessPendingPageState extends State<WebReqSuccessPendingPage> {
                                     Text('pending_info_success'.tr(), style: TextStyle(color: textColor), textAlign: TextAlign.center)
                                   ],
                                 ),
-                                decoration: BoxDecoration(
-                                    color: Colors.red.withValues(alpha: 0.1),
-                                    border: Border.all(color: Colors.red),
-                                    borderRadius: BorderRadius.all(Radius.circular(12))
-                                ),
                               ),
                               SizedBox(height: 16),
                               buttonTemplate(text: 'btnWait'.tr(), action: ()=>backAction(), width: double.infinity)

+ 243 - 0
lib/src/repository/history_repository.dart

@@ -0,0 +1,243 @@
+import 'dart:io';
+
+import 'package:easy_localization/easy_localization.dart';
+import 'package:flutter/material.dart';
+import 'package:telnow_mobile_new/src/api/jwt_token.dart';
+import 'package:translator/translator.dart';
+
+import '../api/api_auth_provider.dart';
+import '../utils/U.dart';
+import '../utils/cache_manager.dart';
+
+class HistoryRepository {
+  final ApiAuthProvider _apiAuthProvider = ApiAuthProvider();
+  final translator = GoogleTranslator();
+  final JwtToken token = JwtToken();
+
+  //## cuma request doang, balikin hasil request ke cubit
+  Future<List<dynamic>> getData(String key, String filter, int page, int size,
+      List<dynamic> activeForum) async {
+    try {
+      String url = '/api/requestHistories/search/myReqHistory';
+      var sort = ['datetimeRequest,desc'];
+
+      var mission = await _apiAuthProvider.getData(url, {
+        'size': size.toString(),
+        'page': page.toString(),
+        'sort': sort,
+        'filter': filter
+      });
+      List tempData = [];
+
+      if (mission != null) {
+        if (mission.containsKey('_embedded')) {
+          for (int i = 0; i <
+              mission['_embedded']['requestHistories'].length; i++) {
+            var isFrm = false;
+            String id = "";
+            String msg = "";
+
+            activeForum.forEach((el) {
+              if (el['ticketId'] ==
+                  mission['_embedded']['requestHistories'][i]['ticketNo']) {
+                id = el['id'];
+                msg = el['desc'];
+              }
+            });
+
+            if (id != "") isFrm = true;
+            mission['_embedded']['requestHistories'][i]['_hasForum'] = isFrm;
+            mission['_embedded']['requestHistories'][i]['_forumId'] = id;
+            mission['_embedded']['requestHistories'][i]['_forumMsg'] = msg;
+
+            tempData.add(mission['_embedded']['requestHistories'][i]);
+          }
+        }
+      }
+
+      // # cache manager
+      CacheMan.writeData(key, tempData);
+
+      return tempData;
+    } catch (e) {
+      debugPrint(e.toString());
+    }
+
+    return [];
+  }
+
+  deleteData(List<String> params) async {
+    var res = await _apiAuthProvider.postData(
+        "/api/requestHistories/deleteMyHistory", {"ticketNumbers": params},
+        null);
+
+    if (res != null) {
+      return res;
+    }
+
+    return null;
+  }
+
+  Future<List<dynamic>> getActiveForum(String url) async {
+    try {
+      var data = await _apiAuthProvider.getData(url, null);
+      if (data != null) {
+        // # caching disini
+        CacheMan.writeData(url, data);
+
+        return data;
+      }
+    } catch (e) {
+      debugPrint(e.toString());
+    }
+
+    return [];
+  }
+
+  Future<Map<String, dynamic>> checkRequest(String filter) async {
+    try {
+      var res = await _apiAuthProvider.getData(
+          '/api/requests/search/customFind', {'filter': filter});
+      return res;
+    } catch (e) {
+      debugPrint(e.toString());
+    }
+    return {};
+  }
+
+  Future<Map<String, dynamic>> getDetail(String ticketNo, String locale) async {
+    try {
+      var data = await getByTicketNo(ticketNo);
+
+      if (data['datetimeScheduled'] != null &&
+          data['datetimeScheduled'] != '' && data['noteFormat'] == 'DATE') {
+        var date = data['datetimeScheduled'];
+        data['datetimeScheduled'] =
+            DateFormat('dd MMM yyyy HH:mm', 'id').format(DateTime.parse(date));
+      }
+
+      data['noteStartTranslate'] = '';
+      data['noteFinishTranslate'] = '';
+      data['noteCompleteTranslate'] = '';
+      data['noteCancelTranslate'] = '';
+
+      if (locale == 'zh') locale = 'zh-cn';
+
+      if (data['noteStart'] == 'transferNoteBySystem') {
+        data['noteStart'] = 'transferNoteBySystem'.tr();
+      } else if (data['noteStart'] == 'escalationNoteBySystem') {
+        data['noteStart'] = 'escalationNoteBySystem'.tr();
+      } else {
+        if (U.autoTranslate() && data['noteStart'] != null &&
+            data['noteStart'] != '') {
+          var translate = await translator.translate(
+              data['noteStart'], to: locale);
+          data['noteStartTranslate'] = translate.text;
+        }
+      }
+
+      if (U.autoTranslate() && data['noteFinish'] != null &&
+          data['noteFinish'] != '') {
+        var translate = await translator.translate(
+            data['noteFinish'], to: locale);
+        data['noteFinishTranslate'] = translate.text;
+      }
+      if (U.autoTranslate() && data['noteComplete'] != null &&
+          data['noteComplete'] != '') {
+        var translate = await translator.translate(
+            data['noteComplete'], to: locale);
+        data['noteCompleteTranslate'] = translate.text;
+      }
+      if (U.autoTranslate() && data['noteCancel'] != null &&
+          data['noteCancel'] != '') {
+        var translate = await translator.translate(
+            data['noteCancel'], to: locale);
+        data['noteCancelTranslate'] = translate.text;
+      }
+      data['_collaboratorDataFilter'] = data['_collaboratorData']
+          .where((el) => el['status'] == 'ACCEPTED')
+          .toList();
+
+      return data;
+      //   {
+      //   'list': data
+      // };
+    } catch (e) {
+      debugPrint(e.toString());
+    }
+    return {};
+  }
+
+  Future<dynamic> getByTicketNo(String ticketNo) async {
+    Map<String, dynamic> res = {};
+    try {
+      var data = await _apiAuthProvider.getData(
+          '/api/requestHistories/$ticketNo', null);
+
+      if (data != null) {
+        res = data;
+      }
+    } catch (e) {
+      debugPrint(e.toString());
+    }
+    return res;
+  }
+
+  getFileName(pdfUrl){
+    var imgSplit = pdfUrl.toString().split('/');
+    return imgSplit[imgSplit.length-1];
+  }
+
+  Future<dynamic> getPath(Map<String, dynamic> data) async {
+    String path = await token.getPath();
+    var filePath = '$path/TelNow/Files/';
+
+    if(!File(filePath + getFileName(data['responseAttachment'])).existsSync()){
+      await _apiAuthProvider.downloadImage(data['responseAttachment'], filePath + getFileName(data['responseAttachment']));
+    }
+
+    return filePath + getFileName(data['responseAttachment']);
+  }
+
+  Future<Map<String, dynamic>> setAsset(String ticketNo, Map<String, dynamic> data, String baseUrl) async {
+    Map<String, dynamic> asset = {};
+
+    var params = {'assetCode': data['code']};
+    try{
+      var res = await _apiAuthProvider.postData('/api/requestHistories/$ticketNo/asset/add', null, params);
+
+      if (res != null){
+        if (data['code'] != null){
+          asset = data;
+        }
+      }
+
+      return asset;
+    }catch(e){
+      return asset;
+    }
+
+  }
+
+  Future<dynamic> cancelRequest(list, Map<String, dynamic> data) async {
+    var res = {};
+
+    try{
+      res = await _apiAuthProvider.postData('/api/requestHistories/search/request/cancel/${list['ticketNo']}', null, data);
+    }catch(e){}
+
+    return res;
+  }
+
+
+  Future<String> getBaseUrl() async {
+    try {
+      return '${U.decodeBase64Url(U.getBaseUrl()!)}${U.decodeBase64Url(
+          U.getAccessCode()!)}';
+    }catch(e) {
+      debugPrint(e.toString());
+    }
+    return '';
+  }
+
+}

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

@@ -5,8 +5,8 @@ enum VersionKey {
 
 class C{
 
-  static const Map<String, int> version = {
-    'multiBahasa': 1754624839 //penambahan jadi 10 bahasa, identifikasi berdasarkan ordinal 1,2,3
+  static Map<String, int> version = {
+    VersionKey.multiBahasa.name: 1754624839 //penambahan jadi 10 bahasa, identifikasi berdasarkan ordinal 1,2,3
   };
 
   static int get(String key) => version[key]?? 0;

+ 14 - 20
lib/src/utils/U.dart

@@ -316,7 +316,7 @@ class U {
     try {
       var dt = await ApiAuthProvider().getJsonDataNoAuth(url);
       _serverVersion = dt['serverVersion'];
-      validLang = newServerVersion(1754624839) ? dt["_validLang"] : dt['languages'];
+      validLang = dt["_validLang"];
       CacheMan.writeData(url, _serverVersion);
       _versionReady.complete();
     } catch (error) {
@@ -356,12 +356,8 @@ class U {
     return validLang;
   }
 
-  static newServerVersion(int version){
-    return version <= _serverVersion;
-  }
-
   static final Map<String, Future<bool>> _compatibilityCache = {};
-  static Future<bool> isCompatibleWith(VersionKey key) {
+  static Future<bool> isCompatibleWithX(VersionKey key) {
     final keyName = key.name.toString();
     if (_compatibilityCache.containsKey(keyName)) {
       return _compatibilityCache[keyName]!;
@@ -391,11 +387,9 @@ class U {
 
   static Map _otherLabelList = {};
   static getOtherLabelList(BuildContext context) async{
-    if(newServerVersion(1725245109)){
-      var res = await ApiAuthProvider().getData('/api/systemSettings/search/additional', {'key': 'request-for-other'});
-      if(res != null){
-        _otherLabelList = res;
-      }
+    var res = await ApiAuthProvider().getData('/api/systemSettings/search/additional', {'key': 'request-for-other'});
+    if(res != null){
+      _otherLabelList = res;
     }
   }
 
@@ -510,15 +504,15 @@ class U {
   }
 
   static List<Color> defaultRainbowColors() {
-      return [
-        Colors.red,
-        Colors.orange,
-        Colors.yellow,
-        Colors.green,
-        Colors.blue,
-        Colors.indigo,
-        Colors.purple,
-      ];
+    return [
+      Colors.red,
+      Colors.orange,
+      Colors.yellow,
+      Colors.green,
+      Colors.blue,
+      Colors.indigo,
+      Colors.purple,
+    ];
   }
 
   static List<Color> loadingIndicatorColors() {

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

@@ -63,7 +63,7 @@ class DioLoggingInterceptors extends InterceptorsWrapper {
         await _sharedPreferencesManager.putInt(SharedPreferencesManager.keyCountRefreshToken, refreshCount!+1);
       }
     } catch (error) {
-      print("Error dio: ${error.toString()}");
+      debugPrint("Error dio: ${error.toString()}");
       eventBus.fire("logout");
       // handlingError(NavigationService.navigatorKey.currentContext, 3);
     }

+ 10 - 0
lib/src/utils/extensions.dart

@@ -0,0 +1,10 @@
+import 'package:flutter/material.dart';
+
+extension HoverExtension on GestureDetector {
+  Widget withHover() {
+    return MouseRegion(
+      cursor: SystemMouseCursors.click,
+      child: this,
+    );
+  }
+}

+ 34 - 26
pubspec.lock

@@ -213,42 +213,42 @@ packages:
     dependency: "direct main"
     description:
       name: camera
-      sha256: d6ec2cbdbe2fa8f5e0d07d8c06368fe4effa985a4a5ddade9cc58a8cd849557d
+      sha256: "034c38cb8014d29698dcae6d20276688a1bf74e6487dfeb274d70ea05d5f7777"
       url: "https://pub.dev"
     source: hosted
-    version: "0.11.2"
+    version: "0.12.0+1"
   camera_android:
     dependency: "direct main"
     description:
       name: camera_android
-      sha256: "4f40d053a67e99029b5be7f00ef8047b63edb65ccc4e2546b84d47e302c6bf62"
+      sha256: "6b2e240022c61bc89711717c59264a2650c569d2dd4bf513228bd1fc45e189e0"
       url: "https://pub.dev"
     source: hosted
-    version: "0.10.10+4"
+    version: "0.10.10+16"
   camera_android_camerax:
     dependency: transitive
     description:
       name: camera_android_camerax
-      sha256: "7cc6adf1868bdcf4e63a56b24b41692dfbad2bec1cdceea451c77798f6a605c3"
+      sha256: b5064cf25a2787d122d0bf12e77c7b1033a2b983d0730e3091f770ee376efde5
       url: "https://pub.dev"
     source: hosted
-    version: "0.6.13"
+    version: "0.7.2"
   camera_avfoundation:
     dependency: transitive
     description:
       name: camera_avfoundation
-      sha256: eff7ed630b1ac3994737c790368fe006388ad9f271d7148e432263721e45dc75
+      sha256: "90e4cc3fde331581a3b2d35d83be41dbb7393af0ab857eb27b732174289cb96d"
       url: "https://pub.dev"
     source: hosted
-    version: "0.9.18+7"
+    version: "0.10.1"
   camera_platform_interface:
     dependency: transitive
     description:
       name: camera_platform_interface
-      sha256: "2f757024a48696ff4814a789b0bd90f5660c0fb25f393ab4564fb483327930e2"
+      sha256: "7ac852d77699acee79f0d438b793feee26721841e50973576419ff5c6d95e9b7"
       url: "https://pub.dev"
     source: hosted
-    version: "2.10.0"
+    version: "2.13.0"
   camera_web:
     dependency: transitive
     description:
@@ -277,10 +277,10 @@ packages:
     dependency: transitive
     description:
       name: characters
-      sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803
+      sha256: faf38497bda5ead2a8c7615f4f7939df04333478bf32e4173fcb06d428b5716b
       url: "https://pub.dev"
     source: hosted
-    version: "1.4.0"
+    version: "1.4.1"
   checked_yaml:
     dependency: transitive
     description:
@@ -481,6 +481,14 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "3.4.0"
+  equatable:
+    dependency: "direct main"
+    description:
+      name: equatable
+      sha256: "3e0141505477fd8ad55d6eb4e7776d3fe8430be8e497ccb1521370c3f21a3e2b"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.0.8"
   event_bus:
     dependency: "direct main"
     description:
@@ -1033,26 +1041,26 @@ packages:
     dependency: transitive
     description:
       name: matcher
-      sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2
+      sha256: dc0b7dc7651697ea4ff3e69ef44b0407ea32c487a39fff6a4004fa585e901861
       url: "https://pub.dev"
     source: hosted
-    version: "0.12.17"
+    version: "0.12.19"
   material_color_utilities:
     dependency: transitive
     description:
       name: material_color_utilities
-      sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec
+      sha256: "9c337007e82b1889149c82ed242ed1cb24a66044e30979c44912381e9be4c48b"
       url: "https://pub.dev"
     source: hosted
-    version: "0.11.1"
+    version: "0.13.0"
   meta:
     dependency: transitive
     description:
       name: meta
-      sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c
+      sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394"
       url: "https://pub.dev"
     source: hosted
-    version: "1.16.0"
+    version: "1.17.0"
   mime:
     dependency: transitive
     description:
@@ -1065,10 +1073,10 @@ packages:
     dependency: "direct main"
     description:
       name: mobile_scanner
-      sha256: "91d28b825784e15572fdc39165c5733099ce0e69c6f6f0964ebdbf98a62130fd"
+      sha256: c92c26bf2231695b6d3477c8dcf435f51e28f87b1745966b1fe4c47a286171ce
       url: "https://pub.dev"
     source: hosted
-    version: "6.0.6"
+    version: "7.2.0"
   nested:
     dependency: transitive
     description:
@@ -1417,10 +1425,10 @@ packages:
     dependency: "direct main"
     description:
       name: searchfield
-      sha256: c06d4e7b916472c60926a2b79656e0c55480d60a06aef542d1e8708567da90ad
+      sha256: "09231f4b86c78e2ae03c1ce83b0a9facd44b2ffa8fd9208175a97736092742ba"
       url: "https://pub.dev"
     source: hosted
-    version: "1.3.5"
+    version: "2.0.0"
   selectable_autolink_text:
     dependency: "direct main"
     description:
@@ -1638,10 +1646,10 @@ packages:
     dependency: transitive
     description:
       name: test_api
-      sha256: "522f00f556e73044315fa4585ec3270f1808a4b186c936e612cab0b565ff1e00"
+      sha256: "8161c84903fd860b26bfdefb7963b3f0b68fee7adea0f59ef805ecca346f0c7a"
       url: "https://pub.dev"
     source: hosted
-    version: "0.7.6"
+    version: "0.7.10"
   timelines_plus:
     dependency: "direct main"
     description:
@@ -1947,5 +1955,5 @@ packages:
     source: hosted
     version: "3.1.1"
 sdks:
-  dart: ">=3.8.0-0 <4.0.0"
-  flutter: ">=3.27.0"
+  dart: ">=3.9.0 <4.0.0"
+  flutter: ">=3.41.0"

+ 7 - 6
pubspec.yaml

@@ -16,8 +16,8 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
 # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
 # In Windows, build-name is used as the major, minor, and patch parts
 # of the product and file versions while build-number is used as the build suffix.
-#version: 4.0.16+50
-version: 4.0.17+51
+#version: 4.0.17+52
+version: 4.0.17+53
 
 environment:
   sdk: ^3.6.1
@@ -69,8 +69,8 @@ dependencies:
   synchronized: ^3.3.0+3
 
   # 📁 File & Media Handling
-  camera: ^0.11.2
-  camera_android: ^0.10.10+4
+  camera: ^0.12.0+1
+  camera_android: ^0.10.10+16
   file_picker: ^9.0.0
   image: ^4.5.2
   image_picker: ^1.1.2
@@ -97,13 +97,13 @@ dependencies:
   dotted_line: ^3.2.3
   drag_and_drop_lists: ^0.4.2
   lazy_load_scrollview: ^1.3.0
-  searchfield: ^1.2.5
+  searchfield: ^2.0.0
   selectable_autolink_text: ^2.6.0
   timelines_plus: ^1.0.6
 
   # 📱 Device & Permissions
   app_settings: ^5.1.1
-  mobile_scanner: ^6.0.6
+  mobile_scanner: ^7.2.0
   permission_handler: ^11.3.1
   url_launcher: ^6.3.1
 
@@ -124,6 +124,7 @@ dependencies:
   upgrader: ^11.3.1
   youtube_player_iframe: ^5.2.1
   lazy_load_indexed_stack: ^1.2.1
+  equatable: ^2.0.8
 
 dev_dependencies:
   flutter_test: