Compare commits

...

75 Commits

Author SHA1 Message Date
haroon amjad 11155457b8 Update to stores VersionID 10.1 4 weeks ago
haroon amjad bea191e987 Merge branch 'flutter_upgrade_with_timesheet_changes' 4 weeks ago
haroon amjad 89b77c205b Merge branch 'master' of http://34.17.182.140/Haroon6138/mohemm-flutter-app 4 weeks ago
Sultan khan bfd1ce2eab add family member issue fixed. 1 month ago
haroon amjad 64e2b2c42a updates 1 month ago
Sultan khan d2eaa863d6 Merge branch 'master' of http://34.17.182.140/Haroon6138/mohemm-flutter-app into flutter_upgrade_with_timesheet_changes
* 'master' of http://34.17.182.140/Haroon6138/mohemm-flutter-app:
  CEI, worklist po pr filter, date issue in absence dynamic screen
  PR changes done.
  fixes for monthly calendar color coding .. and ticket screen
1 month ago
Sultan khan 8812decd6e Merge branch 'master' of http://34.17.182.140/Haroon6138/mohemm-flutter-app into flutter_upgrade_with_timesheet_changes
* 'master' of http://34.17.182.140/Haroon6138/mohemm-flutter-app:
  Timer Counter & Dead line Counter Null Handling
  update to stores, VersionID 10.0
  ENSAT, Notification Timer Counter & Dead Line
  calendar issue fixed and courses enabled.
  Update to stores, VersionID 9.9
  ticket enable
1 month ago
Sultan khan a9f0cb8216 CEI, worklist po pr filter, date issue in absence dynamic screen 1 month ago
Sultan khan f218dab93e PR changes done. 3 months ago
Sultan khan a5e0e1165e Merge branch 'master' of http://34.17.182.140/Haroon6138/mohemm-flutter-app
* 'master' of http://34.17.182.140/Haroon6138/mohemm-flutter-app:
  Timer Counter & Dead line Counter Null Handling
3 months ago
aamir-csol e9fc205bee Timer Counter & Dead line Counter Null Handling 5 months ago
Sultan khan a37ce5c666 Merge branch 'master' of http://34.17.182.140/Haroon6138/mohemm-flutter-app
* 'master' of http://34.17.182.140/Haroon6138/mohemm-flutter-app:
  update to stores, VersionID 10.0
  ENSAT, Notification Timer Counter & Dead Line

# Conflicts:
#	lib/ui/screens/ticket/ticket_detailed_screen.dart
5 months ago
Sultan khan a6454776dd fixes for monthly calendar color coding .. and ticket screen 5 months ago
haroon amjad 72656a3564 update to stores, VersionID 10.0 6 months ago
aamir-csol 1d3f33ea81 ENSAT, Notification Timer Counter & Dead Line 6 months ago
Sultan khan 4a09bbdf1b Merge branch 'master' of http://34.17.182.140/Haroon6138/mohemm-flutter-app 6 months ago
Sultan khan 2c2d16674e calendar issue fixed and courses enabled. 6 months ago
haroon amjad 9763c7c014 Update to stores, VersionID 9.9 6 months ago
Sultan khan 33829a2ab3 Merge branch 'master' of http://34.17.182.140/Haroon6138/mohemm-flutter-app
* 'master' of http://34.17.182.140/Haroon6138/mohemm-flutter-app:
  ticket enable
  dashboard
  dashboard
  Ticket
  Ticket
  color coding changes on the monthly leave calendar and prod e-learning URL added.
  VHR-279
  VHR-279
  Alma
  Banner updates, VersionID 9.7 sent to stores
  updates
  Etqan fixes, Update to Stores VersionID 9.6
  updates
  Greeting
  Greeting Card
  Ticket Attachments
  Survey title key fix
6 months ago
Aamir Saleem Ahmad 598ce5d7fe ticket enable 6 months ago
aamir-csol 8260a65bdd dashboard 6 months ago
aamir-csol de3f091ef1 dashboard 6 months ago
aamir-csol 279fbc85d1 Merge branch 'master' into flutter_upgrade_with_timesheet_changes 6 months ago
aamir-csol ecc0869a23 Ticket 6 months ago
aamir-csol 90faa4dd5e Merge branch 'Courses-CR#-7150' into flutter_upgrade_with_timesheet_changes
# Conflicts:
#	lib/api/api_client.dart
#	lib/api/dashboard_api_client.dart
#	lib/classes/consts.dart
#	lib/ui/landing/dashboard_screen.dart
#	lib/ui/landing/widget/app_drawer.dart
#	lib/ui/screens/ticket/ticket_detailed_screen.dart
#	lib/widgets/sso_webview_widget.dart
6 months ago
aamir-csol e1f2819fe6 Ticket 6 months ago
Sultan khan 8ea831c2c4 color coding changes on the monthly leave calendar and prod e-learning URL added. 6 months ago
aamir-csol a131179c71 VHR-279 6 months ago
aamir-csol 9f4e9943cf VHR-279 6 months ago
aamir-csol deffeda015 Alma 6 months ago
Haroon Amjad 5ad012d602 Banner updates, VersionID 9.7 sent to stores 7 months ago
haroon amjad 3391cf49ef updates 7 months ago
haroon amjad 057e71e3c0 Etqan fixes, Update to Stores VersionID 9.6 7 months ago
haroon amjad bdaccf133c updates 7 months ago
Haroon6138 16e2cc604f Merge pull request 'Courses-CR#-7150' (#20) from Courses-CR#-7150 into master
Reviewed-on: https://34.17.182.140/Haroon6138/mohemm-flutter-app/pulls/20
7 months ago
Sultan khan d5c3ce4c62 Merge branch 'master' into Courses-CR#-7150
* master:
7 months ago
Sultan khan 5da81968d7 Merge branch 'greeting_card' into Courses-CR#-7150
* greeting_card:
  Greeting
  Greeting Card

# Conflicts:
#	assets/langs/ar-SA.json
#	assets/langs/en-US.json
#	lib/api/dashboard_api_client.dart
#	lib/generated/codegen_loader.g.dart
#	lib/provider/dashboard_provider_model.dart
7 months ago
Haroon6138 6a80e21c3f Merge pull request 'Courses-CR#-7150' (#19) from Courses-CR#-7150 into master
Reviewed-on: https://34.17.182.140/Haroon6138/mohemm-flutter-app/pulls/19
7 months ago
Sultan khan b240f55aff Merge branch 'master' of http://34.17.182.140/Haroon6138/mohemm-flutter-app into Courses-CR#-7150
# Conflicts:
#	lib/ui/landing/widget/menus_widget.dart
7 months ago
Sultan khan 3343e4fe10 sso and courses in app browser updated 7 months ago
haroon amjad 2c9db30d6a Merge branch 'master' into etqan_ovr_integration
# Conflicts:
#	assets/langs/ar-SA.json
#	assets/langs/en-US.json
#	lib/api/dashboard_api_client.dart
#	lib/config/routes.dart
#	lib/generated/codegen_loader.g.dart
#	lib/generated/locale_keys.g.dart
#	lib/provider/dashboard_provider_model.dart
7 months ago
haroon amjad eb3eb1d102 updates 7 months ago
aamir-csol 257b803cce QIPS-1205 7 months ago
aamir-csol a958257ce9 Greeting 7 months ago
aamir-csol dae746587f QIPS-1205 7 months ago
aamir-csol facb3bf4e6 QIPS-1205 7 months ago
aamir-csol 71d03ba664 QIPS-1205 7 months ago
aamir-csol 9f663df3cc QIPS-1205 7 months ago
aamir-csol ba8908d4eb Greeting Card 7 months ago
aamir-csol a8f390d49f QIPS-1175,QIPS-1179,QIPS-1180 7 months ago
aamir-csol 2c7d3bf963 QIPS-1175,QIPS-1179,QIPS-1180 7 months ago
aamir-csol 31d1804f7a QIPS-1175,QIPS-1179,QIPS-1180 8 months ago
haroon amjad 82c9aa8a2f updates 8 months ago
aamir-csol 048c9b395f approval level commented Code for filter . 8 months ago
aamir-csol eea35e4d77 approval level commented Code for filter . 8 months ago
Sultan khan 19ccee6a20 updates 8 months ago
Sultan khan 5705619ce4 untracked icon added 8 months ago
Sultan khan fe583c234b Merge branch 'master' of http://34.17.182.140/Haroon6138/mohemm-flutter-app
* 'master' of http://34.17.182.140/Haroon6138/mohemm-flutter-app:
  approval level commented Code for filter .
  Parking Qr Solution
  CR-19329 - ERP MOWADHFAI System changes
  Changed the device identifier, Update to Stores VersionID 9.5
  Update to Stores for Fixed Asset Disposal, VersionID 9.4

# Conflicts:
#	assets/langs/ar-SA.json
#	assets/langs/en-US.json
#	lib/api/dashboard_api_client.dart
#	lib/generated/codegen_loader.g.dart
#	lib/generated/locale_keys.g.dart
8 months ago
Sultan khan a426bc332e E-learning Mandatory Courses - CR# 7150 8 months ago
aamir-csol 12d8fd95ba approval level commented Code for filter . 8 months ago
aamir-csol eebaafcf7c approval level commented Code for filter . 8 months ago
aamir-csol a28eb4426b Merge remote-tracking branch 'origin/etqan_ovr_integration' into etqan_ovr_integration 8 months ago
aamir-csol dfa7d9a713 approval level commented Code for filter . 8 months ago
haroon amjad 9112b26987 updates 8 months ago
aamir-csol e3fcc992df approval level commented Code for filter . 8 months ago
aamir-csol d021c95def Parking Qr Solution 9 months ago
aamir-csol 74bcf3e1b7 translation 9 months ago
aamir-csol 912f7b23f1 Merge branch 'master' into etqan_ovr_integration 9 months ago
aamir-csol 99414bf787 Itiqan Ovr Completed 9 months ago
haroon amjad 90bf529865 CR-19329 - ERP MOWADHFAI System changes 9 months ago
aamir-csol 5809aa157f Ticket Attachments 9 months ago
aamir-csol e11b214a28 Merge remote-tracking branch 'origin/flutter_upgrade_with_timesheet_changes' into flutter_upgrade_with_timesheet_changes 9 months ago
Sultan khan 89ea554c7a Merge branch 'flutter_upgrade_with_timesheet_changes' 10 months ago
Sultan khan 3d91a1444e wallet ticket fix 10 months ago
aamir-csol 676e662967 Survey title key fix 12 months ago

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 31 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 31 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 730 KiB

@ -0,0 +1,4 @@
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M17.3339 15.9992H13.3339V11.1992C13.3339 10.9365 13.3343 10.7929 13.34 10.6886L13.341 10.673L13.3565 10.6721C13.4609 10.6664 13.6045 10.6659 13.8672 10.6659H17.3339C18.8066 10.6659 20.0005 11.8598 20.0005 13.3326C20.0005 14.8053 18.8066 15.9992 17.3339 15.9992Z" fill="#2E3039"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M16.0684 2.33203H15.9316C13.1698 2.33202 11.005 2.33201 9.30102 2.53899C7.55973 2.75051 6.16606 3.19084 5.02088 4.16892C4.71548 4.42976 4.43104 4.71419 4.1702 5.0196C3.19212 6.16478 2.75179 7.55845 2.54027 9.29974C2.33329 11.0037 2.3333 13.1684 2.33331 15.9304V16.067C2.3333 18.829 2.33329 20.9937 2.54027 22.6977C2.75179 24.4389 3.19212 25.8326 4.1702 26.9778C4.43104 27.2832 4.71547 27.5676 5.02088 27.8285C6.16606 28.8066 7.55973 29.2469 9.30102 29.4584C11.005 29.6654 13.1697 29.6654 15.9316 29.6654H16.0683C18.8302 29.6654 20.995 29.6654 22.6989 29.4584C24.4402 29.2469 25.8339 28.8066 26.9791 27.8285C27.2845 27.5676 27.5689 27.2832 27.8298 26.9778C28.8078 25.8326 29.2482 24.4389 29.4597 22.6977C29.6667 20.9937 29.6667 18.829 29.6666 16.067V15.9304C29.6667 13.1684 29.6667 11.0037 29.4597 9.29974C29.2482 7.55845 28.8078 6.16478 27.8298 5.0196C27.5689 4.71419 27.2845 4.42976 26.9791 4.16892C25.8339 3.19084 24.4402 2.75051 22.6989 2.53899C20.995 2.33201 18.8303 2.33202 16.0684 2.33203ZM13.8672 7.99925L13.7592 7.99898C13.3835 7.99761 12.9217 7.99593 12.5098 8.12976C11.698 8.39355 11.0615 9.03003 10.7977 9.84187C10.6639 10.2538 10.6656 10.7156 10.6669 11.0913L10.6672 11.1992V23.9993C10.6672 24.7356 11.2642 25.3326 12.0005 25.3326C12.7369 25.3326 13.3339 24.7356 13.3339 23.9993V18.6659H17.3339C20.2794 18.6659 22.6672 16.2781 22.6672 13.3326C22.6672 10.3871 20.2794 7.99925 17.3339 7.99925H13.8672Z" fill="#2E3039"/>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

@ -0,0 +1,8 @@
<svg xmlns="http://www.w3.org/2000/svg" width="19.5" height="19.5" viewBox="0 0 19.5 19.5">
<g id="graduation-cap" transform="translate(0)">
<path id="cap-top" d="M9.75,4.5L3.5,7.5L9.75,10.5L16,7.5L9.75,4.5Z" fill="#2e303a"/>
<path id="cap-body" d="M4.5,8.5V13.5C4.5,14.5,6.5,16.5,9.75,16.5C13,16.5,15,14.5,15,13.5V8.5L9.75,11.5L4.5,8.5Z" fill="#2e303a"/>
<path id="tassel" d="M16,8V12.5L16.5,13L17,12.5V8H16Z" fill="#2e303a"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 457 B

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 1.2 MiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 1.2 MiB

@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32.774" height="32.788" viewBox="0 0 32.774 32.788">
<g id="park-tickets-couple" transform="translate(-0.205 0.001)">
<path id="Path_4724" data-name="Path 4724" d="M68.36,485.746a1.657,1.657,0,0,1-1.581,1.3.539.539,0,0,0-.206,1.025,1.656,1.656,0,0,1,.955,1.814l-.14.7a1.744,1.744,0,0,1-2.093,1.278c-.25-.06-.506-.106-.759-.156-.373-.073-.745-.15-1.118-.223-.493-.1-.985-.2-1.477-.3l-1.76-.353c-.655-.133-1.311-.263-1.967-.4-.7-.14-1.4-.279-2.1-.423-.719-.143-1.438-.289-2.153-.433l-2.133-.429-2.036-.409c-.622-.123-1.241-.25-1.863-.373-.539-.107-1.078-.216-1.614-.323l-1.291-.26-.888-.18c-.136-.027-.273-.057-.409-.083-.007,0-.013,0-.02,0a1.686,1.686,0,0,1-.12,1.062,1.705,1.705,0,0,1-1.87.958.5.5,0,0,0-.562.246l-.3.649a.5.5,0,0,0,.176.589c.033.027,24.018,11.084,24.058,11.094a.5.5,0,0,0,.562-.246l.3-.649a.5.5,0,0,0-.176-.589,1.7,1.7,0,0,1,1.388-3,.5.5,0,0,0,.562-.246l.3-.649a.5.5,0,0,0-.176-.589,1.7,1.7,0,0,1,1.388-3,.5.5,0,0,0,.562-.246l.3-.649a.5.5,0,0,0-.176-.589,1.7,1.7,0,0,1,1.388-3,.5.5,0,0,0,.562-.246l.329-.719a.41.41,0,0,0-.2-.546L68.416,485.5Z" transform="translate(-39.26 -469.349)" fill="#2bb8a6"/>
<path id="Path_4725" data-name="Path 4725" d="M.519,16.168c.04.02,25.932,5.214,25.975,5.214a.5.5,0,0,0,.489-.369l.14-.7a.5.5,0,0,0-.309-.532,1.7,1.7,0,0,1,.652-3.244.5.5,0,0,0,.489-.369l.1-.512.037-.19a.5.5,0,0,0-.309-.532,1.7,1.7,0,0,1,.652-3.244.5.5,0,0,0,.489-.369l.14-.7a.5.5,0,0,0-.309-.532,1.7,1.7,0,0,1,.652-3.244.5.5,0,0,0,.489-.369l.156-.775a.41.41,0,0,0-.323-.482S3.714,0,3.687,0a.412.412,0,0,0-.4.329L3.128,1.1a.5.5,0,0,0,.309.532A1.7,1.7,0,0,1,2.786,4.88.5.5,0,0,0,2.3,5.25l-.14.7a.5.5,0,0,0,.309.532,1.7,1.7,0,0,1-.652,3.244.5.5,0,0,0-.489.369l-.14.7a.5.5,0,0,0,.309.532A1.7,1.7,0,0,1,.842,14.57a.5.5,0,0,0-.489.369l-.14.7A.494.494,0,0,0,.519,16.168ZM22.7,7.639a.831.831,0,1,1,1.631.326l-1.1,5.464L22.555,16.8a.832.832,0,0,1-.815.669.9.9,0,0,1-.163-.017.833.833,0,0,1-.652-.978l.755-3.757ZM7.7,4.628a.831.831,0,0,1,1.631.326L8.948,6.84,8.519,8.98,8.173,10.7l-.616,3.081a.832.832,0,0,1-.815.669.9.9,0,0,1-.163-.017.4.4,0,0,1-.067-.017.829.829,0,0,1-.582-.962l.123-.622.323-1.611Z" fill="#125765"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

@ -0,0 +1,16 @@
<svg xmlns="http://www.w3.org/2000/svg" width="23.959" height="37.006" viewBox="0 0 23.959 37.006">
<g id="Layer_x0020_1" transform="translate(-300.998)">
<g id="_411123120" transform="translate(301)">
<g id="Group_8657" data-name="Group 8657" transform="translate(3.252)">
<path id="Path_13674" data-name="Path 13674" d="M612.691,6.612H619.8V1.691h-7.111ZM620.669,8.3h-8.823A.833.833,0,0,1,611,7.458V.845A.847.847,0,0,1,611.846,0h8.823a.861.861,0,0,1,.845.845V7.458A.847.847,0,0,1,620.669,8.3Z" transform="translate(-607.531)" fill="#2bb8a6"/>
<path id="Path_13675" data-name="Path 13675" d="M466.845,305h15.089a.833.833,0,0,1,.845.845,5.44,5.44,0,0,1-5.42,5.441h-5.918A5.478,5.478,0,0,1,466,305.845.847.847,0,0,1,466.845,305Z" transform="translate(-465.675 -298.388)" fill="#2bb8a6"/>
<path id="Path_13676" data-name="Path 13676" d="M527.845,0A.861.861,0,0,0,527,.845a.847.847,0,0,0,.846.845h12.444a.851.851,0,0,0,.867-.845A.865.865,0,0,0,540.289,0Z" transform="translate(-525.352)" fill="#2bb8a6"/>
<g id="Group_8656" data-name="Group 8656" transform="translate(0 33.863)">
<path id="Path_13677" data-name="Path 13677" d="M455.553,1562v.867a2.276,2.276,0,1,1-4.553,0V1562h4.553Z" transform="translate(-451 -1562)" fill="#2bb8a6"/>
<path id="Path_13678" data-name="Path 13678" d="M1050.553,1562v.867a2.276,2.276,0,0,1-4.553,0V1562h4.553Z" transform="translate(-1033.101 -1562)" fill="#2bb8a6"/>
</g>
</g>
<path id="Subtraction_59" data-name="Subtraction 59" d="M20570.063,22681.4h-16.975a.817.817,0,0,1-.238-.023,3.388,3.388,0,0,1-2.236-1.018,3.476,3.476,0,0,1-1.02-2.471v-19.4a3.557,3.557,0,0,1,1.02-2.475,3.457,3.457,0,0,1,1.906-.975,1.745,1.745,0,0,0-.193.8,6.288,6.288,0,0,0,6.289,6.285h5.92a6.288,6.288,0,0,0,6.285-6.285,1.692,1.692,0,0,0-.217-.8,3.472,3.472,0,0,1,2.949,3.449v19.4a3.476,3.476,0,0,1-1.02,2.471,3.383,3.383,0,0,1-2.236,1.018A.879.879,0,0,1,20570.063,22681.4Zm-10.756-7.187a2.114,2.114,0,1,0,1.494.619A2.1,2.1,0,0,0,20559.307,22674.211Zm4.027.732-.613.621.961.939-.961.943.613.621.963-.949v0l.973.949.609-.621-.961-.943.961-.939-.609-.621-.973.951Zm-4.025-6.031a2.112,2.112,0,0,0-.807,4.063,2.071,2.071,0,0,0,.809.164,2.113,2.113,0,0,0,0-4.227Zm3.543,1.406-.645.584,1.531,1.7,2.637-2.6-.609-.619-1.992,1.963Zm-3.539-6.709a2.158,2.158,0,0,0-.486.059,2.111,2.111,0,1,0,.969,4.109,2.123,2.123,0,0,0,1.57-2.545A2.1,2.1,0,0,0,20559.313,22663.609Zm3.539,1.266-.645.58,1.531,1.7,2.637-2.6-.609-.619-1.992,1.963Z" transform="translate(-20549.596 -22648.381)" fill="#125765"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

@ -0,0 +1 @@
<?xml version="1.0" ?><svg id="Outline" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><defs><style>.cls-1{fill:#ffffff;}</style></defs><path style="fill: #FFF" class="cls-1" d="M376,170a11.34,11.34,0,0,0-16,.15L215.28,317.64l-64-65.22a11.34,11.34,0,0,0-16.18,15.88l72.16,73.58a11.35,11.35,0,0,0,16,.15,12,12,0,0,0,1.43-1.7l.4-.37,151-154A11.33,11.33,0,0,0,376,170Z"/><path style="fill: #FFF" class="cls-1" d="M256,58.65c-108.38,0-196.56,88.18-196.56,196.56S147.62,451.77,256,451.77,452.56,363.6,452.56,255.21,364.38,58.65,256,58.65Zm0,370.45c-95.88,0-173.88-78-173.88-173.89S160.12,81.33,256,81.33s173.88,78,173.88,173.88S351.88,429.1,256,429.1Z"/></svg>

After

Width:  |  Height:  |  Size: 665 B

@ -0,0 +1 @@
<?xml version="1.0" ?><svg data-name="Livello 1" id="Livello_1" viewBox="0 0 128 128" xmlns="http://www.w3.org/2000/svg"><title/><path style="fill: #fff;" d="M64,0a64,64,0,1,0,64,64A64.07,64.07,0,0,0,64,0Zm0,122a58,58,0,1,1,58-58A58.07,58.07,0,0,1,64,122Z"/><path style="fill: #fff;" d="M92.12,35.79a3,3,0,0,0-4.24,0L64,59.75l-23.87-24A3,3,0,0,0,35.88,40L59.76,64,35.88,88a3,3,0,0,0,4.25,4.24L64,68.25l23.88,24A3,3,0,0,0,92.13,88L68.24,64,92.13,40A3,3,0,0,0,92.12,35.79Z"/></svg>

After

Width:  |  Height:  |  Size: 479 B

@ -164,6 +164,7 @@
"quotationAnalysis": "تحليل الاقتباس",
"subject": "موضوعات",
"description": "وصف",
"pleaseEnterDescription": "الرجاء إدخال الوصف",
"supplier": "المورد",
"site": "موقع",
"buyer": "مشتر",
@ -258,6 +259,7 @@
"fullName": "الأسم الكامل",
"remove": "حذف",
"submit": "ارسال",
"submitAsAnonymous": "إرسال كمجهول",
"areYouSureYouWantToSubmit": "هل أنت متأكد أنك تريد أن تقدم؟",
"comments": "تعليقات",
"writeComment": "أكتب تعليقا",
@ -318,6 +320,8 @@
"createdFor": "انشاء لأجل",
"requestCreatedSuccessfully": "تم انشاء الطلب بنجاح",
"search": "بحث",
"filterEnterPrDetailsHere": "ادخل تفاصيل طلب الشراء هنا",
"filterEnterPoDetailsHere": "ادخل تفاصيل أمر الشراء هنا",
"wantToReject": "هل انت متأكد تريد الرفض",
"requestType": "نوع الطلب",
"employeeDigitalID": "هويةالموظف الرقمية",
@ -531,7 +535,7 @@
"noWinner": "حزين! لم يفز أحد اليوم.",
"myTeam": "فريقي",
"youCanPlayDemo": "لكن يمكنك لعب العرض",
"group" : "مجموعة",
"group": "مجموعة",
"searchGroup": "مجموعة البحث",
"connectHmgWifi": "قم بتوصيل HMG WIFI",
"connectedHmgWifi": "اتصال HMG WIFI",
@ -575,20 +579,20 @@
"versionStatus": "حالة الإصدار",
"supplierNo": "رقم المورد",
"general": "عام",
"requesterOperatingUnit":"وحدة تشغيل مقدم الطلب",
"prepareEmpNum":"إعداد رقم الموظف",
"supplierInfo" : "معلومات المورد",
"requesterOperatingUnit": "وحدة تشغيل مقدم الطلب",
"prepareEmpNum": "إعداد رقم الموظف",
"supplierInfo": "معلومات المورد",
"supplierAcNo": "رقم حساب المورد",
"supplierAcName": "اسم حساب المورد",
"supplierIBAN" : "رقم IBAN للمورد",
"supplierCRNo" :"رقم السجل التجاري",
"suppliedAcNo" : "رقم الحساب المقدم",
"patientRefundInvoice" : "فاتورة استرداد الأموال للمريض",
"patientNumber" : "رقم المريض",
"patientName" : "اسم المريض",
"invoiceDate" : "تاريخ الفاتورة",
"refundInvoice" :"فاتورة الاسترجاع",
"hospitalClinic" : "عيادة المستشفى",
"supplierIBAN": "رقم IBAN للمورد",
"supplierCRNo": "رقم السجل التجاري",
"suppliedAcNo": "رقم الحساب المقدم",
"patientRefundInvoice": "فاتورة استرداد الأموال للمريض",
"patientNumber": "رقم المريض",
"patientName": "اسم المريض",
"invoiceDate": "تاريخ الفاتورة",
"refundInvoice": "فاتورة الاسترجاع",
"hospitalClinic": "عيادة المستشفى",
"graphicalAnalysis": "التحليل الرسومي",
"itemHistoryAnalysis": "تحليل تاريخ العنصر",
"pOno": "امر شراء #",
@ -614,23 +618,23 @@
"members": "الأعضاء",
"searchByUserName": "البحث بواسطة اسم المستخدم",
"shareScreen": "مشاركة الشاشة",
"start":"يبدأ",
"about":"عن",
"start": "يبدأ",
"about": "عن",
"explore": "يستكشف",
"mazaya": "مازيا",
"benefits": "فوائد",
"mazayaDesc": "اكتشف الخصومات والعروض الخاصة المتاحة للموظفين",
"viewallofferMazaya" : "أعرض كل المزايا",
"viewallofferMazaya": "أعرض كل المزايا",
"buyerName": "اسم المشتري",
"buyerNumber": "رقم المشتري",
"highestBidder": "أعلى مزايد",
"remarks": "ملاحظات",
"faHeader": "تفاصيل رأس الصفحة FA",
"bookTypeCode": "رمز نوع الكتاب",
"bookTypeCode": "رمز نوع الكتاب",
"categoryCode": "رمز الفئة",
"categoryGroup": "مجموعة الفئات",
"faLINES": "تفاصيل الأصول",
"assetNumber": "رقم الأصول",
"faLINES": "تفاصيل الأصول",
"assetNumber": "رقم الأصول",
"assetDescription": "وصف الأصول",
"barCodeNumber": "رقم الباركود",
"datePlaceInService": "تاريخ وضعه في الخدمة",
@ -638,9 +642,43 @@
"disposedDate": "تاريخ التخلص",
"netBookValue": "القيمة الدفترية الصافية",
"purchasedPrice": "سعر الشراء",
"usefulLife": "العمر الإنتاجي",
"usefulLife": "العمر الإنتاجي",
"yearsUsed": "سنوات الاستخدام",
"faRequest": "طلب التخلص من FA",
"showMore": "عرض المزيد",
"buyerDetails": "تفاصيل المشتري"
}
"ticketDetails": "تفاصيل التذكرة",
"currentTicketBalance": "رصيد التذكرة الحالي",
"ticketHistory": "تاريخ التذكرة",
"proceedBooking": "المتابعة للحجز",
"courses": "الدورات التدريبية",
"course": "دورة",
"status": "الحالة",
"deadline": "الموعد النهائي",
"overdue": "متأخر",
"noCoursesAvailable": "لا توجد دورات متاحة",
"pullToRefresh": "اسحب للتحديث",
"courseUrlNotAvailable": "رابط الدورة غير متوفر",
"buyerDetails": "تفاصيل المشتري",
"etqanOVR": "الإبلاغ عن حادثة",
"etqanRequest": "طلبات الحوادث",
"selectProject": "حدد المشروع",
"project": "مشروع",
"keen": "حريص",
"reportIncident": "الإبلاغ عن الحادث",
"myIncidents": "حوادثي",
"incidentDetails": "تفاصيل الحادث",
"ticketNumber": "رقم التذكرة",
"ticketId": "معرف التذكرة",
"pleaseSelectProject": "الرجاء اختيار مشروع",
"viewAttachment" : "عرض المرفق",
"parkingQr": "وقوف السيارات QR",
"startNow": "ابدأ الآن",
"destination_type": "نوع الوجهة",
"source_organization_name": "اسم منظمة المصدر",
"destination_organization_name": "اسم منظمة الوجهة",
"costCenter": "مركز التكلفة",
"priceSAR": "السعر (ريال سعودي)",
"amountSAR": "المبلغ (ريال سعودي)",
"amuLastThreeMonths": "AMU (آخر 3 أشهر)"
}

@ -158,6 +158,7 @@
"subject": "Subject",
"quotationAnalysis": "Quotation Analysis",
"description": "Description",
"pleaseEnterDescription": "Please enter description",
"supplier": "Supplier",
"site": "Site",
"buyer": "Buyer",
@ -256,6 +257,7 @@
"remove": "Remove",
"Attendance": "Attendance",
"submit": "Submit",
"submitAsAnonymous": "Submit as Anonymous",
"areYouSureYouWantToSubmit": "Are you sure you want to submit?",
"comments": "Comments",
"writeComment": "Write a comment",
@ -313,6 +315,8 @@
"requestType": "Request Type",
"requestCreatedSuccessfully": "Request created successfully",
"search": "Search",
"filterEnterPrDetailsHere": "Enter PR Details here",
"filterEnterPoDetailsHere": "Enter PO Details here",
"wantToReject": "Are you sure want to reject?",
"employeeDigitalID": "Employee Digital ID",
"businessCard": "Business Card",
@ -565,7 +569,7 @@
"addAtLeastOneAttachment": "Please add at least one attachment.",
"pleaseClickButtonToJoinMarathon": "Press the button below to join the Marathon.",
"youCannotJoinTheMarathon": "You cannot join the Marathon because you have exceeded the time limit.",
"requesterOperatingUnit":"Requester Operating Unit",
"requesterOperatingUnit": "Requester Operating Unit",
"generate": "Generate",
"paymentRequest": "Pay Request",
"paymentDetails": "Payment Details",
@ -591,19 +595,19 @@
"versionStatus": "Version Status",
"supplierNo": "Supplier No",
"general": "General",
"prepareEmpNum":"Prepare Employee Num",
"supplierInfo" : "Supplier Information",
"prepareEmpNum": "Prepare Employee Num",
"supplierInfo": "Supplier Information",
"supplierAcNo": "Supplier Account No",
"supplierAcName":"Supplier Account Name",
"supplierIBAN" : "Supplier IBAN",
"supplierCRNo" : "CR Number",
"suppliedAcNo" : "Supplied Account No.",
"patientRefundInvoice" : "Patient Refund Invoice",
"patientNumber" : "Patient Number",
"patientName" : "Patient Name",
"invoiceDate" : "Invoice Date",
"refundInvoice" :"Refund Invoice",
"hospitalClinic" : "Hospital Clinic",
"supplierAcName": "Supplier Account Name",
"supplierIBAN": "Supplier IBAN",
"supplierCRNo": "CR Number",
"suppliedAcNo": "Supplied Account No.",
"patientRefundInvoice": "Patient Refund Invoice",
"patientNumber": "Patient Number",
"patientName": "Patient Name",
"invoiceDate": "Invoice Date",
"refundInvoice": "Refund Invoice",
"hospitalClinic": "Hospital Clinic",
"graphicalAnalysis": "Graphical Analysis",
"itemHistoryAnalysis": "Item History Analysis",
"pOno": "P.O #",
@ -612,23 +616,23 @@
"qtyReceived": "Qty. Received",
"bonusQty": "Bonus Qty.",
"balQty": "Bal. Qty.",
"start":"Start",
"about":"About",
"start": "Start",
"about": "About",
"explore": "Explore",
"mazaya": "MAZAYA",
"benefits": "Benefits",
"mazayaDesc": "Discover special Discounts and offers available to Employees",
"viewallofferMazaya" : "View All Offers",
"viewallofferMazaya": "View All Offers",
"buyerName": "Buyer Name",
"buyerNumber": "Buyer Number",
"highestBidder": "Highest Bidder",
"remarks": "Remarks",
"faHeader": "FA Header Details",
"bookTypeCode": "Book Type Code",
"bookTypeCode": "Book Type Code",
"categoryCode": "Category Code",
"categoryGroup": "Category Group",
"faLINES": "Asset Details",
"assetNumber": "Asset Number",
"faLINES": "Asset Details",
"assetNumber": "Asset Number",
"assetDescription": "Asset Description",
"barCodeNumber": "BarCode Number",
"datePlaceInService": "Date place In Service",
@ -636,9 +640,42 @@
"disposedDate": "Disposed Date",
"netBookValue": "Net Book Value",
"purchasedPrice": "Purchased Price",
"usefulLife": "Useful Life",
"usefulLife": "Useful Life",
"yearsUsed": "Years Used",
"faRequest":"FA Disposal Request",
"faRequest": "FA Disposal Request",
"showMore": "Show More",
"buyerDetails": "Buyer Details"
"ticketDetails": "Ticket Details",
"currentTicketBalance": "Current Ticket Balance",
"ticketHistory": "Ticket History",
"proceedBooking": "Proceed For Booking",
"courses": "Courses",
"course": "Course",
"status": "Status",
"deadline": "Deadline",
"overdue": "Overdue",
"noCoursesAvailable": "No Courses Available",
"pullToRefresh": "Pull to refresh",
"courseUrlNotAvailable": "Course URL not available",
"buyerDetails": "Buyer Details",
"etqanOVR": "Report An Incident",
"etqanRequest": "Incident Requests",
"selectProject": "Select Project",
"project": "Project",
"keen": "Keen",
"reportIncident": "Report Incident",
"myIncidents": "My Incidents",
"incidentDetails": "Incident Details",
"ticketNumber": "Ticket Number",
"ticketId": "Ticket ID",
"pleaseSelectProject": "Please select a project",
"viewAttachment" : "View Attachment",
"parkingQr": "Parking QR",
"startNow": "Start Now",
"destination_type": "Destination Type",
"source_organization_name": "Source Organization Name",
"destination_organization_name": "Destination Organization Name",
"costCenter": "Cost Center",
"priceSAR": "Price (SAR)",
"amountSAR": "Amount (SAR)",
"amuLastThreeMonths": "AMU (Last 3 months)"
}

@ -61,6 +61,8 @@
<string>This app requires photo library access to select image as document &amp; upload it.</string>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
<key>NSSpeechRecognitionUsageDescription</key>
<string>This app requires speech recognition access to access voice command features.</string>
<key>UIBackgroundModes</key>
<array>
<string>fetch</string>

@ -2,6 +2,7 @@ import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:http/http.dart';
import 'package:http/io_client.dart';
@ -18,15 +19,11 @@ class APIError {
dynamic errorCode;
int? errorType;
String? errorMessage;
int? errorStatusCode;
int? errorStatusCode;
APIError(this.errorCode, this.errorMessage, this.errorType, this.errorStatusCode);
Map<String, dynamic> toJson() => {
'errorCode': errorCode,
'errorMessage': errorMessage,
'errorType': errorType,
'ErrorStatusCode': errorStatusCode
};
Map<String, dynamic> toJson() => {'errorCode': errorCode, 'errorMessage': errorMessage, 'errorType': errorType, 'ErrorStatusCode': errorStatusCode};
@override
String toString() {
@ -48,22 +45,22 @@ APIException _throwAPIException(Response response) {
APIError? apiError;
if (response.body != null && response.body.isNotEmpty) {
var jsonError = jsonDecode(response.body);
apiError = APIError(jsonError['ErrorCode'], jsonError['ErrorMessage'], jsonError['ErrorType'],jsonError['ErrorStatusCode']);
apiError = APIError(jsonError['ErrorCode'], jsonError['ErrorMessage'], jsonError['ErrorType'], jsonError['ErrorStatusCode']);
}
return APIException(APIException.BAD_REQUEST, error: apiError);
case 401:
return APIException(APIException.UNAUTHORIZED);
return const APIException(APIException.UNAUTHORIZED);
case 403:
return APIException(APIException.FORBIDDEN);
return const APIException(APIException.FORBIDDEN);
case 404:
return APIException(APIException.NOT_FOUND);
return const APIException(APIException.NOT_FOUND);
case 500:
return APIException(APIException.INTERNAL_SERVER_ERROR);
return const APIException(APIException.INTERNAL_SERVER_ERROR);
case 444:
var downloadUrl = response.headers["location"];
return APIException(APIException.UPGRADE_REQUIRED, arguments: downloadUrl);
default:
return APIException(APIException.OTHER);
return const APIException(APIException.OTHER);
}
}
@ -74,8 +71,16 @@ class ApiClient {
factory ApiClient() => _instance;
Future<U> postJsonForObject<T, U>(FactoryConstructor<U> factoryConstructor, String url, T jsonObject,
{String? token, Map<String, dynamic>? queryParameters, Map<String, String>? headers, int retryTimes = 0, bool isFormData = false}) async {
Future<U> postJsonForObject<T, U>(
FactoryConstructor<U> factoryConstructor,
String url,
T jsonObject, {
String? token,
Map<String, dynamic>? queryParameters,
Map<String, String>? headers,
int retryTimes = 0,
bool isFormData = false,
}) async {
var _headers = {'Accept': 'application/json'};
if (headers != null && headers.isNotEmpty) {
_headers.addAll(headers);
@ -121,8 +126,15 @@ class ApiClient {
}
}
Future<Response> postJsonForResponse<T>(String url, T jsonObject,
{String? token, Map<String, dynamic>? queryParameters, Map<String, String>? headers, int retryTimes = 0, bool isFormData = false}) async {
Future<Response> postJsonForResponse<T>(
String url,
T jsonObject, {
String? token,
Map<String, dynamic>? queryParameters,
Map<String, String>? headers,
int retryTimes = 0,
bool isFormData = false,
}) async {
String? requestBody;
late Map<String, String> stringObj;
if (jsonObject != null) {
@ -157,9 +169,9 @@ class ApiClient {
var queryString = new Uri(queryParameters: queryParameters).query;
url = url + '?' + queryString;
}
var response = await _post(Uri.parse(url), body: requestBody, headers: _headers).timeout(Duration(seconds: 120));
var response = await _post(Uri.parse(url), body: requestBody, headers: _headers).timeout(const Duration(seconds: 120));
if (response. statusCode >= 200 && response.statusCode < 300) {
if (response.statusCode >= 200 && response.statusCode < 300) {
return response;
} else {
throw _throwAPIException(response);
@ -167,7 +179,7 @@ class ApiClient {
} on SocketException catch (e) {
if (retryTimes > 0) {
print('will retry after 3 seconds...');
await Future.delayed(Duration(seconds: 3));
await Future.delayed(const Duration(seconds: 3));
return await _postForResponse(url, requestBody, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1);
} else {
throw APIException(APIException.OTHER, arguments: e);
@ -175,7 +187,7 @@ class ApiClient {
} on HttpException catch (e) {
if (retryTimes > 0) {
print('will retry after 3 seconds...');
await Future.delayed(Duration(seconds: 3));
await Future.delayed(const Duration(seconds: 3));
return await _postForResponse(url, requestBody, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1);
} else {
throw APIException(APIException.OTHER, arguments: e);
@ -185,7 +197,7 @@ class ApiClient {
} on ClientException catch (e) {
if (retryTimes > 0) {
print('will retry after 3 seconds...');
await Future.delayed(Duration(seconds: 3));
await Future.delayed(const Duration(seconds: 3));
return await _postForResponse(url, requestBody, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1);
} else {
throw APIException(APIException.OTHER, arguments: e);
@ -224,7 +236,7 @@ class ApiClient {
var queryString = new Uri(queryParameters: queryParameters).query;
url = url + '?' + queryString;
}
var response = await _get(Uri.parse(url), headers: _headers).timeout(Duration(seconds: 60));
var response = await _get(Uri.parse(url), headers: _headers).timeout(const Duration(seconds: 60));
if (response.statusCode >= 200 && response.statusCode < 300) {
return response;
@ -234,7 +246,7 @@ class ApiClient {
} on SocketException catch (e) {
if (retryTimes > 0) {
print('will retry after 3 seconds...');
await Future.delayed(Duration(seconds: 3));
await Future.delayed(const Duration(seconds: 3));
return await _getForResponse(url, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1);
} else {
throw APIException(APIException.OTHER, arguments: e);
@ -242,7 +254,7 @@ class ApiClient {
} on HttpException catch (e) {
if (retryTimes > 0) {
print('will retry after 3 seconds...');
await Future.delayed(Duration(seconds: 3));
await Future.delayed(const Duration(seconds: 3));
return await _getForResponse(url, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1);
} else {
throw APIException(APIException.OTHER, arguments: e);
@ -252,7 +264,7 @@ class ApiClient {
} on ClientException catch (e) {
if (retryTimes > 0) {
print('will retry after 3 seconds...');
await Future.delayed(Duration(seconds: 3));
await Future.delayed(const Duration(seconds: 3));
return await _getForResponse(url, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1);
} else {
throw APIException(APIException.OTHER, arguments: e);

@ -1,5 +1,6 @@
import 'dart:async';
import 'dart:convert';
import 'dart:developer';
import 'dart:io';
import 'package:easy_localization/easy_localization.dart';
@ -15,10 +16,15 @@ import 'package:mohem_flutter_app/models/dashboard/get_accural_ticket_balance_mo
import 'package:mohem_flutter_app/models/dashboard/get_attendance_tracking_list_model.dart';
import 'package:mohem_flutter_app/models/dashboard/itg_forms_model.dart';
import 'package:mohem_flutter_app/models/dashboard/list_menu.dart';
import 'package:mohem_flutter_app/models/eit_attachment_ticket_model.dart';
import 'package:mohem_flutter_app/models/dashboard/courses_response_model.dart';
import 'package:mohem_flutter_app/models/generic_response_model.dart';
import 'package:mohem_flutter_app/models/get_employee_parking_details_model.dart';
import 'package:mohem_flutter_app/models/greetings/greeting_card_model.dart';
import 'package:mohem_flutter_app/models/itg/itg_main_response.dart';
import 'package:mohem_flutter_app/models/itg/itg_response_model.dart';
import 'package:mohem_flutter_app/models/sso_auth_model.dart';
// import 'package:platform_device_id/platform_device_id.dart';
import 'package:uuid/uuid.dart';
@ -31,7 +37,7 @@ class DashboardApiClient {
Future<GetAttendanceTracking?> getAttendanceTracking() async {
String url = "${ApiConsts.erpRest}GET_Attendance_Tracking";
Map<String, dynamic> postParams = {};
Map<String, dynamic> postParams = <String, dynamic>{};
postParams.addAll(AppState().postParamsJson);
return await ApiClient().postJsonForObject(
(json) {
@ -45,7 +51,7 @@ class DashboardApiClient {
Future<GenericResponseModel?> getOpenNotifications() async {
String url = "${ApiConsts.erpRest}GET_OPEN_NOTIFICATIONS";
Map<String, dynamic> postParams = {};
Map<String, dynamic> postParams = <String, dynamic>{};
postParams.addAll(AppState().postParamsJson);
return await ApiClient().postJsonForObject(
(json) {
@ -59,7 +65,7 @@ class DashboardApiClient {
Future<GenericResponseModel?> getCOCNotifications() async {
String url = "${ApiConsts.cocRest}Mohemm_ITG_ReviewerAdmin_Pending_Tasks";
Map<String, dynamic> postParams = {"Date": DateUtil.getISODateFormat(DateTime.now()), "EmployeeNumber": AppState().memberInformationList?.eMPLOYEENUMBER};
Map<String, dynamic> postParams = <String, dynamic>{"Date": DateUtil.getISODateFormat(DateTime.now()), "EmployeeNumber": AppState().memberInformationList?.eMPLOYEENUMBER};
postParams.addAll(AppState().postParamsJson);
return await ApiClient().postJsonForObject(
(json) {
@ -73,7 +79,7 @@ class DashboardApiClient {
Future<ItgFormsModel?> getItgFormsPendingTask() async {
String url = "${ApiConsts.cocRest}ITGFormsPendingTasks";
Map<String, dynamic> postParams = {};
Map<String, dynamic> postParams = <String, dynamic>{};
postParams.addAll(AppState().postParamsJson);
return await ApiClient().postJsonForObject(
(json) {
@ -87,13 +93,13 @@ class DashboardApiClient {
Future<List<GetAccrualBalancesList>> getAccrualBalances(String effectiveDate, {String? empID}) async {
String url = "${ApiConsts.erpRest}GET_ACCRUAL_BALANCES";
Map<String, dynamic> postParams = {"P_EFFECTIVE_DATE": effectiveDate};
Map<String, dynamic> postParams = <String, dynamic>{"P_EFFECTIVE_DATE": effectiveDate};
postParams.addAll(AppState().postParamsJson);
if (empID != null) postParams["P_SELECTED_EMPLOYEE_NUMBER"] = empID;
return await ApiClient().postJsonForObject(
(json) {
GenericResponseModel responseData = GenericResponseModel.fromJson(json);
return responseData.getAccrualBalancesList ?? [];
return responseData.getAccrualBalancesList ?? <GetAccrualBalancesList>[];
},
url,
postParams,
@ -102,13 +108,13 @@ class DashboardApiClient {
Future<List<GetTicketAccuralBalanceModel>> getTicketAccuralBalance(String effectiveDate, {String? empID}) async {
String url = "${ApiConsts.erpRest}GET_TICKET_ACCRUAL_BALANCES";
Map<String, dynamic> postParams = {"P_EFFECTIVE_DATE": effectiveDate};
Map<String, dynamic> postParams = <String, dynamic>{"P_EFFECTIVE_DATE": effectiveDate};
postParams.addAll(AppState().postParamsJson);
if (empID != null) postParams["P_SELECTED_EMPLOYEE_NUMBER"] = empID;
return await ApiClient().postJsonForObject(
(json) {
GenericResponseModel responseData = GenericResponseModel.fromJson(json);
return responseData.getAccrualBalancesTicketList ?? [];
return responseData.getAccrualBalancesTicketList ?? <GetTicketAccuralBalanceModel>[];
},
url,
postParams,
@ -117,7 +123,7 @@ class DashboardApiClient {
Future<GenericResponseModel?> getOpenMissingSwipes() async {
String url = "${ApiConsts.erpRest}GET_OPEN_MISSING_SWIPES";
Map<String, dynamic> postParams = {};
Map<String, dynamic> postParams = <String, dynamic>{};
postParams.addAll(AppState().postParamsJson);
return await ApiClient().postJsonForObject(
(json) {
@ -132,12 +138,12 @@ class DashboardApiClient {
//Menus List
Future<List<ListMenu>> getListMenu() async {
String url = "${ApiConsts.erpRest}GET_MENU";
Map<String, dynamic> postParams = {};
Map<String, dynamic> postParams = <String, dynamic>{};
postParams.addAll(AppState().postParamsJson);
return await ApiClient().postJsonForObject(
(json) {
GenericResponseModel responseData = GenericResponseModel.fromJson(json);
return responseData.listMenu ?? [];
return responseData.listMenu ?? <ListMenu>[];
},
url,
postParams,
@ -147,7 +153,7 @@ class DashboardApiClient {
//GET_MENU_ENTRIES
Future<GenericResponseModel?> getGetMenuEntries() async {
String url = "${ApiConsts.erpRest}GET_MENU_ENTRIES";
Map<String, dynamic> postParams = {"P_SELECTED_RESP_ID": -999, "P_MENU_TYPE": "E"};
Map<String, dynamic> postParams = <String, dynamic>{"P_SELECTED_RESP_ID": -999, "P_MENU_TYPE": "E"};
postParams.addAll(AppState().postParamsJson);
return await ApiClient().postJsonForObject(
(json) {
@ -161,7 +167,7 @@ class DashboardApiClient {
Future<GenericResponseModel?> getEventActivity() async {
String url = "${ApiConsts.erpRest}Get_EventActivity";
Map<String, dynamic> postParams = {"P_SELECTED_RESP_ID": -999, "P_MENU_TYPE": "E"};
Map<String, dynamic> postParams = <String, dynamic>{"P_SELECTED_RESP_ID": -999, "P_MENU_TYPE": "E"};
postParams.addAll(AppState().postParamsJson);
return await ApiClient().postJsonForObject(
(json) {
@ -175,7 +181,7 @@ class DashboardApiClient {
Future<GenericResponseModel?> getTicketBookingRedirection() async {
String url = "${ApiConsts.erpRest}GET_PORTAL_REDIRECTION";
Map<String, dynamic> postParams = {"P_USER_NAME": AppState().memberInformationList?.eMPLOYEENUMBER};
Map<String, dynamic> postParams = <String, dynamic>{"P_USER_NAME": AppState().memberInformationList?.eMPLOYEENUMBER};
postParams.addAll(AppState().postParamsJson);
return await ApiClient().postJsonForObject(
(json) {
@ -189,7 +195,7 @@ class DashboardApiClient {
Future<GenericResponseModel?> getTicketBalance() async {
String url = "${ApiConsts.erpRest}GET_TICKET_BALANCE";
Map<String, dynamic> postParams = {"P_USER_NAME": AppState().memberInformationList?.eMPLOYEENUMBER};
Map<String, dynamic> postParams = <String, dynamic>{"P_USER_NAME": AppState().memberInformationList?.eMPLOYEENUMBER};
postParams.addAll(AppState().postParamsJson);
return await ApiClient().postJsonForObject(
@ -206,7 +212,7 @@ class DashboardApiClient {
String url = "${ApiConsts.ssoAuthRedirection}?grantType=mohemm";
//https://sso-uat.hmg.com/api/auth/connect?grantType=mohemm'
// Map<String, dynamic> postParams = {"P_USER_NAME": AppState().memberInformationList?.eMPLOYEENUMBER};
Map<String, dynamic> postParams = {
Map<String, dynamic> postParams = <String, dynamic>{
"ClientId": clientID,
// "ClientId": "a9f4d1a0596d4aea8f830992ec4bdac1",
"PersonId": AppState().memberInformationList?.eMPLOYEENUMBER,
@ -225,19 +231,35 @@ class DashboardApiClient {
);
}
Future<dynamic> getBookingSSOFinalRedirection({required String token}) async {
token =
"eyJhbGciOiJSUzI1NiIsImtpZCI6IjhjZTE2OWM0YjIwYjQ2ZWM5YTQyOTU3Y2ZhODUzNzQ1IiwidHlwIjoiSldUIn0.eyJ0ZW5hbnRfaWQiOiJhOWY0ZDFhMDU5NmQ0YWVhOGY4MzA5OTJlYzRiZGFjMSIsImVpZCI6IjExNzkzMCIsImh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL3NpZCI6Ijk2MDI0OGM1NzA3YzQ3MmFhYTEzM2I1N2ZhODE1ZmVhIiwibGFuZ3VhZ2UiOiJVUyIsImh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL2VtYWlsYWRkcmVzcyI6IjExNzkzMEBobWcuY29tIiwiZXhwIjoxNzgyNDc1NzY5LCJpc3MiOiJodHRwczovL3Nzby11YXQuaG1nLmNvbSIsImF1ZCI6ImE5ZjRkMWEwNTk2ZDRhZWE4ZjgzMDk5MmVjNGJkYWMxIn0.rJcLVsG8D0XECyLERCTD2uqGeWyvp-OBVGE9uL2qKrX4etFUHgdFt_5kYF6edFTtGy-0PIZadHDmv7e-IOhVWHm5HVMClaukiXoRXR8cDN8XA1wfme3Kd-U5PXN-IRh49AyRTzLO0rYNPvH81ScosWGlsFSkOvA-0hJNa2adHdtvgNvB8wJshSU5p7sAmF8mjdDY6aInG19etu2iEuUDwHHA4ZY_ts4hboHo8fE392hFaYGonExoD7bpW5RMx5xKWeRCmWpG_PK8Aw_z1jGzdB9PANus4pteRGuln1J-kmo2lQC9pVrSyZATAKp1HfgfyZ_vUhaHEfM69cMWaCslJQ";
// var request = http.MultipartRequest('POST', Uri.parse('https://ek.techmaster.in/SSO/HMG'));
var request = http.MultipartRequest('POST', Uri.parse('https://Paxes-release.techmaster.in/SSO/HMG'));
request.fields.addAll({'JWTToken': token});
// request.headers.addAll(headers);
Future<GetEitAttachmentTicket?> getTicketEitPDFDownload({required String peiExtraInfoId}) async {
String url = "${ApiConsts.erpRest}GET_EIT_ATTACHMENTS";
Map<String, dynamic> postParams = <String, dynamic>{
"P_PERSON_EXTRA_INFO_ID": peiExtraInfoId,
"PersonId": AppState().memberInformationList?.eMPLOYEENUMBER,
"Username": AppState().memberInformationList?.eMPLOYEENUMBER,
"Language": "US",
"SessionId": AppState().postParamsObject?.pSessionId,
};
postParams.addAll(AppState().postParamsJson);
return await ApiClient().postJsonForObject(
(json) {
GetEitAttachmentTicket responseData = GetEitAttachmentTicket.fromJson(json);
return responseData;
},
url,
postParams,
);
}
Future<dynamic> getBookingSSOFinalRedirection({required String token, required String refreshToken}) async {
// token =
// "eyJhbGciOiJSUzI1NiIsImtpZCI6IjhjZTE2OWM0YjIwYjQ2ZWM5YTQyOTU3Y2ZhODUzNzQ1IiwidHlwIjoiSldUIn0.eyJ0ZW5hbnRfaWQiOiJhOWY0ZDFhMDU5NmQ0YWVhOGY4MzA5OTJlYzRiZGFjMSIsImVpZCI6IjExNzkzMCIsImh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL3NpZCI6Ijk2MDI0OGM1NzA3YzQ3MmFhYTEzM2I1N2ZhODE1ZmVhIiwibGFuZ3VhZ2UiOiJVUyIsImh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL2VtYWlsYWRkcmVzcyI6IjExNzkzMEBobWcuY29tIiwiZXhwIjoxNzgyNDc1NzY5LCJpc3MiOiJodHRwczovL3Nzby11YXQuaG1nLmNvbSIsImF1ZCI6ImE5ZjRkMWEwNTk2ZDRhZWE4ZjgzMDk5MmVjNGJkYWMxIn0.rJcLVsG8D0XECyLERCTD2uqGeWyvp-OBVGE9uL2qKrX4etFUHgdFt_5kYF6edFTtGy-0PIZadHDmv7e-IOhVWHm5HVMClaukiXoRXR8cDN8XA1wfme3Kd-U5PXN-IRh49AyRTzLO0rYNPvH81ScosWGlsFSkOvA-0hJNa2adHdtvgNvB8wJshSU5p7sAmF8mjdDY6aInG19etu2iEuUDwHHA4ZY_ts4hboHo8fE392hFaYGonExoD7bpW5RMx5xKWeRCmWpG_PK8Aw_z1jGzdB9PANus4pteRGuln1J-kmo2lQC9pVrSyZATAKp1HfgfyZ_vUhaHEfM69cMWaCslJQ";
http.MultipartRequest request = http.MultipartRequest('POST', Uri.parse('https://www.paxes.com/sso/hmg'));
// http.MultipartRequest request = http.MultipartRequest('POST', Uri.parse('https://ek.techmaster.in/SSO/HMG'));
request.fields.addAll(<String, String>{'JWTToken': token, 'RefreshToken': refreshToken});
http.StreamedResponse response = await request.send();
if (response.statusCode == 302) {
print("================== post ==========");
var res = await response.stream.bytesToString();
String res = await response.stream.bytesToString();
return response.headers["location"];
} else {
print(response.reasonPhrase);
@ -257,7 +279,7 @@ class DashboardApiClient {
var _mobileDeviceIdentifierPlugin = MobileDeviceIdentifier();
Codec<String, String> stringToBase64 = utf8.fuse(base64);
String url = "${ApiConsts.swpRest}AuthenticateAndSwipeUserSupportNFC";
var uuid = Uuid();
Uuid uuid = Uuid();
String? deviceId = "";
// Generate a v4 (random) id
if (Platform.isAndroid) {
@ -269,7 +291,7 @@ class DashboardApiClient {
IosDeviceInfo iosInfo = await DeviceInfoPlugin().iosInfo;
deviceId = iosInfo.identifierForVendor;
}
Map<String, dynamic> postParams = {
Map<String, dynamic> postParams = <String, dynamic>{
"UID": deviceId, //uuid.v4(), //Mobile Id
// "UID": uuid.v4(), //Mobile Id
"Latitude": lat,
@ -295,10 +317,10 @@ class DashboardApiClient {
//Mark Fake Location
Future<GenericResponseModel?> markFakeLocation({String lat = "0", String? long = "0", required String sourceName}) async {
String url = "${ApiConsts.swpRest}CreateIssueInfo";
var uuid = Uuid();
Uuid uuid = Uuid();
// Generate a v4 (random) id
Map<String, dynamic> postParams = {
Map<String, dynamic> postParams = <String, dynamic>{
"UID": uuid.v4(), //Mobile Id
"Latitude": lat,
"Longitude": long,
@ -322,7 +344,7 @@ class DashboardApiClient {
Future<MohemmItgResponseItem?> getITGPageNotification() async {
String url = "${ApiConsts.cocRest}Mohemm_ITG_GetPageNotification";
Map<String, dynamic> postParams = {
Map<String, dynamic> postParams = <String, dynamic>{
"EmployeeNumber": AppState().getUserName,
"ItgEnableAt": "After Service Submission", //Mobile Id
"ItgServiceName": "Login",
@ -340,11 +362,26 @@ class DashboardApiClient {
);
}
Future<String?> getENSATItgToken() async {
String url = "${ApiConsts.cocRest}Mohemm_ENSAT_GetItgToken";
Map<String, dynamic> postParams = <String, dynamic>{"EmployeeNumber": AppState().getUserName};
postParams.addAll(AppState().postParamsJson);
return await ApiClient().postJsonForObject(
(json) {
GenericResponseModel responseData = GenericResponseModel.fromJson(json);
return responseData.Mohemm_ENSAT_GetItgToken_Response;
},
url,
postParams,
);
}
//Submit ITG
Future<ItgMainRes?> submitItgForm({required String comment, required String masterId, required List<Map<String, dynamic>> itgList, required int serviceId}) async {
String url = "${ApiConsts.cocRest}Mohemm_ITG_Survey_Response";
Map<String, dynamic> postParams = {
Map<String, dynamic> postParams = <String, dynamic>{
"EmployeeNumber": AppState().getUserName,
"ItgComments": comment,
"ItgNotificationMasterId": masterId,
@ -365,7 +402,7 @@ class DashboardApiClient {
Future<ItgMainRes?> getAdvertisementDetail(String masterID) async {
String url = "${ApiConsts.cocRest}Mohemm_ITG_GetPageNotificationDetails";
Map<String, dynamic> postParams = {
Map<String, dynamic> postParams = <String, dynamic>{
"EmployeeNumber": AppState().getUserName,
"ItgNotificationMasterId": masterID, //Mobile Id
};
@ -383,7 +420,7 @@ class DashboardApiClient {
Future setAdvertisementViewed(String masterID, int advertisementId, String? ackValue) async {
String url = "${ApiConsts.cocRest}Mohemm_ITG_UpdateAdvertisementAsViewed";
Map<String, dynamic> postParams = {
Map<String, dynamic> postParams = <String, dynamic>{
"ItgNotificationMasterId": masterID,
"EmployeeNumber": AppState().memberInformationList!.eMPLOYEENUMBER.toString(),
"ItgAdvertisementId": advertisementId,
@ -414,4 +451,55 @@ class DashboardApiClient {
// postParams,
// );
// }
Future<GetEmployeeParking?> getEmployeeParkingQrCode() async {
String url = "${ApiConsts.erpRest}GET_Employee_Parking";
Map<String, dynamic> postParams = {};
postParams.addAll(AppState().postParamsJson);
return await ApiClient().postJsonForObject(
(json) {
GetEmployeeParking responseData = GetEmployeeParking.fromJson(json);
return responseData;
},
url,
postParams,
);
}
//Fetch All Courses Status
Future<CoursesResponseModel?> fetchAllCoursesStatus() async {
String url = ApiConsts.eLearningBaseUrl + "Fetch_All_Courses_Status.php";
Map<String, String> headers = {
'x-api-key': 'bLi@mbXJeXTHd/)h&LFh%25+%25(Nbnaq6hBg%7d%5dyQbthY%7bv6ew6-5UT\$NASwucn%7d,_PSJpuwNCCen2%7djj%7b00HR2T-%5b,k7W%7d-0yepK?%258',
'Content-Type': 'application/x-www-form-urlencoded',
};
Map<String, dynamic> postParams = {"username": AppState().memberInformationList?.eMPLOYEENUMBER ?? ""};
return await ApiClient().postJsonForObject(
(json) {
CoursesResponseModel responseData = CoursesResponseModel.fromJson(json);
return responseData;
},
url,
postParams,
headers: headers,
isFormData: false,
);
}
Future<GetGreetingCardsModelResponse?> getGreetingCards() async {
String url = "${ApiConsts.erpRest}Get_GreetingCards";
Map<String, dynamic> postParams = {};
postParams.addAll(AppState().postParamsJson);
return await ApiClient().postJsonForObject(
(json) {
GetGreetingCardsModelResponse responseData = GetGreetingCardsModelResponse.fromJson(json);
return responseData;
},
url,
postParams,
);
}
}

@ -25,16 +25,23 @@ class EITApiClient {
postParams.addAll(AppState().postParamsJson);
return await ApiClient().postJsonForObject(
(json) {
// Check if GetEITTransactionList exists and is not empty
if (json['GetEITTransactionList'] == null || (json['GetEITTransactionList'] is List && json['GetEITTransactionList'].isEmpty)) {
return isCompleteList ? <List<CollectionTransaction>>[] : <CollectionTransaction>[];
}
if (isCompleteList) {
List<List<CollectionTransaction>> responseData = [];
json['GetEITTransactionList'].forEach((element) {
var transactionList = GetEitTransactionsModel.fromJson(element).collectionTransaction;
if (transactionList != null) responseData.add(transactionList);
if (transactionList != null && transactionList.isNotEmpty) {
responseData.add(transactionList);
}
});
return responseData;
} else {
List<CollectionTransaction>? responseData = GetEitTransactionsModel.fromJson(json['GetEITTransactionList'][0]).collectionTransaction;
return responseData;
return responseData ?? <CollectionTransaction>[];
}
},
url,

@ -0,0 +1,140 @@
import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:intl/intl.dart';
import 'package:mohem_flutter_app/api/api_client.dart';
import 'package:mohem_flutter_app/app_state/app_state.dart';
import 'package:mohem_flutter_app/classes/consts.dart';
import 'package:mohem_flutter_app/models/etqan_ovr/etqan_get_employee_incident_report.dart';
import 'package:mohem_flutter_app/models/etqan_ovr/etqan_get_requests_model.dart';
import 'package:mohem_flutter_app/models/etqan_ovr/etqan_getprojects_model.dart';
import 'package:mohem_flutter_app/models/generic_response_model.dart';
import 'package:mohem_flutter_app/models/mowadhafhi/get_department_sections.dart';
import 'package:mohem_flutter_app/models/mowadhafhi/get_project_departments.dart';
import 'package:mohem_flutter_app/models/mowadhafhi/get_projects.dart';
import 'package:mohem_flutter_app/models/mowadhafhi/get_section_topics.dart';
import 'package:mohem_flutter_app/models/mowadhafhi/get_ticket_details.dart';
import 'package:mohem_flutter_app/models/mowadhafhi/get_ticket_transactions.dart';
import 'package:mohem_flutter_app/models/mowadhafhi/get_ticket_types.dart';
import 'package:mohem_flutter_app/models/mowadhafhi/get_tickets_list.dart';
import 'package:mohem_flutter_app/models/mowadhafhi/get_transaction_attachment_model.dart';
class EtqanApiClient {
static final EtqanApiClient _instance = EtqanApiClient._internal();
EtqanApiClient._internal();
factory EtqanApiClient() => _instance;
Future<List<EtqanGetProjectsResponse>> getEtqanProjects() async {
String url = "${ApiConsts.cocRest}ETQAN_GetProjects";
Map<String, dynamic> postParams = <String, dynamic>{"P_SELECTED_EMPLOYEE_NUMBER": AppState().memberInformationList?.eMPLOYEENUMBER};
postParams.addAll(AppState().postParamsJson);
return await ApiClient().postJsonForObject(
(json) {
List<EtqanGetProjectsResponse>? responseData = <EtqanGetProjectsResponse>[];
if (json["ETQAN_GetProjects_Response"] != null && json["ETQAN_GetProjects_Response"].isNotEmpty) {
json["ETQAN_GetProjects_Response"].forEach((element) {
responseData.add(EtqanGetProjectsResponse.fromJson(element));
});
}
return responseData;
},
url,
postParams,
);
}
Future<List<EtqanGetEmployeeOvrRequestsResponse>> getEmployeeEtqanRequests() async {
String url = "${ApiConsts.cocRest}ETQAN_GetEmployeeOVRRequests";
Map<String, dynamic> postParams = <String, dynamic>{
"ETQAN_EmployeeID": AppState().memberInformationList?.eMPLOYEENUMBER,
"P_SELECTED_EMPLOYEE_NUMBER": AppState().memberInformationList?.eMPLOYEENUMBER,
};
postParams.addAll(AppState().postParamsJson);
return await ApiClient().postJsonForObject(
(json) {
List<EtqanGetEmployeeOvrRequestsResponse> responseData = <EtqanGetEmployeeOvrRequestsResponse>[];
if (json["ETQAN_GetEmployeeOVRRequests_Response"] != null && json["ETQAN_GetEmployeeOVRRequests_Response"].isNotEmpty) {
json["ETQAN_GetEmployeeOVRRequests_Response"].forEach((element) {
responseData.add(EtqanGetEmployeeOvrRequestsResponse.fromJson(element));
});
}
if (responseData.isNotEmpty) {
responseData.sort((EtqanGetEmployeeOvrRequestsResponse a, EtqanGetEmployeeOvrRequestsResponse b) {
if (a.createdDate == null && b.createdDate == null) return 0;
if (a.createdDate == null) return 1;
if (b.createdDate == null) return -1;
try {
// Parse dates in format "26-Feb-2026 12:54 PM" or "01-Mar-2026 02:45 PM"
DateFormat dateFormat = DateFormat("dd-MMM-yyyy hh:mm a", "en_US");
DateTime dateA = dateFormat.parse(a.createdDate!);
DateTime dateB = dateFormat.parse(b.createdDate!);
return dateB.compareTo(dateA); // Descending order (newest first)
} catch (e) {
return (b.createdDate ?? '').compareTo(a.createdDate ?? '');
}
});
}
return responseData;
},
url,
postParams,
);
}
Future<List<EtqanGetIncidentRequestResponse>> getEtqanIncidentRequests(String ticketNo) async {
String url = "${ApiConsts.cocRest}ETQAN_GetIncidentRequest";
Map<String, dynamic> postParams = <String, dynamic>{"ETQAN_TicketNumber": ticketNo, "P_SELECTED_EMPLOYEE_NUMBER": AppState().memberInformationList?.eMPLOYEENUMBER};
postParams.addAll(AppState().postParamsJson);
return await ApiClient().postJsonForObject(
(json) {
List<EtqanGetIncidentRequestResponse> responseData = <EtqanGetIncidentRequestResponse>[];
if (json["ETQAN_GetIncidentRequest_Response"] != null && json["ETQAN_GetIncidentRequest_Response"].isNotEmpty) {
json["ETQAN_GetIncidentRequest_Response"].forEach((element) {
responseData.add(EtqanGetIncidentRequestResponse.fromJson(element));
});
}
return responseData;
},
url,
postParams,
);
}
Future<Map<String, dynamic>?> createRequest(String description, int? projectID, String? attachmentBase64, bool? isAnonymous) async {
String url = "${ApiConsts.cocRest}ETQAN_CreateIncident";
Map<String, dynamic> postParams = <String, dynamic>{
"P_SELECTED_EMPLOYEE_NUMBER": AppState().memberInformationList?.eMPLOYEENUMBER,
"P_USER_NAME": AppState().memberInformationList?.eMPLOYEENUMBER,
"ETQAN_Emp_EmployeeNumber": AppState().memberInformationList?.eMPLOYEENUMBER,
"ETQAN_Description": description,
"ETQAN_ProjectId": projectID,
"ETQAN_FileInfoBase64": attachmentBase64,
"ETQAN_IsAnonymous": isAnonymous ?? false,
};
postParams.addAll(AppState().postParamsJson);
return await ApiClient().postJsonForObject(
(json) {
if (json["ETQAN_CreateIncident_Response"] != null) {
var response = json["ETQAN_CreateIncident_Response"];
if (response["id"] != null && response["ticketNumber"] != null) {
return {"id": response["id"], "ticketNumber": response["ticketNumber"]};
}
return null;
}
return null;
// "ETQAN_CreateIncident_Response": {
// "id": "00adabe4-4a32-4b35-1f00-08de4d152e7c",
// "ticketNumber": "OVR/OLY/2026/224"
// },
},
url,
postParams,
);
}
}

@ -71,7 +71,14 @@ class LoginApiClient {
Future<BasicMemberInformationModel?> mohemmSendActivationCodeByOTPNotificationType(int isMobileFingerPrint, String? mobileNumber, int optSendType, String? pUserName) async {
String url = "${ApiConsts.erpRest}Mohemm_SendActivationCodebyOTPNotificationType";
Map<String, dynamic> postParams = {"IsMobileFingerPrint": isMobileFingerPrint, "MobileNumber": mobileNumber, "OTP_SendType": optSendType, "P_USER_NAME": pUserName};
Map<String, dynamic> postParams = {
"IsMobileFingerPrint": isMobileFingerPrint,
"MobileNumber": mobileNumber,
"OTP_SendType": optSendType,
"P_USER_NAME": pUserName,
"NotificationCenterAppGUID": ApiConsts.notificationCenterAppGUID,
"NotificationCenterAppSeviceGUID": ApiConsts.notificationCenterLoginServiceGUID,
};
postParams.addAll(AppState().postParamsJson);
return await ApiClient().postJsonForObject((json) => GenericResponseModel.fromJson(json).basicMemberInformation, url, postParams);
}
@ -105,7 +112,13 @@ class LoginApiClient {
Future<GenericResponseModel?> sendPublicActivationCode(String? mobileNumber, String? pUsername) async {
String url = "${ApiConsts.erpRest}SendPublicActivationCode";
Map<String, dynamic> postParams = {"MobileNumber": mobileNumber, "P_MOBILE_NUMBER": mobileNumber, "P_USER_NAME": pUsername};
Map<String, dynamic> postParams = {
"MobileNumber": mobileNumber,
"P_MOBILE_NUMBER": mobileNumber,
"P_USER_NAME": pUsername,
"NotificationCenterAppGUID": ApiConsts.notificationCenterAppGUID,
"NotificationCenterAppSeviceGUID": ApiConsts.notificationCenterForgotPasswordServiceGUID,
};
postParams.addAll(AppState().postParamsJson);
return await ApiClient().postJsonForObject((json) {
GenericResponseModel responseData = GenericResponseModel.fromJson(json);

@ -90,7 +90,7 @@ class AppState {
String get getHuaweiPushToken => _huaweiPushToken;
final PostParamsModel _postParamsInitConfig = PostParamsModel(channel: 31, versionID: 9.5, mobileType: Platform.isAndroid ? "android" : "ios");
final PostParamsModel _postParamsInitConfig = PostParamsModel(channel: 31, versionID: 10.1, mobileType: Platform.isAndroid ? "android" : "ios");
void setPostParamsInitConfig() {
isAuthenticated = false;

@ -5,14 +5,21 @@ class ApiConsts {
// static String baseUrl = "https://erptstapp.srca.org.sa"; // SRCA server
// static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver
// static String baseUrl = "http://10.201.204.101:2024";
// static String baseUrl = "http://10.201.204.101:2024";
// static String baseUrl = "https://webservices.hmg.com"; // PreProd
// static String baseUrl = "https://hmgwebservices.com"; // Live server
static String baseUrl = "https://mohemm.hmg.com"; // New Live server
// static String baseUrl = "https://mohemm.hmg.com"; // New Live server
static String ssoBaseUrl = "https://sso.hmg.com"; // New Live server
//
// static String baseUrl = "https://uat.hmgwebservices.com"; // UAT ser343622ver
// static String baseUrl = "http://10.20.200.111:1010/";
static String baseUrl = "https://mohemm.hmg.com"; // New Live server
//static String eLearningBaseUrl = "https://elearning.hmg.com/moodle_dev/api/"; // Elearning server UAT
static String eLearningBaseUrl = "https://elearning.hmg.com/moodle/api/"; // Elearning server live
static String enSATLiveURL = "https://ensat.hmg.com/auth/autologin"; // ENSAT server live
// static String baseUrl = "http://10.20.200.111:1010/";
// static String baseUrl = "https://webservices.hmg.com"; // PreProd
// static String baseUrl = "https://mohemm.hmg.com";
@ -27,7 +34,8 @@ class ApiConsts {
static String user = baseUrlServices + "api/User/";
static String cocRest = baseUrlServices + "COCWS.svc/REST/";
static String ssoAuthRedirection = "https://sso-uat.hmg.com/api/auth/connect";
static String ssoAuthRedirection = ssoBaseUrl + "/api/auth/connect";
//Chat
static String chatServerBaseUrl = "https://apiderichat.hmg.com/";
@ -55,6 +63,7 @@ class ApiConsts {
static String marathonBaseUrlUAT = "https://marathoon.com/uatservice/api/";
static String marathonBaseUrl = marathonBaseUrlLive;
// static String marathonBaseUrl = marathonBaseUrlUAT;
static String marathonBaseUrlServices = "https://marathoon.com/service/";
static String marathonParticipantLoginUrl = marathonBaseUrl + "auth/participantlogin";
@ -71,6 +80,11 @@ class ApiConsts {
//DummyCards for the UI
static int tabletMinLength = 500;
// Notification Center GUIDs for OTP
static String notificationCenterAppGUID = "VDZreDY5TTNmTDVudzc4aDkwU3ZqcW9OcmI0";
static String notificationCenterLoginServiceGUID = "D8BD5C76-4B50-4122-81D0-C3AA25DB08A2";
static String notificationCenterForgotPasswordServiceGUID = "5CCCC2C9-EEA0-4207-9BE9-EE1FBBFFE8D0";
}
class SharedPrefsConsts {
@ -86,5 +100,3 @@ class SharedPrefsConsts {
static String mohemmWifiPassword = "mohemmWifiPassword";
static String editItemForSale = "editItemForSale";
}

@ -524,14 +524,47 @@ class DateUtil {
// }
// return "";
// }
static String replaceArabicNumber(String input) {
static String replaceArabicNumber(String? input) {
if (input == null || input.isEmpty) return input ?? "";
const english = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
const arabic = ['٠', '١', '٢', '٣', '٤', '٥', '٦', '٧', '٨', '٩'];
const persian = ['۰', '۱', '۲', '۳', '۴', '۵', '۶', '۷', '۸', '۹'];
for (int i = 0; i < english.length; i++) {
input = input.replaceAll(arabic[i], english[i]);
input = input!.replaceAll(arabic[i], english[i]).replaceAll(persian[i], english[i]);
}
return input;
return input!;
}
static DateTime? parseFlexibleDateTime(String? dateStr) {
if (dateStr == null || dateStr.trim().isEmpty) return null;
String cleanStr = replaceArabicNumber(dateStr.trim()).replaceAll('/"', '').replaceAll('"', '');
if (cleanStr.contains(' 00:00:00')) {
cleanStr = cleanStr.replaceAll(' 00:00:00', '').trim();
}
DateTime? result = DateTime.tryParse(cleanStr);
if (result != null) return result;
if (cleanStr.contains('/')) {
try {
return DateFormat("yyyy/MM/dd", "en_US").parseLoose(cleanStr);
} catch (_) {}
try {
return DateFormat("dd/MM/yyyy", "en_US").parseLoose(cleanStr);
} catch (_) {}
}
if (cleanStr.contains('-')) {
try {
return DateFormat("yyyy-MM-dd", "en_US").parseLoose(cleanStr);
} catch (_) {}
try {
return DateFormat("dd-MM-yyyy", "en_US").parseLoose(cleanStr);
} catch (_) {}
}
return null;
}
}

@ -135,8 +135,8 @@ class Utils {
}
}
static Future showErrorDialog({required BuildContext context, required VoidCallback onOkTapped, required String message}) async {
return showDialog(context: context, builder: (BuildContext context) => ConfirmDialog(message: message, onTap: onOkTapped));
static Future showErrorDialog({required BuildContext context, required VoidCallback onOkTapped, required String message, VoidCallback? onCloseTap}) async {
return showDialog(context: context, builder: (BuildContext context) => ConfirmDialog(message: message, onTap: onOkTapped, onCloseTap: onCloseTap));
}
static void confirmDialog(cxt, String message, {VoidCallback? onTap}) {

@ -10,6 +10,9 @@ import 'package:mohem_flutter_app/ui/chat/favorite_users_screen.dart';
import 'package:mohem_flutter_app/ui/chat/group_chat_detaied_screen.dart';
import 'package:mohem_flutter_app/ui/chat/group_members.dart';
import 'package:mohem_flutter_app/ui/chat/manage_group.dart';
import 'package:mohem_flutter_app/ui/etqan_ovr/etqan_create_request.dart';
import 'package:mohem_flutter_app/ui/etqan_ovr/etqan_ovr_home.dart';
import 'package:mohem_flutter_app/ui/etqan_ovr/etqan_request_detailed.dart';
import 'package:mohem_flutter_app/ui/landing/dashboard_screen.dart';
import 'package:mohem_flutter_app/ui/landing/itg/change_itg_ad_password_screen.dart';
import 'package:mohem_flutter_app/ui/landing/itg/its_add_screen_video_image.dart';
@ -40,6 +43,7 @@ import 'package:mohem_flutter_app/ui/my_team/profile_details.dart';
import 'package:mohem_flutter_app/ui/my_team/subordinate_leave.dart';
import 'package:mohem_flutter_app/ui/my_team/team_members.dart';
import 'package:mohem_flutter_app/ui/my_team/view_attendance.dart';
import 'package:mohem_flutter_app/ui/parking_qr/parking_qr.dart';
import 'package:mohem_flutter_app/ui/payslip/monthly_pay_slip_screen.dart';
import 'package:mohem_flutter_app/ui/performance/performance_appraisal_screen.dart';
import 'package:mohem_flutter_app/ui/profile/add_update_family_member.dart';
@ -54,6 +58,7 @@ import 'package:mohem_flutter_app/ui/profile/profile_screen.dart';
import 'package:mohem_flutter_app/ui/screens/announcements/announcement_details.dart';
import 'package:mohem_flutter_app/ui/screens/announcements/announcements.dart';
import 'package:mohem_flutter_app/ui/screens/child_education/child_education_assistance.dart';
import 'package:mohem_flutter_app/ui/screens/courses/courses_screen.dart';
// import 'package:mohem_flutter_app/ui/my_attendance/work_from_home_screen.dart';
import 'package:mohem_flutter_app/ui/screens/eit/add_eit.dart';
import 'package:mohem_flutter_app/ui/screens/event_activity/event_activity.dart';
@ -166,6 +171,9 @@ class AppRoutes {
static const String offersAndDiscounts = "/offersAndDiscounts";
static const String offersAndDiscountsDetails = "/offersAndDiscountsDetails";
// Courses
static const String courses = "/courses";
//Pay slip
static const String monthlyPaySlip = "/monthlyPaySlip";
@ -211,6 +219,13 @@ class AppRoutes {
static const String activityScreen = "/activityScreen";
static const String etqanOvr = "/etqanOvr";
static const String etqanCreateRequest = "/etqanCreateRequest";
static const String etqanGetIncidientRequest = "/etqanGetIncidientRequest";
//Parking QR
static const String parkingQr = "/parkingQrScreen";
static final Map<String, WidgetBuilder> routes = {
login: (BuildContext context) => LoginScreen(),
verifyLogin: (BuildContext context) => VerifyLoginScreen(),
@ -291,6 +306,9 @@ class AppRoutes {
offersAndDiscounts: (BuildContext context) => OffersAndDiscountsHome(),
offersAndDiscountsDetails: (BuildContext context) => OffersAndDiscountsDetails(),
// Courses
courses: (BuildContext context) => const CoursesScreen(),
//pay slip
monthlyPaySlip: (BuildContext context) => MonthlyPaySlipScreen(),
performanceEvaluation: (BuildContext context) => PerformanceAppraisal(),
@ -328,6 +346,16 @@ class AppRoutes {
unsafeDeviceScreen: (BuildContext context) => const UnsafeDeviceScreen(),
appUpdateScreen: (BuildContext context) => const AppUpdateScreen(),
childEducation: (BuildContext context) => ChildEducationAssistance(),
activityScreen:(BuildContext context) => const EventActivityScreen()
activityScreen:(BuildContext context) => const EventActivityScreen(),
//ETQAN OVR
etqanOvr: (BuildContext context) => EtqanOvrHome(),
etqanCreateRequest: (BuildContext context) => EtqanOvrCreateRequest(),
etqanGetIncidientRequest: (BuildContext context) => EtqanOvrRequestDetailed(),
activityScreen:(BuildContext context) => const EventActivityScreen(),
//Parking QR
parkingQr: (BuildContext context) => const ParkingQrScreen(),
};
}

@ -180,6 +180,7 @@ class CodegenLoader extends AssetLoader{
"quotationAnalysis": "تحليل الاقتباس",
"subject": "موضوعات",
"description": "وصف",
"pleaseEnterDescription": "الرجاء إدخال الوصف",
"supplier": "المورد",
"site": "موقع",
"buyer": "مشتر",
@ -274,6 +275,7 @@ class CodegenLoader extends AssetLoader{
"fullName": "الأسم الكامل",
"remove": "حذف",
"submit": "ارسال",
"submitAsAnonymous": "إرسال كمجهول",
"areYouSureYouWantToSubmit": "هل أنت متأكد أنك تريد أن تقدم؟",
"comments": "تعليقات",
"writeComment": "أكتب تعليقا",
@ -655,7 +657,40 @@ class CodegenLoader extends AssetLoader{
"yearsUsed": "سنوات الاستخدام",
"faRequest": "طلب التخلص من FA",
"showMore": "عرض المزيد",
"buyerDetails": "تفاصيل المشتري"
"ticketDetails": "تفاصيل التذكرة",
"currentTicketBalance": "رصيد التذكرة الحالي",
"ticketHistory": "تاريخ التذكرة",
"proceedBooking": "المتابعة للحجز",
"courses": "الدورات التدريبية",
"course": "دورة",
"status": "الحالة",
"deadline": "الموعد النهائي",
"overdue": "متأخر",
"noCoursesAvailable": "لا توجد دورات متاحة",
"pullToRefresh": "اسحب للتحديث",
"courseUrlNotAvailable": "رابط الدورة غير متوفر",
"buyerDetails": "تفاصيل المشتري",
"etqanOVR": "الإبلاغ عن حادثة",
"etqanRequest": "طلبات الحوادث",
"selectProject": "حدد المشروع",
"project": "مشروع",
"keen": "حريص",
"reportIncident": "الإبلاغ عن الحادث",
"myIncidents": "حوادثي",
"incidentDetails": "تفاصيل الحادث",
"ticketNumber": "رقم التذكرة",
"ticketId": "معرف التذكرة",
"pleaseSelectProject": "الرجاء اختيار مشروع",
"viewAttachment": "عرض المرفق",
"parkingQr": "وقوف السيارات QR",
"startNow": "ابدأ الآن",
"destination_type": "نوع الوجهة",
"source_organization_name": "اسم منظمة المصدر",
"destination_organization_name": "اسم منظمة الوجهة",
"costCenter": "مركز التكلفة",
"priceSAR": "السعر (ريال سعودي)",
"amountSAR": "المبلغ (ريال سعودي)",
"amuLastThreeMonths": "AMU (آخر 3 أشهر)"
};
static const Map<String,dynamic> _en_US = {
"mohemm": "Mohemm",
@ -817,6 +852,7 @@ static const Map<String,dynamic> _en_US = {
"subject": "Subject",
"quotationAnalysis": "Quotation Analysis",
"description": "Description",
"pleaseEnterDescription": "Please enter description",
"supplier": "Supplier",
"site": "Site",
"buyer": "Buyer",
@ -915,6 +951,7 @@ static const Map<String,dynamic> _en_US = {
"remove": "Remove",
"Attendance": "Attendance",
"submit": "Submit",
"submitAsAnonymous": "Submit as Anonymous",
"areYouSureYouWantToSubmit": "Are you sure you want to submit?",
"comments": "Comments",
"writeComment": "Write a comment",
@ -1298,7 +1335,40 @@ static const Map<String,dynamic> _en_US = {
"yearsUsed": "Years Used",
"faRequest": "FA Disposal Request",
"showMore": "Show More",
"buyerDetails": "Buyer Details"
"ticketDetails": "Ticket Details",
"currentTicketBalance": "Current Ticket Balance",
"ticketHistory": "Ticket History",
"proceedBooking": "Proceed For Booking",
"courses": "Courses",
"course": "Course",
"status": "Status",
"deadline": "Deadline",
"overdue": "Overdue",
"noCoursesAvailable": "No Courses Available",
"pullToRefresh": "Pull to refresh",
"courseUrlNotAvailable": "Course URL not available",
"buyerDetails": "Buyer Details",
"etqanOVR": "Report An Incident",
"etqanRequest": "Incident Requests",
"selectProject": "Select Project",
"project": "Project",
"keen": "Keen",
"reportIncident": "Report Incident",
"myIncidents": "My Incidents",
"incidentDetails": "Incident Details",
"ticketNumber": "Ticket Number",
"ticketId": "Ticket ID",
"pleaseSelectProject": "Please select a project",
"viewAttachment": "View Attachment",
"parkingQr": "Parking QR",
"startNow": "Start Now",
"destination_type": "Destination Type",
"source_organization_name": "Source Organization Name",
"destination_organization_name": "Destination Organization Name",
"costCenter": "Cost Center",
"priceSAR": "Price (SAR)",
"amountSAR": "Amount (SAR)",
"amuLastThreeMonths": "AMU (Last 3 months)"
};
static const Map<String, Map<String,dynamic>> mapLocales = {"ar_SA": _ar_SA, "en_US": _en_US};
}

@ -167,6 +167,7 @@ abstract class LocaleKeys {
static const quotationAnalysis = 'quotationAnalysis';
static const subject = 'subject';
static const description = 'description';
static const pleaseEnterDescription = 'pleaseEnterDescription';
static const supplier = 'supplier';
static const site = 'site';
static const buyer = 'buyer';
@ -261,6 +262,7 @@ abstract class LocaleKeys {
static const fullName = 'fullName';
static const remove = 'remove';
static const submit = 'submit';
static const submitAsAnonymous = 'submitAsAnonymous';
static const areYouSureYouWantToSubmit = 'areYouSureYouWantToSubmit';
static const comments = 'comments';
static const writeComment = 'writeComment';
@ -321,6 +323,8 @@ abstract class LocaleKeys {
static const createdFor = 'createdFor';
static const requestCreatedSuccessfully = 'requestCreatedSuccessfully';
static const search = 'search';
static const filterEnterPrDetailsHere = 'filterEnterPrDetailsHere';
static const filterEnterPoDetailsHere = 'filterEnterPoDetailsHere';
static const wantToReject = 'wantToReject';
static const requestType = 'requestType';
static const employeeDigitalID = 'employeeDigitalID';
@ -627,6 +631,39 @@ abstract class LocaleKeys {
static const yearsUsed = 'yearsUsed';
static const faRequest = 'faRequest';
static const showMore = 'showMore';
static const ticketDetails = 'ticketDetails';
static const currentTicketBalance = 'currentTicketBalance';
static const ticketHistory = 'ticketHistory';
static const proceedBooking = 'proceedBooking';
static const courses = 'courses';
static const course = 'course';
static const status = 'status';
static const deadline = 'deadline';
static const overdue = 'overdue';
static const noCoursesAvailable = 'noCoursesAvailable';
static const pullToRefresh = 'pullToRefresh';
static const courseUrlNotAvailable = 'courseUrlNotAvailable';
static const buyerDetails = 'buyerDetails';
static const etqanOVR = 'etqanOVR';
static const etqanRequest = 'etqanRequest';
static const selectProject = 'selectProject';
static const project = 'project';
static const keen = 'keen';
static const reportIncident = 'reportIncident';
static const myIncidents = 'myIncidents';
static const incidentDetails = 'incidentDetails';
static const ticketNumber = 'ticketNumber';
static const ticketId = 'ticketId';
static const pleaseSelectProject = 'pleaseSelectProject';
static const viewAttachment = 'viewAttachment';
static const parkingQr = 'parkingQr';
static const startNow = 'startNow';
static const destination_type = 'destination_type';
static const source_organization_name = 'source_organization_name';
static const destination_organization_name = 'destination_organization_name';
static const costCenter = 'costCenter';
static const priceSAR = 'priceSAR';
static const amountSAR = 'amountSAR';
static const amuLastThreeMonths = 'amuLastThreeMonths';
}

@ -12,6 +12,7 @@ import 'package:mohem_flutter_app/models/post_params_model.dart';
import 'package:mohem_flutter_app/provider/chat_provider_model.dart';
import 'package:mohem_flutter_app/provider/dashboard_provider_model.dart';
import 'package:mohem_flutter_app/provider/eit_provider_model.dart';
import 'package:mohem_flutter_app/provider/etqan_ovr_provider.dart';
import 'package:mohem_flutter_app/theme/app_theme.dart';
import 'package:mohem_flutter_app/ui/marathon/marathon_provider.dart';
import 'package:month_year_picker/month_year_picker.dart';
@ -53,6 +54,7 @@ Future<void> main() async {
ChangeNotifierProvider<EITProviderModel>(create: (_) => EITProviderModel()),
ChangeNotifierProvider<ChatProviderModel>(create: (_) => ChatProviderModel()),
ChangeNotifierProvider<MarathonProvider>(create: (_) => MarathonProvider()),
ChangeNotifierProvider<EtqanOvrProviderModel>(create: (_) => EtqanOvrProviderModel()),
// ChangeNotifierProvider<ChatCallProvider>(
// create: (_) => ChatCallProvider(),
// ),

@ -0,0 +1,94 @@
class CoursesResponseModel {
bool? success;
int? status;
String? username;
List<CourseStatus>? coursesStatus;
int? totalCourses;
CoursesResponseModel({
this.success,
this.status,
this.username,
this.coursesStatus,
this.totalCourses,
});
CoursesResponseModel.fromJson(Map<String, dynamic> json) {
success = json['success'];
status = json['status'];
username = json['username'];
if (json['courses_status'] != null) {
coursesStatus = <CourseStatus>[];
json['courses_status'].forEach((v) {
coursesStatus!.add(CourseStatus.fromJson(v));
});
}
totalCourses = json['total_courses'];
}
Map<String, dynamic> toJson() {
Map<String, dynamic> data = <String, dynamic>{};
data['success'] = success;
data['status'] = status;
data['username'] = username;
if (coursesStatus != null) {
data['courses_status'] = coursesStatus!.map((v) => v.toJson()).toList();
}
data['total_courses'] = totalCourses;
return data;
}
}
class CourseStatus {
String? cId;
String? cFullname;
String? cNameAr;
String? cShortname;
String? cStatus;
String? cIsMohemmAffective;
String? cStartdate;
String? cEnddate;
String? cUrl;
String? token;
CourseStatus({
this.cId,
this.cFullname,
this.cNameAr,
this.cShortname,
this.cStatus,
this.cIsMohemmAffective,
this.cStartdate,
this.cEnddate,
this.cUrl,
this.token
});
CourseStatus.fromJson(Map<String, dynamic> json) {
cId = json['c_id'];
cFullname = json['c_fullname'];
cNameAr = json['c_name_ar'];
cShortname = json['c_shortname'];
cStatus = json['c_status'];
cIsMohemmAffective = json['c_is_mohemm_affective'];
cStartdate = json['c_startdate'];
cEnddate = json['c_enddate'];
cUrl = json['c_url'];
token =json['c_token'];
}
Map<String, dynamic> toJson() {
Map<String, dynamic> data = <String, dynamic>{};
data['c_id'] = cId;
data['c_fullname'] = cFullname;
data['c_name_ar'] = cNameAr;
data['c_shortname'] = cShortname;
data['c_status'] = cStatus;
data['c_is_mohemm_affective'] = cIsMohemmAffective;
data['c_startdate'] = cStartdate;
data['c_enddate'] = cEnddate;
data['c_url'] = cUrl;
data['c_token'] = token;
return data;
}
}

@ -1,7 +1,7 @@
import 'dart:convert';
class GetTicketAccuralBalanceModel {
int? accrualNetEntitlement;
num? accrualNetEntitlement;
String? accuralPlanCode;
GetTicketAccuralBalanceModel({

@ -30,7 +30,7 @@ class CollectionTransaction {
String? dISPLAYFLAG;
int? fROMROWNUM;
int? nOOFROWS;
dynamic? nUMBERVALUE;
dynamic nUMBERVALUE;
int? rOWNUM;
String? sEGMENTNAME;
String? sEGMENTPROMPT;
@ -80,7 +80,7 @@ class CollectionTransaction {
}
Map<String, dynamic> toJson() {
Map<String, dynamic> data = new Map<String, dynamic>();
Map<String, dynamic> data = Map<String, dynamic>();
data['APPLICATION_COLUMN_NAME'] = this.aPPLICATIONCOLUMNNAME;
data['DATATYPE'] = this.dATATYPE;
data['DATE_VALUE'] = this.dATEVALUE;

@ -0,0 +1,97 @@
import 'dart:convert';
class GetEitAttachmentTicket {
List<GetEitAttachmentList>? getEitAttachmentList;
GetEitAttachmentTicket({
this.getEitAttachmentList,
});
factory GetEitAttachmentTicket.fromRawJson(String str) => GetEitAttachmentTicket.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory GetEitAttachmentTicket.fromJson(Map<String, dynamic> json) => GetEitAttachmentTicket(
getEitAttachmentList: json["GetEITAttachmentList"] == null ? [] : List<GetEitAttachmentList>.from(json["GetEITAttachmentList"]!.map((x) => GetEitAttachmentList.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"GetEITAttachmentList": getEitAttachmentList == null ? [] : List<dynamic>.from(getEitAttachmentList!.map((x) => x.toJson())),
};
}
class GetEitAttachmentList {
int? attachedDocumentId;
int? categoryId;
int? datatypeId;
int? documentId;
String? entityName;
String? fileContentType;
String? fileData;
int? fileId;
String? fileName;
String? pk1Value;
String? pk2Value;
String? pk3Value;
String? pk4Value;
String? pk5Value;
int? seqNum;
GetEitAttachmentList({
this.attachedDocumentId,
this.categoryId,
this.datatypeId,
this.documentId,
this.entityName,
this.fileContentType,
this.fileData,
this.fileId,
this.fileName,
this.pk1Value,
this.pk2Value,
this.pk3Value,
this.pk4Value,
this.pk5Value,
this.seqNum,
});
factory GetEitAttachmentList.fromRawJson(String str) => GetEitAttachmentList.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory GetEitAttachmentList.fromJson(Map<String, dynamic> json) => GetEitAttachmentList(
attachedDocumentId: json["ATTACHED_DOCUMENT_ID"],
categoryId: json["CATEGORY_ID"],
datatypeId: json["DATATYPE_ID"],
documentId: json["DOCUMENT_ID"],
entityName: json["ENTITY_NAME"],
fileContentType: json["FILE_CONTENT_TYPE"],
fileData: json["FILE_DATA"],
fileId: json["FILE_ID"],
fileName: json["FILE_NAME"],
pk1Value: json["PK1_VALUE"],
pk2Value: json["PK2_VALUE"],
pk3Value: json["PK3_VALUE"],
pk4Value: json["PK4_VALUE"],
pk5Value: json["PK5_VALUE"],
seqNum: json["SEQ_NUM"],
);
Map<String, dynamic> toJson() => {
"ATTACHED_DOCUMENT_ID": attachedDocumentId,
"CATEGORY_ID": categoryId,
"DATATYPE_ID": datatypeId,
"DOCUMENT_ID": documentId,
"ENTITY_NAME": entityName,
"FILE_CONTENT_TYPE": fileContentType,
"FILE_DATA": fileData,
"FILE_ID": fileId,
"FILE_NAME": fileName,
"PK1_VALUE": pk1Value,
"PK2_VALUE": pk2Value,
"PK3_VALUE": pk3Value,
"PK4_VALUE": pk4Value,
"PK5_VALUE": pk5Value,
"SEQ_NUM": seqNum,
};
}

@ -0,0 +1,57 @@
import 'dart:convert';
class EtqanGetEmployeeIncidentRequestModel {
List<EtqanGetIncidentRequestResponse>? etqanGetIncidentRequestResponse;
EtqanGetEmployeeIncidentRequestModel({
this.etqanGetIncidentRequestResponse,
});
factory EtqanGetEmployeeIncidentRequestModel.fromRawJson(String str) => EtqanGetEmployeeIncidentRequestModel.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory EtqanGetEmployeeIncidentRequestModel.fromJson(Map<String, dynamic> json) => EtqanGetEmployeeIncidentRequestModel(
etqanGetIncidentRequestResponse: json["ETQAN_GetIncidentRequest_Response"] == null ? [] : List<EtqanGetIncidentRequestResponse>.from(json["ETQAN_GetIncidentRequest_Response"]!.map((x) => EtqanGetIncidentRequestResponse.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"ETQAN_GetIncidentRequest_Response": etqanGetIncidentRequestResponse == null ? [] : List<dynamic>.from(etqanGetIncidentRequestResponse!.map((x) => x.toJson())),
};
}
class EtqanGetIncidentRequestResponse {
String? key;
String? keyAr;
String? value;
String? valueAr;
List<String>? subValues;
EtqanGetIncidentRequestResponse({
this.key,
this.keyAr,
this.value,
this.valueAr,
this.subValues,
});
factory EtqanGetIncidentRequestResponse.fromRawJson(String str) => EtqanGetIncidentRequestResponse.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory EtqanGetIncidentRequestResponse.fromJson(Map<String, dynamic> json) => EtqanGetIncidentRequestResponse(
key: json["key"],
keyAr: json["keyAr"],
value: json["value"],
valueAr: json["valueAr"],
subValues: json["subValues"] == null ? [] : List<String>.from(json["subValues"]!.map((x) => x)),
);
Map<String, dynamic> toJson() => {
"key": key,
"keyAr": keyAr,
"value": value,
"valueAr": valueAr,
"subValues": subValues == null ? [] : List<dynamic>.from(subValues!.map((x) => x)),
};
}

@ -0,0 +1,65 @@
import 'dart:convert';
class EtqanGetEmployeeRequestsModel {
List<EtqanGetEmployeeOvrRequestsResponse>? etqanGetEmployeeOvrRequestsResponse;
EtqanGetEmployeeRequestsModel({
this.etqanGetEmployeeOvrRequestsResponse,
});
factory EtqanGetEmployeeRequestsModel.fromRawJson(String str) => EtqanGetEmployeeRequestsModel.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory EtqanGetEmployeeRequestsModel.fromJson(Map<String, dynamic> json) => EtqanGetEmployeeRequestsModel(
etqanGetEmployeeOvrRequestsResponse: json["ETQAN_GetEmployeeOVRRequests_Response"] == null ? [] : List<EtqanGetEmployeeOvrRequestsResponse>.from(json["ETQAN_GetEmployeeOVRRequests_Response"]!.map((x) => EtqanGetEmployeeOvrRequestsResponse.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"ETQAN_GetEmployeeOVRRequests_Response": etqanGetEmployeeOvrRequestsResponse == null ? [] : List<dynamic>.from(etqanGetEmployeeOvrRequestsResponse!.map((x) => x.toJson())),
};
}
class EtqanGetEmployeeOvrRequestsResponse {
String? createdDate;
String? description;
String? id;
bool? isAnonymous;
String? status;
String? statusAr;
String? ticketNumber;
EtqanGetEmployeeOvrRequestsResponse({
this.createdDate,
this.description,
this.id,
this.isAnonymous,
this.status,
this.statusAr,
this.ticketNumber,
});
factory EtqanGetEmployeeOvrRequestsResponse.fromRawJson(String str) => EtqanGetEmployeeOvrRequestsResponse.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory EtqanGetEmployeeOvrRequestsResponse.fromJson(Map<String, dynamic> json) => EtqanGetEmployeeOvrRequestsResponse(
createdDate: json["createdDate"],
description: json["description"],
id: json["id"],
isAnonymous: json["isAnonymous"],
status: json["status"],
statusAr: json["statusAr"],
ticketNumber: json["ticketNumber"],
);
Map<String, dynamic> toJson() => {
"createdDate": createdDate,
"description": description,
"id": id,
"isAnonymous": isAnonymous,
"status": status,
"statusAr": statusAr,
"ticketNumber": ticketNumber,
};
}

@ -0,0 +1,53 @@
import 'dart:convert';
class EtqanGetProjectsModel {
List<EtqanGetProjectsResponse>? etqanGetProjectsResponse;
EtqanGetProjectsModel({
this.etqanGetProjectsResponse,
});
factory EtqanGetProjectsModel.fromRawJson(String str) => EtqanGetProjectsModel.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory EtqanGetProjectsModel.fromJson(Map<String, dynamic> json) => EtqanGetProjectsModel(
etqanGetProjectsResponse: json["ETQAN_GetProjects_Response"] == null ? [] : List<EtqanGetProjectsResponse>.from(json["ETQAN_GetProjects_Response"]!.map((x) => EtqanGetProjectsResponse.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"ETQAN_GetProjects_Response": etqanGetProjectsResponse == null ? [] : List<dynamic>.from(etqanGetProjectsResponse!.map((x) => x.toJson())),
};
}
class EtqanGetProjectsResponse {
String? projectAr;
String? projectCode;
String? projectEn;
int? projectId;
EtqanGetProjectsResponse({
this.projectAr,
this.projectCode,
this.projectEn,
this.projectId,
});
factory EtqanGetProjectsResponse.fromRawJson(String str) => EtqanGetProjectsResponse.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory EtqanGetProjectsResponse.fromJson(Map<String, dynamic> json) => EtqanGetProjectsResponse(
projectAr: json["projectAr"],
projectCode: json["projectCode"],
projectEn: json["projectEn"],
projectId: json["projectId"],
);
Map<String, dynamic> toJson() => {
"projectAr": projectAr,
"projectCode": projectCode,
"projectEn": projectEn,
"projectId": projectId,
};
}

@ -398,6 +398,7 @@ class GenericResponseModel {
bool? isActiveCode;
bool? isSMSSent;
PortalDirectionData? portalDirectionData;
String? Mohemm_ENSAT_GetItgToken_Response;
GenericResponseModel({
this.date,
@ -669,7 +670,8 @@ class GenericResponseModel {
this.ePharmacyGetItemOnHandList,
this.isActiveCode,
this.isSMSSent,
this.getFADisposalNtfDetails
this.getFADisposalNtfDetails,
this.Mohemm_ENSAT_GetItgToken_Response,
});
GenericResponseModel.fromJson(Map<String, dynamic> json) {
@ -943,7 +945,6 @@ class GenericResponseModel {
getFADisposalNtfDetails = json['GetFADisposalNtfDetails'] != null ? GetFaDisposalNtfDetails.fromJson(json['GetFADisposalNtfDetails']) : null;
if (json['GetEarningsList'] != null) {
getEarningsList = <GetEarningsList>[];
json['GetEarningsList'].forEach((v) {
@ -1464,6 +1465,7 @@ class GenericResponseModel {
ePharmacyGetItemOnHandList = json['ePharmacy_GetItemOnHandList'];
isActiveCode = json['isActiveCode'];
isSMSSent = json['isSMSSent'];
Mohemm_ENSAT_GetItgToken_Response = json['Mohemm_ENSAT_GetItgToken_Response'];
}
Map<String, dynamic> toJson() {
@ -1561,7 +1563,7 @@ class GenericResponseModel {
if (this.getActionHistoryList != null) {
data['GetActionHistoryList'] = this.getActionHistoryList!.map((v) => v.toJson()).toList();
}
data['GetFADisposalNtfDetails'] =this.getFADisposalNtfDetails;
data['GetFADisposalNtfDetails'] = this.getFADisposalNtfDetails;
data['GetAddressDffStructureList'] = this.getAddressDffStructureList;
data['GetAddressNotificationBodyList'] = this.getAddressNotificationBodyList;
@ -1949,6 +1951,7 @@ class GenericResponseModel {
data['ePharmacy_GetItemOnHandList'] = this.ePharmacyGetItemOnHandList;
data['isActiveCode'] = this.isActiveCode;
data['isSMSSent'] = this.isSMSSent;
data['Mohemm_ENSAT_GetItgToken_Response'] = this.Mohemm_ENSAT_GetItgToken_Response;
return data;
}
}

@ -22,6 +22,8 @@ class GetDayHoursTypeDetailsList {
dynamic? fROMROWNUM;
String? lATEINFLAG;
String? lATEINHRS;
String? lEAVEDESCRIPTION;
String? lEAVETYPECODE;
String? mISSINGSWIPEFLAG;
String? nONSCHEDULEDFLAG;
dynamic? nOOFROWS;
@ -66,6 +68,8 @@ class GetDayHoursTypeDetailsList {
this.fROMROWNUM,
this.lATEINFLAG,
this.lATEINHRS,
this.lEAVEDESCRIPTION,
this.lEAVETYPECODE,
this.mISSINGSWIPEFLAG,
this.nONSCHEDULEDFLAG,
this.nOOFROWS,
@ -110,6 +114,8 @@ class GetDayHoursTypeDetailsList {
fROMROWNUM = json['FROM_ROW_NUM'];
lATEINFLAG = json['LATE_IN_FLAG'];
lATEINHRS = json['LATE_IN_HRS'];
lEAVEDESCRIPTION = json['LEAVE_DESCRIPTION'];
lEAVETYPECODE = json['LEAVE_TYPE_CODE'];
mISSINGSWIPEFLAG = json['MISSING_SWIPE_FLAG'];
nONSCHEDULEDFLAG = json['NON_SCHEDULED_FLAG'];
nOOFROWS = json['NO_OF_ROWS'];
@ -156,6 +162,8 @@ class GetDayHoursTypeDetailsList {
data['FROM_ROW_NUM'] = this.fROMROWNUM;
data['LATE_IN_FLAG'] = this.lATEINFLAG;
data['LATE_IN_HRS'] = this.lATEINHRS;
data['LEAVE_DESCRIPTION'] = this.lEAVEDESCRIPTION;
data['LEAVE_TYPE_CODE'] = this.lEAVETYPECODE;
data['MISSING_SWIPE_FLAG'] = this.mISSINGSWIPEFLAG;
data['NON_SCHEDULED_FLAG'] = this.nONSCHEDULEDFLAG;
data['NO_OF_ROWS'] = this.nOOFROWS;

@ -0,0 +1,61 @@
import 'dart:convert';
class GetEmployeeParking {
GetEmployeeParkingClass? getEmployeeParking;
GetEmployeeParking({
this.getEmployeeParking,
});
factory GetEmployeeParking.fromRawJson(String str) => GetEmployeeParking.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory GetEmployeeParking.fromJson(Map<String, dynamic> json) => GetEmployeeParking(
getEmployeeParking: json["GET_Employee_Parking"] == null ? null : GetEmployeeParkingClass.fromJson(json["GET_Employee_Parking"]),
);
Map<String, dynamic> toJson() => {
"GET_Employee_Parking": getEmployeeParking?.toJson(),
};
}
class GetEmployeeParkingClass {
DateTime? createdAt;
String? employeeCode;
String? isNewQrCode;
String? qrCode;
String? qrCodeImageBase64;
bool? success;
GetEmployeeParkingClass({
this.createdAt,
this.employeeCode,
this.isNewQrCode,
this.qrCode,
this.qrCodeImageBase64,
this.success,
});
factory GetEmployeeParkingClass.fromRawJson(String str) => GetEmployeeParkingClass.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory GetEmployeeParkingClass.fromJson(Map<String, dynamic> json) => GetEmployeeParkingClass(
createdAt: json["createdAt"] == null ? null : DateTime.parse(json["createdAt"]),
employeeCode: json["employeeCode"],
isNewQrCode: json["isNewQRCode"],
qrCode: json["qrCode"],
qrCodeImageBase64: json["qrCodeImageBase64"],
success: json["success"],
);
Map<String, dynamic> toJson() => {
"createdAt": createdAt?.toIso8601String(),
"employeeCode": employeeCode,
"isNewQRCode": isNewQrCode,
"qrCode": qrCode,
"qrCodeImageBase64": qrCodeImageBase64,
"success": success,
};
}

@ -5,12 +5,13 @@ class GetPrNotificationBodyList {
String? pINFORMATION;
String? pQUESTION;
GetPrNotificationBodyList(
{this.pRHeader,
this.pRLines,
this.pCURRENCYCODE,
this.pINFORMATION,
this.pQUESTION});
GetPrNotificationBodyList({
this.pRHeader,
this.pRLines,
this.pCURRENCYCODE,
this.pINFORMATION,
this.pQUESTION,
});
GetPrNotificationBodyList.fromJson(Map<String, dynamic> json) {
if (json['PRHeader'] != null) {
@ -78,21 +79,28 @@ class PRLines {
int? tOROWNUM;
num? uNITPRICE;
String? uOM;
String? dESTINATIONTYPE;
String? sOURCEORGANIZATIONNAME;
String? dESTINATIONORGANIZATIONNAME;
PRLines(
{this.cOSTCENTER,
this.dESCRIPTION,
this.fROMROWNUM,
this.iTEMAMU,
this.iTEMCODE,
this.lINEAMOUNT,
this.lINENUM,
this.nOOFROWS,
this.qUANTITY,
this.rOWNUM,
this.tOROWNUM,
this.uNITPRICE,
this.uOM});
PRLines({
this.cOSTCENTER,
this.dESCRIPTION,
this.fROMROWNUM,
this.iTEMAMU,
this.iTEMCODE,
this.lINEAMOUNT,
this.lINENUM,
this.nOOFROWS,
this.qUANTITY,
this.rOWNUM,
this.tOROWNUM,
this.uNITPRICE,
this.uOM,
this.dESTINATIONTYPE,
this.sOURCEORGANIZATIONNAME,
this.dESTINATIONORGANIZATIONNAME,
});
PRLines.fromJson(Map<String, dynamic> json) {
cOSTCENTER = json['COST_CENTER'];
@ -108,6 +116,9 @@ class PRLines {
tOROWNUM = json['TO_ROW_NUM'];
uNITPRICE = json['UNIT_PRICE'];
uOM = json['UOM'];
dESTINATIONTYPE = json['DESTINATION_TYPE'];
sOURCEORGANIZATIONNAME = json['SOURCE_ORGANIZATION_NAME'];
dESTINATIONORGANIZATIONNAME = json['DESTINATION_ORGANIZATION_NAME'];
}
Map<String, dynamic> toJson() {
@ -125,6 +136,9 @@ class PRLines {
data['TO_ROW_NUM'] = this.tOROWNUM;
data['UNIT_PRICE'] = this.uNITPRICE;
data['UOM'] = this.uOM;
data['DESTINATION_TYPE'] = this.dESTINATIONTYPE;
data['SOURCE_ORGANIZATION_NAME'] = this.sOURCEORGANIZATIONNAME;
data['DESTINATION_ORGANIZATION_NAME'] = this.dESTINATIONORGANIZATIONNAME;
return data;
}
}

@ -0,0 +1,142 @@
import 'dart:convert';
class GetGreetingCardsModelResponse {
List<GetGreetingCardsModelResponseElement>? getGreetingCardsModelResponse;
GetGreetingCardsModelResponse({
this.getGreetingCardsModelResponse,
});
factory GetGreetingCardsModelResponse.fromRawJson(String str) => GetGreetingCardsModelResponse.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory GetGreetingCardsModelResponse.fromJson(Map<String, dynamic> json) => GetGreetingCardsModelResponse(
getGreetingCardsModelResponse: json["Get_GreetingCardsModel_Response"] == null ? [] : List<GetGreetingCardsModelResponseElement>.from(json["Get_GreetingCardsModel_Response"]!.map((x) => GetGreetingCardsModelResponseElement.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"Get_GreetingCardsModel_Response": getGreetingCardsModelResponse == null ? [] : List<dynamic>.from(getGreetingCardsModelResponse!.map((x) => x.toJson())),
};
}
class GetGreetingCardsModelResponseElement {
String? backgroundImageUrlAr;
String? backgroundImageUrlEn;
String? buttonBgColor;
String? buttonText;
String? buttonTextN;
int? cardType;
int? categoryId;
String? categoryNameAr;
String? categoryNameEn;
int? channel;
String? createdOn;
String? descriptionAr;
String? descriptionEn;
String? endDate;
bool? hasButton;
int? id;
bool? isActive;
int? moduleId;
String? moduleName;
String? moduleNameN;
String? startDate;
String? textColor;
String? titleAr;
String? titleEn;
String? urlAr;
String? urlEn;
GetGreetingCardsModelResponseElement({
this.backgroundImageUrlAr,
this.backgroundImageUrlEn,
this.buttonBgColor,
this.buttonText,
this.buttonTextN,
this.cardType,
this.categoryId,
this.categoryNameAr,
this.categoryNameEn,
this.channel,
this.createdOn,
this.descriptionAr,
this.descriptionEn,
this.endDate,
this.hasButton,
this.id,
this.isActive,
this.moduleId,
this.moduleName,
this.moduleNameN,
this.startDate,
this.textColor,
this.titleAr,
this.titleEn,
this.urlAr,
this.urlEn,
});
factory GetGreetingCardsModelResponseElement.fromRawJson(String str) => GetGreetingCardsModelResponseElement.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory GetGreetingCardsModelResponseElement.fromJson(Map<String, dynamic> json) => GetGreetingCardsModelResponseElement(
backgroundImageUrlAr: json["BackgroundImageUrlAr"],
backgroundImageUrlEn: json["BackgroundImageUrlEn"],
buttonBgColor: json["ButtonBgColor"],
buttonText: json["ButtonText"],
buttonTextN: json["ButtonTextN"],
cardType: json["CardType"],
categoryId: json["CategoryID"],
categoryNameAr: json["CategoryNameAr"],
categoryNameEn: json["CategoryNameEn"],
channel: json["Channel"],
createdOn: json["CreatedOn"],
descriptionAr: json["DescriptionAr"],
descriptionEn: json["DescriptionEn"],
endDate: json["EndDate"],
hasButton: json["HasButton"],
id: json["ID"],
isActive: json["IsActive"],
moduleId: json["ModuleID"],
moduleName: json["ModuleName"],
moduleNameN: json["ModuleNameN"],
startDate: json["StartDate"],
textColor: json["TextColor"],
titleAr: json["TitleAr"],
titleEn: json["TitleEn"],
urlAr: json["UrlAr"],
urlEn: json["UrlEn"],
);
Map<String, dynamic> toJson() => {
"BackgroundImageUrlAr": backgroundImageUrlAr,
"BackgroundImageUrlEn": backgroundImageUrlEn,
"ButtonBgColor": buttonBgColor,
"ButtonText": buttonText,
"ButtonTextN": buttonTextN,
"CardType": cardType,
"CategoryID": categoryId,
"CategoryNameAr": categoryNameAr,
"CategoryNameEn": categoryNameEn,
"Channel": channel,
"CreatedOn": createdOn,
"DescriptionAr": descriptionAr,
"DescriptionEn": descriptionEn,
"EndDate": endDate,
"HasButton": hasButton,
"ID": id,
"IsActive": isActive,
"ModuleID": moduleId,
"ModuleName": moduleName,
"ModuleNameN": moduleNameN,
"StartDate": startDate,
"TextColor": textColor,
"TitleAr": titleAr,
"TitleEn": titleEn,
"UrlAr": urlAr,
"UrlEn": urlEn,
};
}

@ -136,10 +136,21 @@ class ActionButtonsColl {
late String btnTextEn;
late String btnTextAr;
late String actionValue;
late dynamic iconOrImage;
dynamic iconOrImage;
String? actionType;
late int orderNo;
String? url;
ActionButtonsColl({required this.actionButtonId, required this.btnTextEn, required this.btnTextAr, required this.actionValue, required this.iconOrImage, required this.orderNo});
ActionButtonsColl({
required this.actionButtonId,
required this.btnTextEn,
required this.btnTextAr,
required this.actionValue,
this.iconOrImage,
this.actionType,
required this.orderNo,
this.url,
});
ActionButtonsColl.fromJson(Map<String, dynamic> json) {
actionButtonId = json['actionButtonId'];
@ -147,7 +158,9 @@ class ActionButtonsColl {
btnTextAr = json['btnTextAr'];
actionValue = json['actionValue'];
iconOrImage = json['iconOrImage'];
actionType = json['actionType'];
orderNo = json['orderNo'];
url = json['url'];
}
Map<String, dynamic> toJson() {
@ -157,7 +170,9 @@ class ActionButtonsColl {
data['btnTextAr'] = this.btnTextAr;
data['actionValue'] = this.actionValue;
data['iconOrImage'] = this.iconOrImage;
data['actionType'] = this.actionType;
data['orderNo'] = this.orderNo;
data['url'] = this.url;
return data;
}
}

@ -12,12 +12,7 @@ MohemmItgResponseItem mohemmItgResponseItemFromJson(String str) => MohemmItgResp
String mohemmItgResponseItemToJson(MohemmItgResponseItem data) => json.encode(data.toJson());
class MohemmItgResponseItem {
MohemmItgResponseItem({
this.statusCode,
this.message,
this.originalErrMsg,
this.result,
});
MohemmItgResponseItem({this.statusCode, this.message, this.originalErrMsg, this.result});
final int? statusCode;
final dynamic? message;
@ -25,77 +20,64 @@ class MohemmItgResponseItem {
final ItgResponseResult? result;
factory MohemmItgResponseItem.fromJson(Map<String, dynamic> json) => MohemmItgResponseItem(
statusCode: json["statusCode"] == null ? null : json["statusCode"],
message: json["message"],
originalErrMsg: json["originalErrMsg"],
result: json["result"] == null ? null : ItgResponseResult.fromJson(json["result"]),
);
statusCode: json["statusCode"] == null ? null : json["statusCode"],
message: json["message"],
originalErrMsg: json["originalErrMsg"],
result: json["result"] == null ? null : ItgResponseResult.fromJson(json["result"]),
);
Map<String, dynamic> toJson() => {
"statusCode": statusCode == null ? null : statusCode,
"message": message,
"originalErrMsg": originalErrMsg,
"result": result == null ? null : result!.toJson(),
};
Map<String, dynamic> toJson() => {"statusCode": statusCode == null ? null : statusCode, "message": message, "originalErrMsg": originalErrMsg, "result": result == null ? null : result!.toJson()};
}
class ItgResponseResult {
ItgResponseResult({
this.totalItemsCount,
this.data,
this.errormsg,
});
//
// final dynamic totalItemsCount;
// final ItgResponseData? data;
// final dynamic errormsg;
//
// factory ItgResponseResult.fromJson(Map<String, dynamic> json) => ItgResponseResult(
// totalItemsCount: json["totalItemsCount"],
// data: json["data"] == null ? null : ItgResponseData.fromJson(json["data"]),
// errormsg: json["errormsg"],
// );
//
// Map<String, dynamic> toJson() => {
// "totalItemsCount": totalItemsCount,
// "data": data == null ? null : data!.toJson(),
// "errormsg": errormsg,
// };
// }
// todo these lines, for ERM new change on UAT
dynamic totalItemsCount;
List<ItgResponseData>? data;
dynamic errormsg;
ItgResponseResult.fromJson(Map<String, dynamic> json) {
totalItemsCount = json['totalItemsCount'];
if (json['data'] != null) {
data = [];
if(json['data'] is List) {
json['data'].forEach((v) {
data!.add(ItgResponseData.fromJson(v));
});
} else {
data!.add(ItgResponseData.fromJson(json['data']));
ItgResponseResult({this.totalItemsCount, this.data, this.errormsg});
//
// final dynamic totalItemsCount;
// final ItgResponseData? data;
// final dynamic errormsg;
//
// factory ItgResponseResult.fromJson(Map<String, dynamic> json) => ItgResponseResult(
// totalItemsCount: json["totalItemsCount"],
// data: json["data"] == null ? null : ItgResponseData.fromJson(json["data"]),
// errormsg: json["errormsg"],
// );
//
// Map<String, dynamic> toJson() => {
// "totalItemsCount": totalItemsCount,
// "data": data == null ? null : data!.toJson(),
// "errormsg": errormsg,
// };
// }
// todo these lines, for ERM new change on UAT
dynamic totalItemsCount;
List<ItgResponseData>? data;
dynamic errormsg;
ItgResponseResult.fromJson(Map<String, dynamic> json) {
totalItemsCount = json['totalItemsCount'];
if (json['data'] != null) {
data = [];
if (json['data'] is List) {
json['data'].forEach((v) {
data!.add(ItgResponseData.fromJson(v));
});
} else {
data!.add(ItgResponseData.fromJson(json['data']));
}
}
errormsg = json['errormsg'];
}
errormsg = json['errormsg'];
}
//
// factory ItgResponseResult.fromJson(Map<String, dynamic> json) => ItgResponseResult(
// totalItemsCount: json["totalItemsCount"],
// data: json["data"] == null ? null : ItgResponseData.fromJson(json["data"]),
// errormsg: json["errormsg"],
// );
Map<String, dynamic> toJson() => {
"totalItemsCount": totalItemsCount,
"data": data == null ? null : data!.map((v) => v.toJson()).toList(),
"errormsg": errormsg,
};
//
// factory ItgResponseResult.fromJson(Map<String, dynamic> json) => ItgResponseResult(
// totalItemsCount: json["totalItemsCount"],
// data: json["data"] == null ? null : ItgResponseData.fromJson(json["data"]),
// errormsg: json["errormsg"],
// );
Map<String, dynamic> toJson() => {"totalItemsCount": totalItemsCount, "data": data == null ? null : data!.map((v) => v.toJson()).toList(), "errormsg": errormsg};
}
class ItgResponseData {
@ -121,6 +103,7 @@ class ItgResponseData {
this.pageSize,
this.pageNo,
this.languageId,
this.deadline,
});
final String? notificationMasterId;
@ -144,52 +127,55 @@ class ItgResponseData {
final dynamic pageSize;
final dynamic pageNo;
final dynamic languageId;
dynamic deadline;
factory ItgResponseData.fromJson(Map<String, dynamic> json) => ItgResponseData(
notificationMasterId: json["notificationMasterId"] == null ? null : json["notificationMasterId"],
notificationType: json["notificationType"] == null ? null : json["notificationType"],
referenceItemId: json["referenceItemId"] == null ? null : json["referenceItemId"],
notificationTitle: json["notificationTitle"] == null ? null : json["notificationTitle"],
enableAt: json["enableAt"] == null ? null : json["enableAt"],
applicationItemId: json["applicationItemId"],
startDate: json["startDate"],
endDate: json["endDate"],
isRepeat: json["isRepeat"] == null ? null : json["isRepeat"],
channelId: json["channelId"] == null ? null : json["channelId"],
serviceId: json["serviceId"] == null ? null : json["serviceId"],
channelName: json["channelName"] == null ? null : json["channelName"],
serviceName: json["serviceName"] == null ? null : json["serviceName"],
isDeleted: json["isDeleted"] == null ? null : json["isDeleted"],
showDelete: json["showDelete"] == null ? null : json["showDelete"],
advertisement: json["advertisement"] == null ? null : Advertisement.fromJson(json["advertisement"]),
survey: json["survey"] == null ? null : SurveyModel.fromJson(json["survey"]),
isActive: json["isActive"],
pageSize: json["pageSize"],
pageNo: json["pageNo"],
languageId: json["languageId"],
);
notificationMasterId: json["notificationMasterId"] == null ? null : json["notificationMasterId"],
notificationType: json["notificationType"] == null ? null : json["notificationType"],
referenceItemId: json["referenceItemId"] == null ? null : json["referenceItemId"],
notificationTitle: json["notificationTitle"] == null ? null : json["notificationTitle"],
enableAt: json["enableAt"] == null ? null : json["enableAt"],
applicationItemId: json["applicationItemId"],
startDate: json["startDate"],
endDate: json["endDate"],
deadline: json["deadline"] == null ? null : json["deadline"],
isRepeat: json["isRepeat"] == null ? null : json["isRepeat"],
channelId: json["channelId"] == null ? null : json["channelId"],
serviceId: json["serviceId"] == null ? null : json["serviceId"],
channelName: json["channelName"] == null ? null : json["channelName"],
serviceName: json["serviceName"] == null ? null : json["serviceName"],
isDeleted: json["isDeleted"] == null ? null : json["isDeleted"],
showDelete: json["showDelete"] == null ? null : json["showDelete"],
advertisement: json["advertisement"] == null ? null : Advertisement.fromJson(json["advertisement"]),
survey: json["survey"] == null ? null : SurveyModel.fromJson(json["survey"]),
isActive: json["isActive"],
pageSize: json["pageSize"],
pageNo: json["pageNo"],
languageId: json["languageId"],
);
Map<String, dynamic> toJson() => {
"notificationMasterId": notificationMasterId == null ? null : notificationMasterId,
"notificationType": notificationType == null ? null : notificationType,
"referenceItemId": referenceItemId == null ? null : referenceItemId,
"notificationTitle": notificationTitle == null ? null : notificationTitle,
"enableAt": enableAt == null ? null : enableAt,
"applicationItemId": applicationItemId,
"startDate": startDate,
"endDate": endDate,
"isRepeat": isRepeat == null ? null : isRepeat,
"channelId": channelId == null ? null : channelId,
"serviceId": serviceId == null ? null : serviceId,
"channelName": channelName == null ? null : channelName,
"serviceName": serviceName == null ? null : serviceName,
"isDeleted": isDeleted == null ? null : isDeleted,
"showDelete": showDelete == null ? null : showDelete,
"advertisement": advertisement,
"survey": survey,
"isActive": isActive,
"pageSize": pageSize,
"pageNo": pageNo,
"languageId": languageId,
};
"notificationMasterId": notificationMasterId == null ? null : notificationMasterId,
"notificationType": notificationType == null ? null : notificationType,
"referenceItemId": referenceItemId == null ? null : referenceItemId,
"notificationTitle": notificationTitle == null ? null : notificationTitle,
"enableAt": enableAt == null ? null : enableAt,
"applicationItemId": applicationItemId,
"startDate": startDate,
"endDate": endDate,
"deadline": deadline == null ? null : deadline ,
"isRepeat": isRepeat == null ? null : isRepeat,
"channelId": channelId == null ? null : channelId,
"serviceId": serviceId == null ? null : serviceId,
"channelName": channelName == null ? null : channelName,
"serviceName": serviceName == null ? null : serviceName,
"isDeleted": isDeleted == null ? null : isDeleted,
"showDelete": showDelete == null ? null : showDelete,
"advertisement": advertisement,
"survey": survey,
"isActive": isActive,
"pageSize": pageSize,
"pageNo": pageNo,
"languageId": languageId,
};
}

@ -19,8 +19,11 @@ import 'package:mohem_flutter_app/models/dashboard/list_menu.dart';
import 'package:mohem_flutter_app/models/dashboard/menu_entries.dart';
import 'package:mohem_flutter_app/models/dashboard/menus.dart';
import 'package:mohem_flutter_app/models/dashboard/mohemm_itg_pending_task_responseitem.dart';
import 'package:mohem_flutter_app/models/dashboard/courses_response_model.dart';
import 'package:mohem_flutter_app/models/eit/get_eit_transaction_model.dart';
import 'package:mohem_flutter_app/models/eit_attachment_ticket_model.dart';
import 'package:mohem_flutter_app/models/generic_response_model.dart';
import 'package:mohem_flutter_app/models/greetings/greeting_card_model.dart';
import 'package:mohem_flutter_app/models/itg/itg_response_model.dart';
import 'package:mohem_flutter_app/models/offers_and_discounts/get_offers_list.dart';
import 'package:mohem_flutter_app/models/sso_auth_model.dart';
@ -67,6 +70,15 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
bool isOffersLoading = true;
List<OffersListModel> getOffersList = [];
//Courses
bool isCoursesLoading = true;
CoursesResponseModel? coursesResponse;
List<CourseStatus> coursesList = [];
bool isGreetingCardsLoading = true;
bool isDisplayEidGreetings = false;
List<GetGreetingCardsModelResponseElement>? greetingCardsList;
//Attendance Tracking API's & Methods
Future<bool> fetchAttendanceTracking(context) async {
try {
@ -115,12 +127,18 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
getMenuEntriesList = null;
isOffersLoading = true;
getOffersList = [];
isGreetingCardsLoading = true;
isDisplayEidGreetings = false;
drawerMenuItemList = [
DrawerMenuItem("assets/images/drawer/my_profile.svg", LocaleKeys.myProfile.tr(), AppRoutes.profile),
DrawerMenuItem("assets/images/drawer/performance_evaluation.svg", LocaleKeys.performanceEvaluation.tr(), AppRoutes.performanceEvaluation),
DrawerMenuItem("assets/images/drawer/mowadhafi.svg", LocaleKeys.mowadhafhi.tr(), AppRoutes.mowadhafhi),
// DrawerMenuItem("assets/images/drawer/mowadhafi.svg", LocaleKeys.etqanOVR.tr(), AppRoutes.etqanOvr),
DrawerMenuItem("assets/images/drawer/mowadhafi.svg", LocaleKeys.keen.tr(), AppRoutes.etqanOvr),
DrawerMenuItem("assets/images/drawer/car_parking_icon.svg", LocaleKeys.parkingQr.tr(), AppRoutes.parkingQr),
DrawerMenuItem("assets/images/drawer/pending_trasactions.svg", LocaleKeys.pendingTransactions.tr(), AppRoutes.pendingTransactions),
DrawerMenuItem("assets/images/drawer/courses.svg", "courses".tr(), AppRoutes.courses),
// DrawerMenuItem("assets/images/drawer/drawer_marathon.svg", LocaleKeys.brainMarathon.tr(), AppRoutes.marathonIntroScreen),
DrawerMenuItem("assets/images/drawer/change_password.svg", LocaleKeys.changePassword.tr(), AppRoutes.changePassword),
];
@ -306,10 +324,33 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
}
}
void fetchGreetingCards() async {
isGreetingCardsLoading = true;
notifyListeners();
try {
GetGreetingCardsModelResponse? response = await DashboardApiClient().getGreetingCards();
greetingCardsList = response?.getGreetingCardsModelResponse ?? [];
if (greetingCardsList != null && greetingCardsList!.isNotEmpty) {
isDisplayEidGreetings = greetingCardsList!.any((card) => card.isActive == true);
} else {
isDisplayEidGreetings = false;
}
isGreetingCardsLoading = false;
notifyListeners();
} catch (ex) {
logger.wtf(ex);
isDisplayEidGreetings = false;
greetingCardsList = [];
isGreetingCardsLoading = false;
notifyListeners();
}
}
Future<void> fetchTicketBooking() async {
try {
GenericResponseModel? genericResponseModel = await DashboardApiClient().getTicketBookingRedirection();
if (genericResponseModel?.portalDirectionData?.pRedirection!.toLowerCase() == "alma") {
// ticketBookingResponse = TicketBookingResult(true, "a9f4d1a0596d4aea8f830992ec4bdac1");
ticketBookingResponse = TicketBookingResult(true, genericResponseModel?.portalDirectionData?.clientID);
return;
}
@ -319,15 +360,13 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
isEventLoadingLoading = false;
notifyListeners();
Utils.handleException(ex, null, null);
ticketBookingResponse = TicketBookingResult(false, null); // Ensure a return value in case of an exception
ticketBookingResponse = TicketBookingResult(false, null);
}
}
void fetchTicketBalance() async {
try {
GenericResponseModel? ticketResponse = await DashboardApiClient().getTicketBalance();
logger.d("Ticket Balance Response: ${ticketResponse?.toJson()}");
print(" ========= Ticket Balance Response ======= ");
} catch (ex) {
logger.wtf(ex);
isEventLoadingLoading = false;
@ -340,8 +379,7 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
Future<SSOAuthModel?> fetchSSOAuthRedirection({String? clientID}) async {
try {
SSOAuthModel? ssoResponse = await DashboardApiClient().getBookingSSOAuthRedirection(clientID: clientID!);
logger.d("SSO Response: ${ssoResponse!.toJson()}");
if (ssoResponse.status == "Success") {
if (ssoResponse!.status == "Success") {
return ssoResponse;
} else {
Utils.showToast(ssoResponse.message!.first ?? "Failed to fetch SSO Auth Token");
@ -356,17 +394,28 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
}
}
Future<dynamic> fetchURLRedirection({required String token}) async {
Future<dynamic> fetchURLRedirection({required String token, required String refreshToken}) async {
try {
dynamic res = await DashboardApiClient().getBookingSSOFinalRedirection(token: token);
dynamic res = await DashboardApiClient().getBookingSSOFinalRedirection(token: token, refreshToken: refreshToken);
logger.d("SSO URL: $res");
return res;
// if (ssoResponse.status == "Success") {
// return ssoResponse;
// } else {
// Utils.showToast(ssoResponse.message!.first ?? "Failed to fetch SSO Auth Token");
// return null;
// }
} catch (ex) {
logger.wtf(ex);
isEventLoadingLoading = false;
notifyListeners();
Utils.handleException(ex, null, null);
return null;
}
}
Future<GetEitAttachmentTicket?> getTicketEitPDFDownload({String? peiExtraInfoId}) async {
try {
GetEitAttachmentTicket? res = await DashboardApiClient().getTicketEitPDFDownload(peiExtraInfoId: peiExtraInfoId!);
if (res?.getEitAttachmentList != null && res?.getEitAttachmentList!.length! != 0 && res!.getEitAttachmentList!.first.fileData != null) {
return res;
} else {
return null;
}
} catch (ex) {
logger.wtf(ex);
isEventLoadingLoading = false;
@ -409,6 +458,35 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
return res;
}
Future<String?> getENSATItgToken() async {
String? res = await DashboardApiClient().getENSATItgToken();
return res;
}
//Courses API's & Methods
Future<void> fetchCourses(BuildContext context) async {
try {
isCoursesLoading = true;
notifyListeners();
coursesResponse = await DashboardApiClient().fetchAllCoursesStatus();
if (coursesResponse != null && coursesResponse!.success == true) {
coursesList = coursesResponse!.coursesStatus ?? [];
} else {
coursesList = [];
}
isCoursesLoading = false;
notifyListeners();
} catch (ex) {
isCoursesLoading = false;
coursesList = [];
notifyListeners();
Utils.handleException(ex, context, null);
}
}
void notify() {
notifyListeners();
}

@ -0,0 +1,262 @@
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:mohem_flutter_app/api/etqan_ovr_api_client.dart';
import 'package:mohem_flutter_app/classes/utils.dart';
import 'package:mohem_flutter_app/models/etqan_ovr/etqan_get_employee_incident_report.dart';
import 'package:mohem_flutter_app/models/etqan_ovr/etqan_get_requests_model.dart';
import 'package:mohem_flutter_app/models/etqan_ovr/etqan_getprojects_model.dart';
import 'package:speech_to_text/speech_recognition_result.dart';
import 'package:speech_to_text/speech_to_text.dart';
class EtqanOvrProviderModel with ChangeNotifier, DiagnosticableTreeMixin {
// Home screen state
List<EtqanGetProjectsResponse>? getEtqanProjectsList;
List<EtqanGetEmployeeOvrRequestsResponse>? getEtqanEmployeeRequestsList;
List<EtqanGetIncidentRequestResponse>? getEtqanEmployeeIncidnetRequest;
bool isLoading = false;
String? _ticketId;
String? _currentStatus;
String? _currentStatusAr;
bool? _currentIsAnonymous;
// Speech to text state
final SpeechToText _speechToText = SpeechToText();
bool _speechEnabled = false;
bool _isListening = false;
String _currentLocaleId = '';
TextEditingController? _currentController;
String _baseText = ''; // Text that was there when we started listening
String _currentSessionText = ''; // Text captured in current listening session
// Getters for speech state
bool get speechEnabled => _speechEnabled;
bool get isListening => _isListening;
// Getter for ticketId
String get getTicketId => _ticketId ?? '';
String get getCurrentStatus => _currentStatus ?? '';
String get getCurrentStatusAr => _currentStatusAr ?? '';
bool get getCurrentIsAnonymous => _currentIsAnonymous ?? false;
// Setter for ticketId with status and isAnonymous
void setTicketId(String ticketId, {String? status, String? statusAr, bool? isAnonymous}) {
_ticketId = ticketId;
_currentStatus = status;
_currentStatusAr = statusAr;
_currentIsAnonymous = isAnonymous;
notifyListeners();
}
// Create request screen state
EtqanGetProjectsResponse? selectedProject;
String? selectedEmployeeNumber;
File? attachment;
String? attachmentBase64;
String description = '';
bool isAnonymous = false;
/// Initialize speech recognition - call this once when screen loads
Future<void> initSpeech() async {
_speechEnabled = await _speechToText.initialize(
onStatus: (String status) {
print('Speech status: $status, isListening: $_isListening');
// If user wants to keep listening but speech stopped, restart it
if ((status == 'done' || status == 'notListening') && _isListening && _currentController != null) {
// Save the finalized text before restarting
if (_currentSessionText.isNotEmpty) {
_baseText = _currentController!.text.trim();
_currentSessionText = '';
}
// Automatically restart listening after a brief pause
Future.delayed(const Duration(milliseconds: 300), () {
if (_isListening && _currentController != null) {
_startListeningInternal(_currentLocaleId, _currentController!);
}
});
}
},
);
notifyListeners();
}
/// Internal method to start listening
Future<void> _startListeningInternal(String localeId, TextEditingController controller) async {
if (!_speechEnabled) return;
await _speechToText.listen(
onResult: (SpeechRecognitionResult result) {
_currentSessionText = result.recognizedWords;
// Combine base text with current session text
String combinedText = _baseText.isEmpty
? _currentSessionText
: _baseText + (_baseText.endsWith(' ') ? '' : ' ') + _currentSessionText;
description = combinedText;
controller.text = combinedText;
controller.selection = TextSelection.fromPosition(TextPosition(offset: controller.text.length));
notifyListeners();
},
localeId: localeId,
listenFor: const Duration(seconds: 60),
pauseFor: const Duration(seconds: 10),
listenOptions: SpeechListenOptions(
partialResults: true,
listenMode: ListenMode.confirmation,
cancelOnError: false,
),
);
}
/// Start listening for speech input
Future<void> startListening(String localeId, TextEditingController controller) async {
_isListening = true;
_currentLocaleId = localeId;
_currentController = controller;
_baseText = controller.text.trim(); // Save existing text
_currentSessionText = '';
notifyListeners();
await _startListeningInternal(localeId, controller);
}
/// Stop listening for speech input
Future<void> stopListening() async {
_isListening = false;
_currentLocaleId = '';
_currentController = null;
_baseText = '';
_currentSessionText = '';
await _speechToText.stop();
notifyListeners();
}
/// Toggle listening state
Future<void> toggleListening(String localeId, TextEditingController controller) async {
if (_isListening) {
await stopListening();
} else {
await startListening(localeId, controller);
}
}
// Fetch Etqan Projects
Future<void> fetchEtqanProjects(BuildContext context) async {
isLoading = true;
notifyListeners();
Utils.showLoading(context);
getEtqanProjectsList?.clear();
getEtqanProjectsList = await EtqanApiClient().getEtqanProjects();
Utils.hideLoading(context);
isLoading = false;
notifyListeners();
}
// Fetch Etqan Employee Requests
Future<void> fetchEtqanEmployeeRequests(BuildContext context) async {
isLoading = true;
notifyListeners();
Utils.showLoading(context);
getEtqanEmployeeRequestsList?.clear();
getEtqanEmployeeRequestsList = await EtqanApiClient().getEmployeeEtqanRequests();
Utils.hideLoading(context);
isLoading = false;
notifyListeners();
}
// Fetch Etqan Employee Incident Report
Future<void> fetchEtqanEmployeeIncidentRequests(BuildContext context, String ticketNo) async {
isLoading = true;
notifyListeners();
Utils.showLoading(context);
getEtqanEmployeeIncidnetRequest?.clear();
getEtqanEmployeeIncidnetRequest = await EtqanApiClient().getEtqanIncidentRequests(ticketNo);
Utils.hideLoading(context);
isLoading = false;
notifyListeners();
}
// Set selected project
void setSelectedProject(EtqanGetProjectsResponse? project) {
selectedProject = project;
notifyListeners();
}
// Set selected employee number
void setSelectedEmployeeNumber(String? employeeNumber) {
selectedEmployeeNumber = employeeNumber;
notifyListeners();
}
// Set attachment with base64
void setAttachment(File file, String base64) {
attachment = file;
attachmentBase64 = base64;
notifyListeners();
}
// Remove attachment
void removeAttachment() {
attachment = null;
attachmentBase64 = null;
notifyListeners();
}
// Set description
void setDescription(String value) {
description = value;
notifyListeners();
}
// Validate description
bool isDescriptionValid() {
return description.trim().isNotEmpty;
}
// Set isAnonymous
void setIsAnonymous(bool value) {
isAnonymous = value;
notifyListeners();
}
// Clear create request form
void clearCreateRequestForm() {
selectedProject = null;
selectedEmployeeNumber = null;
attachment = null;
attachmentBase64 = null;
description = '';
isAnonymous = false;
notifyListeners();
}
// Submit request
Future<Map<String, dynamic>?> submitRequest(BuildContext context) async {
try {
Utils.showLoading(context);
Map<String, dynamic>? response = await EtqanApiClient().createRequest(description, selectedProject?.projectId, attachmentBase64, isAnonymous);
Utils.hideLoading(context);
if (response != null) {
getEtqanEmployeeRequestsList = await EtqanApiClient().getEmployeeEtqanRequests();
notifyListeners();
return response;
}
return null;
} catch (ex) {
Utils.hideLoading(context);
Utils.handleException(ex, context, null);
return null;
}
}
@override
void dispose() {
if (_isListening) {
_speechToText.stop();
}
super.dispose();
}
}

@ -57,6 +57,15 @@ class _MonthlyAttendanceScreenState extends State<MonthlyAttendanceScreen> {
Utils.showLoading(context);
getTimeCardSummaryList = await MonthlyAttendanceApiClient().getTimeCardSummary(searchMonth, searchYear);
getDayHoursTypeDetailsList = await MonthlyAttendanceApiClient().getDayHoursTypeDetails(searchMonth, searchYear);
// Debug logging to check the data
print('Total days received: ${getDayHoursTypeDetailsList.length}');
for (var day in getDayHoursTypeDetailsList) {
if (day.lEAVETYPECODE != null && day.lEAVETYPECODE!.isNotEmpty) {
print('Date: ${day.sCHEDULEDATE}, LEAVE_TYPE_CODE: ${day.lEAVETYPECODE}');
}
}
Utils.hideLoading(context);
_calendarController.displayDate = formattedDate;
setState(() {});
@ -301,19 +310,49 @@ class _MonthlyAttendanceScreenState extends State<MonthlyAttendanceScreen> {
monthCellBuilder: (build, details) {
if (details.date.month == formattedDate.month && details.date.year == formattedDate.year) {
int val = details.date.day;
int index = val-1;
//check day is off
// if (getDayHoursTypeDetailsList.isNotEmpty) {
// bool isDayIsOff = getDayHoursTypeDetailsList[val - 1].aTTENDEDFLAG == 'N' && getDayHoursTypeDetailsList[val - 1].dAYTYPE == 'OFF';
// bool isDayIsPresent = getDayHoursTypeDetailsList[val - 1].aTTENDEDFLAG == 'Y';
// bool isDayIsAbsent = getDayHoursTypeDetailsList[val - 1].aTTENDEDFLAG == 'N' && getDayHoursTypeDetailsList[val - 1].aBSENTFLAG == 'Y';
List<GetDayHoursTypeDetailsList> getDayHours =
getDayHoursTypeDetailsList.where((GetDayHoursTypeDetailsList element) => DateFormat("MM/dd/yyyy", "en_US").parse(element.sCHEDULEDATE!).day == details.date.day).toList();
getDayHoursTypeDetailsList.where((GetDayHoursTypeDetailsList element) {
DateTime scheduleDate = DateFormat("MM/dd/yyyy", "en_US").parse(element.sCHEDULEDATE!);
return scheduleDate.day == details.date.day &&
scheduleDate.month == details.date.month &&
scheduleDate.year == details.date.year;
}).toList();
if (getDayHours.isNotEmpty) {
bool isDayIsOff = getDayHoursTypeDetailsList[index].aTTENDEDFLAG == 'N' && getDayHoursTypeDetailsList[index].dAYTYPE == 'OFF';
bool isDayIsPresent = getDayHoursTypeDetailsList[index].aTTENDEDFLAG == 'Y';
bool isDayIsAbsent = getDayHoursTypeDetailsList[index].aTTENDEDFLAG == 'N' && getDayHoursTypeDetailsList[index].aBSENTFLAG == 'Y';
GetDayHoursTypeDetailsList dayData = getDayHours.first;
// Debug logging
print('Day: ${details.date.day}, LEAVE_TYPE_CODE: ${dayData.lEAVETYPECODE}, ATTENDED_FLAG: ${dayData.aTTENDEDFLAG}, DAY_TYPE: ${dayData.dAYTYPE}');
bool isDayIsOff = dayData.aTTENDEDFLAG == 'N' && dayData.dAYTYPE == 'OFF';
bool isDayIsPresent = dayData.aTTENDEDFLAG == 'Y';
bool isDayIsAbsent = dayData.aTTENDEDFLAG == 'N' && dayData.aBSENTFLAG == 'Y';
// Get leave type code and corresponding color
String? leaveTypeCode = dayData.lEAVETYPECODE;
Color? leaveTypeColor;
bool useGradient = false;
// Determine color based on leave type code
if (leaveTypeCode != null && leaveTypeCode.isNotEmpty && leaveTypeCode.trim().isNotEmpty) {
leaveTypeColor = leaveTypeColors[leaveTypeCode];
print('Matched color for $leaveTypeCode: $leaveTypeColor');
}
// If no leave type color found, use default colors based on attendance status
if (leaveTypeColor == null) {
if (isDayIsPresent) {
leaveTypeColor = leaveTypeColors['Present'];
useGradient = true; // Use gradient for present days without leave type
} else if (isDayIsAbsent) {
leaveTypeColor = leaveTypeColors['Absent'];
}
}
if (isDayIsOff) {
return Container(
@ -331,12 +370,13 @@ class _MonthlyAttendanceScreenState extends State<MonthlyAttendanceScreen> {
return Container(
margin: const EdgeInsets.all(4),
decoration: BoxDecoration(
gradient: const LinearGradient(
gradient: useGradient && leaveTypeColor != null ? LinearGradient(
transform: GradientRotation(.46),
begin: Alignment.topRight,
end: Alignment.bottomLeft,
colors: [MyColors.gradiantEndColor, MyColors.gradiantStartColor],
),
) : null,
color: !useGradient && leaveTypeColor != null ? leaveTypeColor : null,
shape: BoxShape.circle,
boxShadow: [
BoxShadow(
@ -358,7 +398,29 @@ class _MonthlyAttendanceScreenState extends State<MonthlyAttendanceScreen> {
return Container(
margin: const EdgeInsets.all(4),
decoration: BoxDecoration(
color: MyColors.backgroundBlackColor,
color: leaveTypeColor ?? MyColors.backgroundBlackColor,
shape: BoxShape.circle,
boxShadow: [
BoxShadow(
offset: const Offset(0, 2),
blurRadius: 26,
color: MyColors.blackColor.withOpacity(0.100),
),
],
),
alignment: Alignment.center,
child: Text(
"$val",
style: const TextStyle(fontSize: 13, fontWeight: FontWeight.w500, color: MyColors.white),
),
);
}
// Handle days with leave type codes (HOLIDAY, WFH, etc.) that are not present/absent/off
else if (leaveTypeColor != null) {
return Container(
margin: const EdgeInsets.all(4),
decoration: BoxDecoration(
color: leaveTypeColor,
shape: BoxShape.circle,
boxShadow: [
BoxShadow(
@ -407,12 +469,26 @@ class _MonthlyAttendanceScreenState extends State<MonthlyAttendanceScreen> {
}
void calendarTapped(CalendarTapDetails details) async {
dynamic index = details.date?.day;
if (index != null) {
index = index - 1;
}
pRTPID = getDayHoursTypeDetailsList[index].rTPID;
await getScheduleShiftsDetails(index, pRTPID);
if (details.date == null) return;
// Filter to find the matching day data with full date comparison
List<GetDayHoursTypeDetailsList> getDayHours =
getDayHoursTypeDetailsList.where((GetDayHoursTypeDetailsList element) {
DateTime scheduleDate = DateFormat("MM/dd/yyyy", "en_US").parse(element.sCHEDULEDATE!);
return scheduleDate.day == details.date!.day &&
scheduleDate.month == details.date!.month &&
scheduleDate.year == details.date!.year;
}).toList();
if (getDayHours.isEmpty) return;
GetDayHoursTypeDetailsList dayData = getDayHours.first;
// Debug logging
print('Tapped Day: ${details.date!.day}, LEAVE_TYPE_CODE: ${dayData.lEAVETYPECODE}');
pRTPID = dayData.rTPID;
await getScheduleShiftsDetails(details.date!.day, pRTPID);
dynamic value = getScheduleShiftsDetailsList!.pERCENTAGE;
dynamic percentage;
if (value!.indexOf('%') == 3) {
@ -425,8 +501,7 @@ class _MonthlyAttendanceScreenState extends State<MonthlyAttendanceScreen> {
percentage = 0;
}
if (details.date!.month == formattedDate.month && details.date!.year == formattedDate.year) {
int val = details.date!.day;
getDayHoursTypeDetailsList?[val - 1].aTTENDEDFLAG == 'Y'
dayData.aTTENDEDFLAG == 'Y'
? showModalBottomSheet(
context: context,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(25)),
@ -571,7 +646,7 @@ class _MonthlyAttendanceScreenState extends State<MonthlyAttendanceScreen> {
LocaleKeys.lateIn.tr().toText11(
color: MyColors.grey67Color,
),
"${getDayHoursTypeDetailsList[index].lATEINHRS}".toText22(color: MyColors.redColor, isBold: true),
"${dayData.lATEINHRS}".toText22(color: MyColors.redColor, isBold: true),
],
).expanded,
Column(
@ -580,7 +655,7 @@ class _MonthlyAttendanceScreenState extends State<MonthlyAttendanceScreen> {
LocaleKeys.excess.tr().toText11(
color: MyColors.grey67Color,
),
"${getDayHoursTypeDetailsList[index].eXCESSHRS}".toText22(color: MyColors.backgroundBlackColor, isBold: true),
"${dayData.eXCESSHRS}".toText22(color: MyColors.backgroundBlackColor, isBold: true),
],
).expanded,
],
@ -600,7 +675,7 @@ class _MonthlyAttendanceScreenState extends State<MonthlyAttendanceScreen> {
LocaleKeys.shortage.tr().toText11(
color: MyColors.grey67Color,
),
"${getDayHoursTypeDetailsList[index].sHORTAGEHRS}".toText22(color: MyColors.backgroundBlackColor, isBold: true),
"${dayData.sHORTAGEHRS}".toText22(color: MyColors.backgroundBlackColor, isBold: true),
],
).expanded,
Column(
@ -609,7 +684,7 @@ class _MonthlyAttendanceScreenState extends State<MonthlyAttendanceScreen> {
LocaleKeys.earlyOut.tr().toText11(
color: MyColors.grey67Color,
),
"${getDayHoursTypeDetailsList[index].eARLYOUTHRS}".toText22(color: Colors.black, isBold: true),
"${dayData.eARLYOUTHRS}".toText22(color: Colors.black, isBold: true),
],
).expanded,
],
@ -751,3 +826,24 @@ class Meeting {
Color background;
bool isAllDay;
}
const Map<String, Color> leaveTypeColors = {
'Present': Color(0xFF00ad62),
'Absent': Color(0xFFcb3232),
'HOLIDAY': Color(0xFFF26B0F),
'BUS_TRIP': Color(0xFF001A6E),
'WFH': Color(0xFF5DB996),
'ANNUAL': Color(0xFFf39c12),
'EMERGENCY': Color(0xFFFF2929),
'EXAM': Color(0xFFCB6040),
'HAJJ': Color(0xFF798645),
'HALF': Color(0xFFE8B86D),
'LWOP': Color(0xFFCD5C08),
'LWOP_MATUNPAID': Color(0xFFE73879),
'LWOP_UNAUUNPAID': Color(0xFFA02334),
'MATPAID': Color(0xFFE73879),
'MRGE': Color(0xFF0D7C66),
'PAT': Color(0xFFC96868),
'PROF': Color(0xFF6256CA),
'SICK': Color(0xFFA5B68D),
};

@ -0,0 +1,360 @@
import 'dart:io';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:mohem_flutter_app/app_state/app_state.dart';
import 'package:mohem_flutter_app/classes/colors.dart';
import 'package:mohem_flutter_app/classes/utils.dart';
import 'package:mohem_flutter_app/config/routes.dart';
import 'package:mohem_flutter_app/extensions/int_extensions.dart';
import 'package:mohem_flutter_app/extensions/widget_extensions.dart';
import 'package:mohem_flutter_app/generated/locale_keys.g.dart';
import 'package:mohem_flutter_app/models/etqan_ovr/etqan_getprojects_model.dart';
import 'package:mohem_flutter_app/provider/etqan_ovr_provider.dart';
import 'package:mohem_flutter_app/widgets/app_bar_widget.dart';
import 'package:mohem_flutter_app/widgets/bottom_sheet.dart';
import 'package:mohem_flutter_app/widgets/button/default_button.dart';
import 'package:mohem_flutter_app/widgets/image_picker.dart';
import 'package:provider/provider.dart';
class EtqanOvrCreateRequest extends StatefulWidget {
const EtqanOvrCreateRequest({Key? key}) : super(key: key);
@override
_EtqanOvrCreateRequestState createState() => _EtqanOvrCreateRequestState();
}
class _EtqanOvrCreateRequestState extends State<EtqanOvrCreateRequest> {
final TextEditingController _descriptionController = TextEditingController();
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
var provider = context.read<EtqanOvrProviderModel>();
provider.initSpeech();
provider.fetchEtqanProjects(context);
provider.clearCreateRequestForm();
});
}
@override
void dispose() {
// Stop listening if active
context.read<EtqanOvrProviderModel>().stopListening();
_descriptionController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBarWidget(context, title: LocaleKeys.reportIncident.tr(), showHomeButton: false),
body: Consumer<EtqanOvrProviderModel>(
builder: (BuildContext context, EtqanOvrProviderModel provider, Widget? child) {
return Column(
children: <Widget>[
(ListView(
shrinkWrap: true,
physics: const BouncingScrollPhysics(),
padding: const EdgeInsets.all(21),
children: <Widget>[
_buildDropdownField(
label: LocaleKeys.project.tr(),
hint: LocaleKeys.selectProject.tr(),
value: _getProjectDisplayName(provider.selectedProject),
onTap: () => _showProjectSelectionSheet(context, provider),
isMandatory: true,
),
16.height,
// _buildDropdownField(
// label: 'Employee Number',
// hint: 'Write a message',
// value: provider.selectedEmployeeNumber,
// onTap: () {
// // TODO: Show employee selection dialog
// },
// ),
// 16.height,
_buildAttachmentSection(provider),
16.height,
_buildDescriptionField(provider),
8.height,
_buildAnonymousCheckbox(provider),
24.height,
],
)).expanded,
DefaultButton(LocaleKeys.submit.tr(), () async {
provider.setDescription(_descriptionController.text);
if (provider.selectedProject == null) {
Utils.showErrorDialog(
context: context,
message: LocaleKeys.pleaseSelectProject.tr(),
onOkTapped: () {
Navigator.of(context).pop();
},
);
return;
}
if (!provider.isDescriptionValid()) {
Utils.showErrorDialog(
context: context,
message: LocaleKeys.pleaseEnterDescription.tr(),
onOkTapped: () {
Navigator.of(context).pop();
},
);
return;
}
Map<String, dynamic>? ticketInfo = await provider.submitRequest(context);
if (ticketInfo != null) {
String ticketNumber = ticketInfo['ticketNumber'] ?? '';
String ticketId = ticketInfo['id'] ?? '';
// String successMessage = '${LocaleKeys.requestCreatedSuccessfully.tr()}\n\n${LocaleKeys.ticketNumber.tr()}: $ticketNumber\n${LocaleKeys.ticketId.tr()}: $ticketId';
String successMessage = '${LocaleKeys.requestCreatedSuccessfully.tr()}\n\n${LocaleKeys.ticketNumber.tr()}: $ticketNumber';
Utils.showErrorDialog(
context: context,
message: successMessage,
onOkTapped: () {
Navigator.pop(context);
Navigator.pop(context);
// Navigator.popAndPushNamed(context, AppRoutes.etqanOvr);
},
onCloseTap: () {
Navigator.pop(context);
Navigator.pop(context);
// Navigator.popAndPushNamed(context, AppRoutes.etqanOvr);
},
);
}
}).insideContainer,
],
);
},
),
);
}
String? _getProjectDisplayName(EtqanGetProjectsResponse? project) {
if (project == null) return null;
return AppState().isArabic(context) ? project.projectAr : project.projectEn;
}
void _showProjectSelectionSheet(BuildContext context, EtqanOvrProviderModel provider) {
if (provider.getEtqanProjectsList == null || provider.getEtqanProjectsList!.isEmpty) {
return;
}
showMyBottomSheet(
context,
callBackFunc: () {},
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: Text(LocaleKeys.selectProject.tr(), style: const TextStyle(fontSize: 18, fontWeight: FontWeight.w600, color: Color(0xff2B353E))),
),
const Divider(),
ListView.separated(
shrinkWrap: true,
physics: const BouncingScrollPhysics(),
itemCount: provider.getEtqanProjectsList!.length,
separatorBuilder: (BuildContext context, int index) => const Divider(height: 1),
itemBuilder: (BuildContext context, int index) {
EtqanGetProjectsResponse project = provider.getEtqanProjectsList![index];
bool isSelected = provider.selectedProject?.projectId == project.projectId;
return ListTile(
title: Text(
AppState().isArabic(context) ? (project.projectAr ?? '') : (project.projectEn ?? ''),
style: TextStyle(fontSize: 14, fontWeight: isSelected ? FontWeight.w600 : FontWeight.w400, color: isSelected ? MyColors.gradiantEndColor : const Color(0xff2B353E)),
),
trailing: isSelected ? const Icon(Icons.check, color: MyColors.gradiantEndColor) : null,
onTap: () {
provider.setSelectedProject(project);
Navigator.pop(context);
},
);
},
),
16.height,
],
),
);
}
Widget _buildDropdownField({required String label, required String hint, String? value, required VoidCallback onTap, bool isMandatory = false}) {
return InkWell(
onTap: onTap,
borderRadius: BorderRadius.circular(15),
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 15),
decoration: BoxDecoration(borderRadius: BorderRadius.circular(15), color: Colors.white, border: Border.all(color: const Color(0xffefefef), width: 1)),
child: Row(
children: <Widget>[
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Row(
children: <Widget>[
Text(label, style: const TextStyle(fontSize: 11, fontWeight: FontWeight.w600, color: Color(0xff2B353E), letterSpacing: -0.44)),
if (isMandatory) const Text(' *', style: TextStyle(fontSize: 11, fontWeight: FontWeight.w600, color: Colors.red, letterSpacing: -0.44)),
],
),
const SizedBox(height: 4),
Text(value ?? hint, style: TextStyle(fontSize: 14, fontWeight: FontWeight.w400, color: value != null ? const Color(0xff2B353E) : const Color(0xff575757), letterSpacing: -0.56)),
],
),
),
const Icon(Icons.keyboard_arrow_down, color: Color(0xff575757)),
],
),
),
);
}
Widget _buildAttachmentSection(EtqanOvrProviderModel provider) {
return Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(borderRadius: BorderRadius.circular(15), color: Colors.white, border: Border.all(color: const Color(0xffefefef), width: 1)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(LocaleKeys.supportingDocument.tr(), style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: Color(0xff2B353E))),
const SizedBox(height: 12),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(LocaleKeys.attachments.tr(), style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w500, color: Color(0xff2B353E))),
if (provider.attachment == null)
InkWell(
onTap: () {
ImageOptions.showImageOptionsNew(context, true, (String base64, File file) {
provider.setAttachment(file, base64);
Navigator.of(context).pop();
});
},
borderRadius: BorderRadius.circular(8),
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 8),
decoration: BoxDecoration(color: MyColors.gradiantEndColor, borderRadius: BorderRadius.circular(8)),
child: Text(LocaleKeys.add.tr(), style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w600, color: Colors.white)),
),
),
],
),
if (provider.attachment != null) ...<Widget>[
const SizedBox(height: 12),
Padding(
padding: const EdgeInsets.only(bottom: 8),
child: Row(
children: <Widget>[
const Icon(Icons.attach_file, size: 18, color: Color(0xff575757)),
const SizedBox(width: 8),
Expanded(child: Text(provider.attachment!.path.split('/').last, style: const TextStyle(fontSize: 12, color: Color(0xff575757)), overflow: TextOverflow.ellipsis)),
InkWell(
onTap: () {
provider.removeAttachment();
},
child: const Icon(Icons.close, size: 18, color: Colors.red),
),
],
),
),
],
],
),
);
}
Widget _buildDescriptionField(EtqanOvrProviderModel provider) {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 15),
decoration: BoxDecoration(borderRadius: BorderRadius.circular(15), color: Colors.white, border: Border.all(color: const Color(0xffefefef), width: 1)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Row(
children: <Widget>[
Text(LocaleKeys.description.tr(), style: const TextStyle(fontSize: 11, fontWeight: FontWeight.w600, color: Color(0xff2B353E), letterSpacing: -0.44)),
const Text(' *', style: TextStyle(fontSize: 11, fontWeight: FontWeight.w600, color: Colors.red, letterSpacing: -0.44)),
],
),
GestureDetector(
onTap:
provider.speechEnabled
? () {
String localeId = AppState().isArabic(context) ? 'ar_SA' : 'en_US';
provider.toggleListening(localeId, _descriptionController);
}
: null,
child: Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(color: provider.isListening ? MyColors.gradiantEndColor.withOpacity(0.1) : Colors.transparent, borderRadius: BorderRadius.circular(20)),
child: Icon(
provider.isListening ? Icons.mic : Icons.mic_none,
color: provider.isListening ? MyColors.gradiantEndColor : (provider.speechEnabled ? MyColors.grey57Color : Colors.grey.shade300),
size: 24,
),
),
),
],
),
if (provider.isListening)
Padding(
padding: const EdgeInsets.only(bottom: 8),
child: Row(
children: <Widget>[
Container(width: 8, height: 8, decoration: BoxDecoration(color: Colors.red, borderRadius: BorderRadius.circular(4))),
const SizedBox(width: 8),
const Text('Listening...', style: TextStyle(fontSize: 12, color: MyColors.gradiantEndColor, fontWeight: FontWeight.w500)),
],
),
),
TextField(
controller: _descriptionController,
maxLines: 4,
onChanged: (String value) => provider.setDescription(value),
style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w400, color: Color(0xff2B353E), letterSpacing: -0.44),
decoration: InputDecoration(
isDense: true,
hintText: LocaleKeys.writeAMessage.tr(),
hintStyle: const TextStyle(fontSize: 14, fontWeight: FontWeight.w400, color: Color(0xff575757), letterSpacing: -0.56),
contentPadding: EdgeInsets.zero,
border: InputBorder.none,
focusedBorder: InputBorder.none,
enabledBorder: InputBorder.none,
),
),
],
),
);
}
Widget _buildAnonymousCheckbox(EtqanOvrProviderModel provider) {
return InkWell(
onTap: () {
provider.setIsAnonymous(!provider.isAnonymous);
},
child: Row(
children: <Widget>[
Checkbox(
value: provider.isAnonymous,
onChanged: (bool? value) {
if (value != null) {
provider.setIsAnonymous(value);
}
},
activeColor: MyColors.gradiantEndColor,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(4)),
),
Expanded(child: Text(LocaleKeys.submitAsAnonymous.tr(), style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w500, color: Color(0xff2B353E), letterSpacing: -0.44))),
],
),
);
}
}

@ -0,0 +1,165 @@
import 'package:easy_localization/easy_localization.dart' as lclize;
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:mohem_flutter_app/app_state/app_state.dart';
import 'package:mohem_flutter_app/classes/colors.dart';
import 'package:mohem_flutter_app/config/routes.dart';
import 'package:mohem_flutter_app/extensions/int_extensions.dart';
import 'package:mohem_flutter_app/extensions/string_extensions.dart';
import 'package:mohem_flutter_app/extensions/widget_extensions.dart';
import 'package:mohem_flutter_app/generated/locale_keys.g.dart';
import 'package:mohem_flutter_app/models/etqan_ovr/etqan_get_requests_model.dart';
import 'package:mohem_flutter_app/provider/etqan_ovr_provider.dart';
import 'package:mohem_flutter_app/classes/utils.dart';
import 'package:mohem_flutter_app/widgets/app_bar_widget.dart';
import 'package:mohem_flutter_app/widgets/button/default_button.dart';
import 'package:provider/provider.dart';
import 'package:intl/src/intl/text_direction.dart' as intl;
import 'package:sizer/sizer.dart';
class EtqanOvrHome extends StatefulWidget {
const EtqanOvrHome({Key? key}) : super(key: key);
@override
_EtqanOvrHomeState createState() => _EtqanOvrHomeState();
}
class _EtqanOvrHomeState extends State<EtqanOvrHome> {
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
context.read<EtqanOvrProviderModel>().fetchEtqanEmployeeRequests(context);
});
}
Color _getStatusColor(String status) {
String statusLower = status.toLowerCase();
if (statusLower.contains('open') || statusLower.contains('مفتوح')) {
return const Color(0xff2196F3); // Blue for open
} else if (statusLower.contains('progress') || statusLower.contains('قيد التنفيذ')) {
return const Color(0xffFF9800); // Orange for in progress
} else if (statusLower.contains('closed') || statusLower.contains('مغلق')) {
return const Color(0xff4CAF50); // Green for closed
}
return MyColors.grey70Color; // Default gray
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBarWidget(context, title: LocaleKeys.myIncidents.tr()),
body: Consumer<EtqanOvrProviderModel>(
builder: (BuildContext context, EtqanOvrProviderModel provider, Widget? child) {
return Column(
children: <Widget>[
(provider.getEtqanEmployeeRequestsList == null || provider.getEtqanEmployeeRequestsList!.isEmpty
? Utils.getNoDataWidget(context)
: ListView.separated(
physics: const BouncingScrollPhysics(),
padding: const EdgeInsets.all(20),
itemBuilder: (BuildContext context, int index) {
EtqanGetEmployeeOvrRequestsResponse data = provider.getEtqanEmployeeRequestsList![index];
return InkWell(
onTap: () {
context.read<EtqanOvrProviderModel>().setTicketId(data.ticketNumber ?? '', status: data.status, statusAr: data.statusAr, isAnonymous: data.isAnonymous);
Navigator.pushNamed(context, AppRoutes.etqanGetIncidientRequest);
},
child: Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(15), border: Border.all(color: const Color(0xffefefef), width: 1)),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Row(
children: [
Expanded(
child: Wrap(
spacing: 8,
runSpacing: 8,
children: [
if (data.status != null && data.status!.isNotEmpty)
Container(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
decoration: BoxDecoration(
color: _getStatusColor(data.status ?? "").withOpacity(0.1),
borderRadius: BorderRadius.circular(6),
border: Border.all(color: _getStatusColor(data.status ?? "").withOpacity(0.3), width: 1),
),
child: (AppState().isArabic(context) ? (data.statusAr ?? "") : (data.status ?? "")).toText11(
color: _getStatusColor(data.status ?? ""),
isBold: true,
),
),
if (data.isAnonymous == true)
Container(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
decoration: BoxDecoration(
color: MyColors.grey70Color.withOpacity(0.15),
borderRadius: BorderRadius.circular(6),
border: Border.all(color: MyColors.grey70Color.withOpacity(0.3), width: 1),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(Icons.visibility_off, size: 12, color: MyColors.grey70Color),
const SizedBox(width: 4),
(AppState().isArabic(context) ? "مجهول" : "Anonymous").toText11(color: MyColors.grey70Color, isBold: true),
],
),
),
],
),
),
const SizedBox(width: 8),
],
),
8.height,
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
(data.ticketNumber ?? "").toText14(isBold: true, color: MyColors.darkTextColor),
Directionality(textDirection: TextDirection.ltr, child: (data.createdDate!.split(" ").first ?? "").toText12(color: MyColors.grey70Color)),
],
),
8.height,
Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [(data.description ?? "").toText12(color: MyColors.grey57Color).expanded]),
3.height,
Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.end,
children: [
RotatedBox(
quarterTurns: AppState().isArabic(context) ? 2 : 0,
child: SvgPicture.asset("assets/images/arrow_next.svg", color: MyColors.grey70Color, width: 16, height: 16),
),
],
),
],
),
),
],
),
),
);
},
separatorBuilder: (BuildContext context, int index) => 12.height,
itemCount: provider.getEtqanEmployeeRequestsList!.length,
))
.expanded,
DefaultButton(LocaleKeys.reportIncident.tr(), () async {
await Navigator.pushNamed(context, AppRoutes.etqanCreateRequest);
// getOpenTickets();
}).insideContainer,
],
);
},
),
);
}
}

@ -0,0 +1,235 @@
import 'dart:convert';
import 'dart:io';
import 'dart:typed_data';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:mohem_flutter_app/app_state/app_state.dart';
import 'package:mohem_flutter_app/classes/colors.dart';
import 'package:mohem_flutter_app/extensions/int_extensions.dart';
import 'package:mohem_flutter_app/extensions/string_extensions.dart';
import 'package:mohem_flutter_app/extensions/widget_extensions.dart';
import 'package:mohem_flutter_app/generated/locale_keys.g.dart';
import 'package:mohem_flutter_app/models/etqan_ovr/etqan_get_employee_incident_report.dart';
import 'package:mohem_flutter_app/provider/etqan_ovr_provider.dart';
import 'package:mohem_flutter_app/classes/utils.dart';
import 'package:mohem_flutter_app/widgets/app_bar_widget.dart';
import 'package:provider/provider.dart';
import 'package:open_filex/open_filex.dart';
import 'package:path_provider/path_provider.dart';
class EtqanOvrRequestDetailed extends StatefulWidget {
const EtqanOvrRequestDetailed({Key? key}) : super(key: key);
@override
_EtqanOvrRequestDetailedState createState() => _EtqanOvrRequestDetailedState();
}
class _EtqanOvrRequestDetailedState extends State<EtqanOvrRequestDetailed> {
List<String> get fieldOrder => ['Status', 'Project', 'Created', 'Is Anonymous', 'Occurrence Time', 'OVR Reference No', 'Involved Employee Number', 'Description'];
List<String> get hiddenFields => ['OVR Id'];
Color _getStatusColor(String status) {
String statusLower = status.toLowerCase();
if (statusLower.contains('open') || statusLower.contains('مفتوح')) {
return const Color(0xff2196F3); // Blue for open
} else if (statusLower.contains('progress') || statusLower.contains('قيد التنفيذ')) {
return const Color(0xffFF9800); // Orange for in progress
} else if (statusLower.contains('closed') || statusLower.contains('مغلق')) {
return const Color(0xff4CAF50); // Green for closed
}
return MyColors.grey70Color; // Default gray
}
Future<void> _viewAttachment(BuildContext context, String base64Data) async {
try {
Uint8List bytes = base64.decode(base64Data);
String dir = (await getApplicationDocumentsDirectory()).path;
String ext = 'pdf';
if (base64Data.startsWith('/9j/')) {
ext = 'jpg';
} else if (base64Data.startsWith('iVBORw0KGgo')) {
ext = 'png';
}
File file = File("$dir/${DateTime.now().millisecondsSinceEpoch}.$ext");
await file.writeAsBytes(bytes);
OpenFilex.open(file.path);
} catch (e) {
Utils.showToast("Cannot open attachment.");
}
}
List<EtqanGetIncidentRequestResponse> _getOrderedList(List<EtqanGetIncidentRequestResponse> list, EtqanOvrProviderModel provider) {
List<EtqanGetIncidentRequestResponse> orderedList = [];
List<EtqanGetIncidentRequestResponse> filteredList = list.where((EtqanGetIncidentRequestResponse item) => !hiddenFields.any((f) => f.toLowerCase() == item.key?.toLowerCase())).toList();
for (String fieldName in fieldOrder) {
// Check if this is Status or Is Anonymous - inject from provider
if (fieldName.toLowerCase() == 'status' && provider.getCurrentStatus.isNotEmpty) {
orderedList.add(EtqanGetIncidentRequestResponse(
key: 'Status',
keyAr: 'الحالة',
value: provider.getCurrentStatus,
valueAr: provider.getCurrentStatusAr.isNotEmpty ? provider.getCurrentStatusAr : provider.getCurrentStatus,
));
} else if (fieldName.toLowerCase() == 'is anonymous') {
orderedList.add(EtqanGetIncidentRequestResponse(
key: 'Is Anonymous',
keyAr: 'مجهول',
value: provider.getCurrentIsAnonymous.toString(),
valueAr: provider.getCurrentIsAnonymous.toString(),
));
} else {
// Regular field from API
var item = filteredList.firstWhere((e) => e.key?.toLowerCase() == fieldName.toLowerCase(), orElse: () => EtqanGetIncidentRequestResponse());
if (item.key != null) {
orderedList.add(item);
}
}
}
for (var item in filteredList) {
if (!fieldOrder.any((f) => f.toLowerCase() == item.key?.toLowerCase())) {
orderedList.add(item);
}
}
return orderedList;
}
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
EtqanOvrProviderModel provider = context.read<EtqanOvrProviderModel>();
provider.fetchEtqanEmployeeIncidentRequests(context, provider.getTicketId);
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBarWidget(context, title: LocaleKeys.incidentDetails.tr()),
body: Consumer<EtqanOvrProviderModel>(
builder: (BuildContext context, EtqanOvrProviderModel provider, Widget? child) {
if (provider.getEtqanEmployeeIncidnetRequest == null || provider.getEtqanEmployeeIncidnetRequest!.isEmpty) {
return Utils.getNoDataWidget(context);
}
List<EtqanGetIncidentRequestResponse> orderedList = _getOrderedList(provider.getEtqanEmployeeIncidnetRequest!, provider);
return SingleChildScrollView(
physics: const BouncingScrollPhysics(),
padding: const EdgeInsets.all(16),
child: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(15),
border: Border.all(color: const Color(0xffefefef), width: 1),
boxShadow: <BoxShadow>[BoxShadow(color: Colors.black.withValues(alpha: 0.05), blurRadius: 10, offset: const Offset(0, 2))],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children:
orderedList.asMap().entries.map((MapEntry<int, EtqanGetIncidentRequestResponse> entry) {
int index = entry.key;
EtqanGetIncidentRequestResponse data = entry.value;
bool isLast = index == orderedList.length - 1;
bool isAttachment = data.key?.toLowerCase() == 'attachment';
bool isStatus = data.key?.toLowerCase() == 'status';
bool isAnonymous = data.key?.toLowerCase() == 'is anonymous';
String displayKey = context.locale.languageCode == "ar" ? (data.keyAr ?? data.key ?? "") : (data.key ?? "");
String displayValue = context.locale.languageCode == "ar" ? (data.valueAr ?? data.value ?? "") : (data.value ?? "");
bool hasSubValues = data.subValues != null && data.subValues!.isNotEmpty;
return Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Expanded(flex: 2, child: displayKey.toText12(isBold: true, color: MyColors.grey57Color)),
8.width,
Expanded(
flex: 3,
child: isStatus
? displayValue.toText14(
color: _getStatusColor(displayValue),
isBold: true,
)
: isAnonymous
? (displayValue.toLowerCase() == 'true' || displayValue.toLowerCase() == 'yes' || displayValue == '1'
? (context.locale.languageCode == "ar" ? "نعم" : "Yes")
: (context.locale.languageCode == "ar" ? "لا" : "No")
).toText14(color: MyColors.darkTextColor)
: isAttachment && hasSubValues
? Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: data.subValues!.asMap().entries.map((entry) {
int subIndex = entry.key;
String base64Data = entry.value;
return Padding(
padding: EdgeInsets.only(bottom: subIndex < data.subValues!.length - 1 ? 8.0 : 0),
child: GestureDetector(
onTap: () => _viewAttachment(context, base64Data),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: context.locale.languageCode == "ar" ? MainAxisAlignment.end : MainAxisAlignment.start,
children: [
Text(
data.subValues!.length > 1 ? '${LocaleKeys.viewAttachment.tr()} ${subIndex + 1}' : LocaleKeys.viewAttachment.tr(),
style: const TextStyle(
fontSize: 14,
color: MyColors.green9CColor,
decoration: TextDecoration.underline,
decorationColor: MyColors.green9CColor,
),
),
],
),
),
);
}).toList(),
)
: hasSubValues
? Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (displayValue.isNotEmpty) displayValue.toText14(color: MyColors.darkTextColor),
if (displayValue.isNotEmpty) 8.height,
...data.subValues!
.map(
(subValue) => Padding(
padding: const EdgeInsets.only(bottom: 4),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [const Text("• ", style: TextStyle(fontSize: 14)), Expanded(child: subValue.toText14(color: MyColors.darkTextColor))],
),
),
)
.toList(),
],
)
: (displayValue.isNotEmpty ? displayValue : "-").toText14(color: MyColors.darkTextColor),
),
],
),
),
if (!isLast) const Padding(padding: EdgeInsets.only(left: 14, right: 14), child: Divider(height: 1, thickness: 1, color: Color(0xffefefef))),
],
);
}).toList(),
),
),
);
},
).paddingOnly(bottom: 20),
);
}
}

@ -1,7 +1,6 @@
import 'dart:async';
import 'dart:io';
import 'dart:ui' as ui;
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_countdown_timer/flutter_countdown_timer.dart';
@ -34,6 +33,7 @@ import 'package:mohem_flutter_app/widgets/shimmer/offers_shimmer_widget.dart';
import 'package:provider/provider.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';
import 'package:signalr_netcore/signalr_client.dart';
import 'package:url_launcher/url_launcher.dart';
late HubConnection chatHubConnection;
@ -156,6 +156,7 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
data.fetchMenuEntries();
data.fetchEventActivity();
data.getCategoryOffersListAPI(context);
data.fetchGreetingCards();
marathonProvider.getMarathonDetailsFromApi();
marathonProvider.getMarathonTutorial();
if (isFromInit) {
@ -164,11 +165,12 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
if (!cProvider.disbaleChatForThisUser && !isFromInit) checkHubCon();
_refreshController.refreshCompleted();
// await data.fetchTicketBooking();
await data.fetchTicketBooking();
// if (data.ticketBookingResponse != null && !data.ticketBookingResponse!.success) {
// // data.fetchTicketBalance();
// data.fetchTicketBalance();
// }
//continue here
}
@ -183,13 +185,18 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
ItgMainRes? response = await DashboardApiClient().getAdvertisementDetail(list[ermIndex].notificationMasterId ?? "");
// Utils.hideLoading(context);
if (response!.mohemmItgResponseItem!.result!.data != null) {
for (ItgResponseData payload in response.mohemmItgResponseItem!.result!.data!) {
if (payload.notificationMasterId == list[ermIndex].notificationMasterId) {
payload.deadline = list[ermIndex].deadline;
}
}
if (list[ermIndex].notificationType == "Survey") {
await Navigator.pushNamed(context, AppRoutes.survey, arguments: response.mohemmItgResponseItem!.result!.data!.first);
} else {
await Navigator.pushNamed(
context,
AppRoutes.advertisement,
arguments: {"masterId": list[ermIndex].notificationMasterId, "advertisement": response.mohemmItgResponseItem!.result!.data!.first.advertisement},
arguments: {"masterId": list[ermIndex].notificationMasterId, "advertisement": response.mohemmItgResponseItem!.result!.data!.first},
);
}
}
@ -283,7 +290,9 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
});
},
),
Image.asset("assets/images/logos/main_mohemm_logo.png", width: 134, height: 28).expanded,
Image
.asset("assets/images/logos/main_mohemm_logo.png", width: 134, height: 28)
.expanded,
SvgPicture.asset("assets/images/announcements.svg", matchTextDirection: true).onPress(() async {
await Navigator.pushNamed(context, AppRoutes.announcements);
}),
@ -423,8 +432,29 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
),
],
).paddingOnly(left: 21, right: 21, top: 7, bottom: 21),
eventActivityWidget(context),
Consumer<DashboardProviderModel>(
builder: (BuildContext context, DashboardProviderModel model, Widget? child) {
if (model.isGreetingCardsLoading) {
return const GreetingCardShimmer();
} else if (model.isDisplayEidGreetings && model.greetingCardsList != null && model.greetingCardsList!.isNotEmpty) {
return SizedBox(
width: double.infinity,
child: SvgPicture.network(
AppState().isArabic(context)
? (model.greetingCardsList!.first.backgroundImageUrlAr ?? "https://www.hmg.com/Lists/CS_Greeting_Cards/Attachments/5/CS_Ramadan_26.jpg")
: (model.greetingCardsList!.first.backgroundImageUrlEn ?? "https://www.hmg.com/Lists/CS_Greeting_Cards/Attachments/5/CS_Ramadan_26.jpg"),
fit: BoxFit.cover,
placeholderBuilder: (context) => ClipRRect(borderRadius: BorderRadius.circular(18), child: Container(height: 80, color: Colors.white).toShimmer()),
).onPress(() {
launchUrl(Uri.parse(AppState().isArabic(context) ? model.greetingCardsList!.first.urlAr! : model.greetingCardsList!.first.urlEn!));
}),
);
} else {
return const SizedBox();
}
},
).paddingOnly(bottom: 24, left: 24, right: 24),
// eventActivityWidget(context),
if (isDisplayMazaya) ...[
Column(
mainAxisSize: MainAxisSize.min,
@ -471,7 +501,7 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
fontFamily: AppState().isArabic(context) ? 'Cairo' : 'Poppins',
fontWeight: FontWeight.w700,
height: 24 / 16,
color: Color(0xFF5D5E5E),
color: const Color(0xFF5D5E5E),
),
),
TextSpan(
@ -576,12 +606,10 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
LocaleKeys.discounts.tr().toText24(isBold: true),
6.width,
Container(
padding: const EdgeInsets.only(left: 8, right: 8),
decoration: BoxDecoration(
color: MyColors.yellowColor,
borderRadius: BorderRadius.circular(10),
),
child: LocaleKeys.newString.tr().toText10(isBold: true)),
padding: const EdgeInsets.only(left: 8, right: 8),
decoration: BoxDecoration(color: MyColors.yellowColor, borderRadius: BorderRadius.circular(10)),
child: LocaleKeys.newString.tr().toText10(isBold: true),
),
],
),
],
@ -589,7 +617,7 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
),
LocaleKeys.viewAllOffers.tr().toText12(isUnderLine: true).onPress(() {
Navigator.pushNamed(context, AppRoutes.offersAndDiscounts);
})
}),
],
).paddingOnly(left: 21, right: 21),
Consumer<DashboardProviderModel>(
@ -597,59 +625,54 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
return SizedBox(
height: 103 + 33,
child: ListView.separated(
shrinkWrap: true,
physics: const BouncingScrollPhysics(),
padding: const EdgeInsets.only(left: 21, right: 21, top: 13),
scrollDirection: Axis.horizontal,
itemBuilder: (BuildContext cxt, int index) {
return model.isOffersLoading
? const OffersShimmerWidget()
: InkWell(
onTap: () {
navigateToDetails(data.getOffersList[index]);
},
child: SizedBox(
width: 73,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
width: 73,
height: 73,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: const BorderRadius.all(
Radius.circular(100),
),
border: Border.all(color: MyColors.lightGreyE3Color, width: 1),
),
child: ClipRRect(
borderRadius: const BorderRadius.all(
Radius.circular(50),
),
child: Hero(
tag: "ItemImage" + data.getOffersList[index].offersDiscountId.toString()!,
transitionOnUserGestures: true,
child: Image.network(
data.getOffersList[index].logo ?? "",
fit: BoxFit.contain,
),
),
),
shrinkWrap: true,
physics: const BouncingScrollPhysics(),
padding: const EdgeInsets.only(left: 21, right: 21, top: 13),
scrollDirection: Axis.horizontal,
itemBuilder: (BuildContext cxt, int index) {
return model.isOffersLoading
? const OffersShimmerWidget()
: InkWell(
onTap: () {
navigateToDetails(data.getOffersList[index]);
},
child: SizedBox(
width: 73,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
width: 73,
height: 73,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: const BorderRadius.all(Radius.circular(100)),
border: Border.all(color: MyColors.lightGreyE3Color, width: 1),
),
4.height,
Expanded(
child: AppState().isArabic(context)
? data.getOffersList[index].titleAr!.toText12(isCenter: true, maxLine: 1)
: data.getOffersList[index].titleEn!.toText12(isCenter: true, maxLine: 1),
child: ClipRRect(
borderRadius: const BorderRadius.all(Radius.circular(50)),
child: Hero(
tag: "ItemImage" + data.getOffersList[index].offersDiscountId.toString()!,
transitionOnUserGestures: true,
child: Image.network(data.getOffersList[index].logo ?? "", fit: BoxFit.contain),
),
),
],
),
),
4.height,
Expanded(
child:
AppState().isArabic(context)
? data.getOffersList[index].titleAr!.toText12(isCenter: true, maxLine: 1)
: data.getOffersList[index].titleEn!.toText12(isCenter: true, maxLine: 1),
),
],
),
);
},
separatorBuilder: (BuildContext cxt, int index) => 8.width,
itemCount: 9),
),
);
},
separatorBuilder: (BuildContext cxt, int index) => 8.width,
itemCount: 9,
),
);
},
),
@ -668,7 +691,9 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
mainAxisSize: MainAxisSize.min,
children: [
ServicesWidget(),
context.watch<MarathonProvider>().isLoading ? const MarathonBannerShimmer().paddingAll(20) : const MarathonBanner().paddingOnly(left: 21, right: 21, bottom: 8, top: 8),
context
.watch<MarathonProvider>()
.isLoading ? const MarathonBannerShimmer().paddingAll(20) : const MarathonBanner().paddingOnly(left: 21, right: 21, bottom: 8, top: 8),
// context.watch<MarathonProvider>().isTutorialLoading
// ? const MarathonBannerShimmer().paddingAll(20)
// : Container(
@ -829,9 +854,16 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
}
Widget eventActivityWidget(BuildContext context) {
return (context.watch<DashboardProviderModel>().isEventLoadingLoading)
return (context
.watch<DashboardProviderModel>()
.isEventLoadingLoading)
? const MarathonBannerShimmer().paddingOnly(left: 21, right: 21, bottom: 21, top: 0)
: (context.watch<DashboardProviderModel>().eventActivity != null && context.watch<DashboardProviderModel>().eventActivity!.isActive == true)
: (context
.watch<DashboardProviderModel>()
.eventActivity != null && context
.watch<DashboardProviderModel>()
.eventActivity!
.isActive == true)
? const EventActivityBanner().paddingOnly(left: 21, right: 21, bottom: 21, top: 0)
: const SizedBox();
}
@ -864,4 +896,4 @@ class _DashboardScreenState extends State<DashboardScreen> with WidgetsBindingOb
}
return false;
}
}
}

@ -1,19 +1,27 @@
import 'package:flutter/material.dart';
import 'package:flutter_countdown_timer/index.dart';
import 'package:jiffy/jiffy.dart';
import 'package:lottie/lottie.dart';
import 'package:mohem_flutter_app/api/dashboard_api_client.dart';
import 'package:mohem_flutter_app/app_state/app_state.dart';
import 'package:mohem_flutter_app/classes/colors.dart';
import 'package:mohem_flutter_app/classes/lottie_consts.dart';
import 'package:mohem_flutter_app/classes/utils.dart';
import 'package:mohem_flutter_app/config/routes.dart';
import 'package:mohem_flutter_app/extensions/int_extensions.dart';
import 'package:mohem_flutter_app/extensions/string_extensions.dart';
import 'package:mohem_flutter_app/extensions/widget_extensions.dart';
import 'package:mohem_flutter_app/main.dart';
import 'package:mohem_flutter_app/models/dashboard/menu_entries.dart';
import 'package:mohem_flutter_app/models/itg/advertisement.dart' as ads;
import 'package:mohem_flutter_app/models/itg/itg_response_model.dart' as itgres;
import 'package:mohem_flutter_app/provider/dashboard_provider_model.dart';
import 'package:mohem_flutter_app/ui/my_attendance/services_menu_list_screen.dart';
import 'package:mohem_flutter_app/widgets/app_bar_widget.dart';
import 'package:mohem_flutter_app/widgets/button/default_button.dart';
import 'package:mohem_flutter_app/widgets/my_video_progress_indicator.dart';
import 'package:provider/provider.dart';
import 'package:sizer/sizer.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:video_player/video_player.dart';
@ -26,7 +34,7 @@ class ITGAdsScreen extends StatefulWidget {
class _ITGAdsScreenState extends State<ITGAdsScreen> {
late Future<VideoPlayerController> _futureController;
late VideoPlayerController _controller;
VideoPlayerController? _controller;
bool skip = false;
bool isVideo = false;
bool isImage = false;
@ -37,6 +45,7 @@ class _ITGAdsScreenState extends State<ITGAdsScreen> {
// late File imageFile;
late String imageUrl;
itgres.ItgResponseData? advertisementPayload;
ads.Advertisement? advertisementData;
dynamic data;
String? masterID;
@ -47,6 +56,7 @@ class _ITGAdsScreenState extends State<ITGAdsScreen> {
final ValueNotifier<bool> hasTimerEnded = ValueNotifier(false);
late CountdownTimerController timerController;
CountdownTimerController? deadlineTimerController;
void checkFileType() {
if (advertisementData!.viewAttachFileColl!.first.contentType!.toLowerCase() == "text") {
@ -123,34 +133,227 @@ class _ITGAdsScreenState extends State<ITGAdsScreen> {
});
}
String getDeadlineText() {
if (advertisementPayload?.deadline == null) {
return "";
}
try {
// Parse the deadline string using Jiffy (format: MM/dd/yyyy hh:mm:ss aa)
Jiffy deadlineJiffy = Jiffy.parse(advertisementPayload!.deadline!, pattern: "MM/dd/yyyy hh:mm:ss aa");
Jiffy nowJiffy = Jiffy.now();
// Calculate days left
int daysLeft = deadlineJiffy.diff(nowJiffy, unit: Unit.day).toInt();
if (daysLeft < 0) {
// Deadline has passed
int daysAgo = daysLeft.abs();
if (AppState().isArabic(context)) {
return "انتهى الموعد النهائي منذ $daysAgo ${daysAgo == 1 ? 'يوم' : 'أيام'}";
} else {
return "Deadline passed $daysAgo ${daysAgo == 1 ? 'day' : 'days'} ago";
}
} else if (daysLeft == 0) {
// Deadline is today
if (AppState().isArabic(context)) {
return "الموعد النهائي اليوم!";
} else {
return "Deadline is today!";
}
} else if (daysLeft == 1) {
// Deadline is tomorrow
if (AppState().isArabic(context)) {
return "الموعد النهائي غداً";
} else {
return "Deadline is tomorrow";
}
} else {
// Deadline is in the future
if (AppState().isArabic(context)) {
return "متبقي $daysLeft ${daysLeft <= 10 ? 'أيام' : 'يوم'}";
} else {
return "$daysLeft ${daysLeft == 1 ? 'day' : 'days'} left";
}
}
} catch (e) {
logger.e("Error parsing deadline: $e");
return "Deadline: ${Utils.formatDate(advertisementPayload!.deadline)}";
}
}
void initDeadlineTimer() {
if (advertisementPayload?.deadline == null) return;
try {
// Parse the deadline string using Jiffy (format: MM/dd/yyyy hh:mm:ss aa)
Jiffy deadlineJiffy = Jiffy.parse(advertisementPayload!.deadline!, pattern: "MM/dd/yyyy hh:mm:ss aa");
DateTime deadlineDate = deadlineJiffy.dateTime;
int endTime = deadlineDate.millisecondsSinceEpoch;
int currentTime = DateTime.now().millisecondsSinceEpoch;
// Only create timer if deadline is in the future
if (endTime > currentTime) {
deadlineTimerController = CountdownTimerController(
endTime: endTime,
onEnd: () {
// Timer ended, could trigger a refresh or notification
logger.d("Deadline timer ended");
},
);
}
} catch (e) {
logger.e("Error initializing deadline timer: $e");
}
}
@override
void dispose() {
if (_controller != null) _controller.dispose();
_controller?.dispose();
deadlineTimerController?.dispose();
super.dispose();
}
// Helper method to get localized text
String _getLocalizedText(String arabic, String english) {
return AppState().isArabic(context) ? arabic : english;
}
// Build advertisement content text
Widget _buildAdvertisementContent() {
String content = AppState().isArabic(context) ? advertisementData!.viewAttachFileColl![0].base64String! : advertisementData!.viewAttachFileColl![1].base64String!;
return content.toText16(color: MyColors.darkTextColor);
}
// Build deadline section with timer
Widget _buildDeadlineSection() {
if (deadlineTimerController != null) {
return Center(
child: Column(crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center, children: [_buildEndDateText(), 4.height, _buildTimeRemainingRow(), 8.height]),
);
} else {
return Center(child: _buildEndDateText(isLargeText: true));
}
}
// Build end date text
Widget _buildEndDateText({bool isLargeText = false}) {
String label = _getLocalizedText("تاريخ الانتهاء: ", "End Date: ");
String fullText = label + advertisementPayload!.deadline ?? "";
return isLargeText ? fullText.toText16(color: MyColors.darkTextColor) : fullText.toText14(color: MyColors.darkTextColor);
}
// Build time remaining row with timer
Widget _buildTimeRemainingRow() {
return Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [_getLocalizedText("الوقت المتبقي", "Time Remaining").toText16(color: MyColors.darkTextColor, isBold: true), 8.width, _buildCountdownTimer()],
);
}
// Build countdown timer widget
Widget _buildCountdownTimer() {
return CountdownTimer(
controller: deadlineTimerController,
endWidget: _getLocalizedText("انتهى الموعد النهائي!", "Deadline Expired!").toText16(color: MyColors.redColor, isBold: true),
textStyle: const TextStyle(color: MyColors.darkTextColor, fontSize: 16, letterSpacing: -0.48, fontWeight: FontWeight.bold),
);
}
// Build action buttons list
Widget _buildActionButtons() {
return ListView.separated(
itemCount: advertisementData!.actionButtonsColl?.length ?? 0,
separatorBuilder: (cxt, index) => 16.height,
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
padding: EdgeInsets.zero,
itemBuilder: (cxt, index) {
var actionButton = advertisementData!.actionButtonsColl![index];
String btnText = _getLocalizedText(actionButton.btnTextAr, actionButton.btnTextEn);
return DefaultButton(btnText, () => _handleButtonAction(actionButton));
},
);
}
// Handle button action based on type
Future<void> _handleButtonAction(actionButton) async {
String actionValue = actionButton.actionValue.toLowerCase();
if (actionValue == "skip") {
Navigator.pop(context);
return;
}
String actionType = actionButton.actionType?.toLowerCase() ?? '';
if (actionType == 'redirect' && actionValue == 'external') {
await _handleExternalRedirect(actionButton.url);
} else if (actionType == 'redirect' && actionValue == 'internal') {
await _handleInternalRedirect(actionButton.url);
} else if (actionType == 'eit' && actionValue == 'internal') {
await _handleEitInternal(actionButton.url);
} else {
await _handleExternalRedirect(actionButton.iconOrImage);
}
}
// Handle external URL redirect
Future<void> _handleExternalRedirect(String url) async {
Uri uri = Uri.parse(url);
await launchUrl(uri, mode: LaunchMode.externalApplication).catchError((err) {
Utils.showToast('Could not launch');
});
Navigator.pop(context);
}
// Handle internal route navigation
Future<void> _handleInternalRedirect(String url) async {
await Navigator.pushNamed(context, url);
}
// Handle EIT internal navigation
Future<void> _handleEitInternal(String url) async {
var pro = Provider.of<DashboardProviderModel>(context, listen: false);
List<GetMenuEntriesList> menuList =
pro.getMenuEntriesList?.where((element) => element.parentMenuName == url && (element.menuEntryType == "FUNCTION" || element.menuEntryType == "MENU")).toList() ?? [];
Navigator.pushNamed(context, AppRoutes.servicesMenuListScreen, arguments: ServicesMenuListScreenParams(advertisementData!.advertisementTitle!, menuList));
}
@override
Widget build(BuildContext context) {
data = ModalRoute.of(context)!.settings.arguments;
advertisementData ??= data["advertisement"] as ads.Advertisement;
advertisementPayload ??= data["advertisement"] as itgres.ItgResponseData;
advertisementData = advertisementPayload!.advertisement;
masterID ??= data["masterId"];
if (advertisementData != null) {
checkFileType();
videoDuration = advertisementData?.durationInSeconds ?? 0;
timerController = CountdownTimerController(endTime: DateTime.now().millisecondsSinceEpoch + 1000 * videoDuration, onEnd: onTimerEnd);
if (isTextURL) {
if (advertisementPayload?.deadline != null && deadlineTimerController == null) {
initDeadlineTimer();
}
} else {
videoDuration = advertisementData?.durationInSeconds ?? 0;
timerController = CountdownTimerController(endTime: DateTime.now().millisecondsSinceEpoch + 1000 * videoDuration, onEnd: onTimerEnd);
}
}
return Scaffold(
backgroundColor: isTextURL ? Colors.white : Colors.black,
appBar: isTextURL
? AppBar(
centerTitle: true,
automaticallyImplyLeading: false,
backgroundColor: Colors.white,
title: (AppState().isArabic(context) ? advertisementData!.advertisementTitleAr! : advertisementData!.advertisementTitle!).toText24(color: MyColors.darkTextColor, isBold: true),
//advertisementData!.viewAttachFileColl!.first.base64String!.toText24(color: MyColors.darkTextColor, isBold: true),
)
: null,
appBar:
isTextURL
? AppBar(
centerTitle: true,
automaticallyImplyLeading: false,
backgroundColor: Colors.white,
title: (AppState().isArabic(context) ? advertisementData!.advertisementTitleAr! : advertisementData!.advertisementTitle!).toText24(color: MyColors.darkTextColor, isBold: true),
)
: null,
body: Stack(
children: [
if (isVideo)
@ -163,38 +366,33 @@ class _ITGAdsScreenState extends State<ITGAdsScreen> {
mainAxisAlignment: MainAxisAlignment.center,
children: [
Center(
child: isAudio
? Lottie.asset(MyLottieConsts.audioPlaybackLottie)
: AspectRatio(
aspectRatio: _controller.value.aspectRatio,
child: Stack(
alignment: Alignment.bottomCenter,
children: [
VideoPlayer(_controller),
if (advertisementData?.isOptional ?? false)
Positioned(
top: 4,
right: 8,
child: Container(
padding: const EdgeInsets.only(left: 8, right: 8, top: 4, bottom: 4),
decoration: BoxDecoration(color: Colors.white.withOpacity(0.5), borderRadius: BorderRadius.circular(30)),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(AppState().isArabic(context) ? "يتخطى" : "Skip"),
Icon(Icons.skip_next),
],
),
).onPress(() {
Navigator.pop(context);
DashboardApiClient().setAdvertisementViewed(masterID!, advertisementData!.advertisementId!, "Skip").then((value) {
logger.d(value);
});
}),
),
],
child:
isAudio
? Lottie.asset(MyLottieConsts.audioPlaybackLottie)
: AspectRatio(
aspectRatio: _controller!.value.aspectRatio,
child: Stack(
alignment: Alignment.bottomCenter,
children: [
VideoPlayer(_controller!),
if (advertisementData?.isOptional ?? false)
Positioned(
top: 4,
right: 8,
child: Container(
padding: const EdgeInsets.only(left: 8, right: 8, top: 4, bottom: 4),
decoration: BoxDecoration(color: Colors.white.withOpacity(0.5), borderRadius: BorderRadius.circular(30)),
child: Row(mainAxisSize: MainAxisSize.min, children: [Text(AppState().isArabic(context) ? "يتخطى" : "Skip"), Icon(Icons.skip_next)]),
).onPress(() {
Navigator.pop(context);
DashboardApiClient().setAdvertisementViewed(masterID!, advertisementData!.advertisementId!, "Skip").then((value) {
logger.d(value);
});
}),
),
],
),
),
),
),
30.height,
CountdownTimer(
@ -230,7 +428,7 @@ class _ITGAdsScreenState extends State<ITGAdsScreen> {
alignment: Alignment.center,
children: [
MyVideoProgressIndicator(
_controller,
_controller!,
allowScrubbing: false,
//padding: EdgeInsets.only(left: 60, right: 60),
),
@ -238,13 +436,13 @@ class _ITGAdsScreenState extends State<ITGAdsScreen> {
btnText!,
hasTimerEndedBool
? () async {
Navigator.pop(context);
DashboardApiClient()
.setAdvertisementViewed(masterID!, advertisementData!.advertisementId!, advertisementData?.actionButtonsColl![index].actionValue)
.then((value) {
logger.d(value);
});
}
Navigator.pop(context);
DashboardApiClient().setAdvertisementViewed(masterID!, advertisementData!.advertisementId!, advertisementData?.actionButtonsColl![index].actionValue).then((
value,
) {
logger.d(value);
});
}
: null,
disabledColor: Colors.transparent,
textColor: !hasTimerEndedBool ? Colors.white.withOpacity(.5) : Colors.white,
@ -252,15 +450,12 @@ class _ITGAdsScreenState extends State<ITGAdsScreen> {
],
);
}
return DefaultButton(
btnText!,
() async {
Navigator.pop(context);
DashboardApiClient().setAdvertisementViewed(masterID!, advertisementData!.advertisementId!, advertisementData?.actionButtonsColl![index].actionValue).then((value) {
logger.d(value);
});
},
).paddingOnly(left: 60.0, right: 60.0, top: 8, bottom: 8);
return DefaultButton(btnText!, () async {
Navigator.pop(context);
DashboardApiClient().setAdvertisementViewed(masterID!, advertisementData!.advertisementId!, advertisementData?.actionButtonsColl![index].actionValue).then((value) {
logger.d(value);
});
}).paddingOnly(left: 60.0, right: 60.0, top: 8, bottom: 8);
},
// gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
// crossAxisCount: 1,
@ -333,9 +528,7 @@ class _ITGAdsScreenState extends State<ITGAdsScreen> {
],
);
} else {
return const Center(
child: CircularProgressIndicator(),
);
return const Center(child: CircularProgressIndicator());
}
},
),
@ -348,19 +541,17 @@ class _ITGAdsScreenState extends State<ITGAdsScreen> {
children: [
Image.network(imageUrl),
50.height,
Container(padding: const EdgeInsets.all(16), decoration: Utils.containerRadius(MyColors.white, 10), child: const Icon(Icons.thumb_up, color: MyColors.gradiantEndColor)).onPress(
() {
try {
Navigator.pop(context);
DashboardApiClient().setAdvertisementViewed(masterID!, advertisementData!.advertisementId!, "Like").then((value) {
logger.d(value);
});
} catch (ex) {
logger.wtf(ex);
Utils.handleException(ex, context, null);
}
},
),
Container(padding: const EdgeInsets.all(16), decoration: Utils.containerRadius(MyColors.white, 10), child: const Icon(Icons.thumb_up, color: MyColors.gradiantEndColor)).onPress(() {
try {
Navigator.pop(context);
DashboardApiClient().setAdvertisementViewed(masterID!, advertisementData!.advertisementId!, "Like").then((value) {
logger.d(value);
});
} catch (ex) {
logger.wtf(ex);
Utils.handleException(ex, context, null);
}
}),
],
),
),
@ -371,35 +562,11 @@ class _ITGAdsScreenState extends State<ITGAdsScreen> {
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
(AppState().isArabic(context) ? advertisementData!.viewAttachFileColl![0].base64String! : advertisementData!.viewAttachFileColl![1].base64String!)
.toText16(color: MyColors.darkTextColor),
_buildAdvertisementContent(),
24.height,
ListView.separated(
itemCount: advertisementData!.actionButtonsColl?.length ?? 0,
separatorBuilder: (cxt, index) => 16.height,
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
padding: EdgeInsets.zero,
itemBuilder: (cxt, index) => DefaultButton(
AppState().isArabic(context) ? advertisementData!.actionButtonsColl![index].btnTextAr : advertisementData!.actionButtonsColl![index].btnTextEn,
() async {
if (advertisementData!.actionButtonsColl![index].actionValue.toLowerCase() == "skip") {
Navigator.pop(context);
} else {
Uri uri = Uri.parse(advertisementData!.actionButtonsColl![index].iconOrImage);
// if (await canLaunchUrl(uri)) {
await launchUrl(uri, mode: LaunchMode.externalApplication).catchError((err) {
// print(err);
Utils.showToast('Could not launch');
});
Navigator.pop(context);
// } else {
// Utils.showToast('Could not launch');
// }
}
},
),
),
if (advertisementPayload != null && advertisementPayload!.deadline != null) _buildDeadlineSection(),
if (advertisementPayload != null && advertisementPayload!.deadline != null) 24.height,
_buildActionButtons(),
],
),
),

@ -58,15 +58,15 @@ class _AppDrawerState extends State<AppDrawer> {
children: [
AppState().memberInformationList!.eMPLOYEEIMAGE == null
? SvgPicture.asset(
"assets/images/user.svg",
height: 52,
width: 52,
)
"assets/images/user.svg",
height: 52,
width: 52,
)
: CircleAvatar(
radius: 52 / 2,
backgroundImage: MemoryImage(Utils.dataFromBase64String(AppState().memberInformationList!.eMPLOYEEIMAGE!)),
backgroundColor: Colors.black,
),
radius: 52 / 2,
backgroundImage: MemoryImage(Utils.dataFromBase64String(AppState().memberInformationList!.eMPLOYEEIMAGE!)),
backgroundColor: Colors.black,
),
12.width,
Column(
crossAxisAlignment: CrossAxisAlignment.start,
@ -119,7 +119,7 @@ class _AppDrawerState extends State<AppDrawer> {
}),
menuItem("assets/images/drawer/employee_id.svg", LocaleKeys.employeeDigitalID.tr(), "", closeDrawer: false, onPress: () => showMDialog(context, child: EmployeeDigitialIdDialog())),
if (AppState().businessCardPrivilege)
menuItem("assets/images/drawer/view_business_card.svg", LocaleKeys.viewBusinessCard.tr(), "", closeDrawer: false, onPress: () => showMDialog(context, child: BusinessCardDialog(), isBusniessCard: true)),
menuItem("assets/images/drawer/view_business_card.svg", LocaleKeys.viewBusinessCard.tr(), "", closeDrawer: false, onPress: () => showMDialog(context, child: BusinessCardDialog(), isBusniessCard: true)),
menuItem("assets/images/drawer/logout.svg", LocaleKeys.logout.tr(), "", color: MyColors.redA3Color, closeDrawer: false, onPress: (){Utils.performLogout(context, chatData);}),
// menuItem("assets/images/drawer/logout.svg", LocaleKeys.logout.tr(), "", color: MyColors.redA3Color, closeDrawer: false, onPress: () {Navigator.pushNamed(context, AppRoutes.survey,);
],
@ -156,9 +156,9 @@ class _AppDrawerState extends State<AppDrawer> {
],
).paddingOnly(left: 21, top: 10, bottom: 10, right: 21).onPress(closeDrawer
? () async {
Navigator.pop(context);
Future.delayed(const Duration(microseconds: 200), onPress);
}
Navigator.pop(context);
Future.delayed(const Duration(microseconds: 200), onPress);
}
: onPress!);
}
@ -171,13 +171,13 @@ class _AppDrawerState extends State<AppDrawer> {
setState(() {});
}
// void performLogout() async {
// // AppState().isAuthenticated = false;
// // AppState().isLogged = false;
// // AppState().setPostParamsInitConfig();
// // chatData.disposeData();
// // // SharedPreferences prefs = await SharedPreferences.getInstance();
// // // await prefs.clear();
// // Navigator.pushNamedAndRemoveUntil(context, AppRoutes.login, (Route<dynamic> route) => false, arguments: null);
// }
// void performLogout() async {
// // AppState().isAuthenticated = false;
// // AppState().isLogged = false;
// // AppState().setPostParamsInitConfig();
// // chatData.disposeData();
// // // SharedPreferences prefs = await SharedPreferences.getInstance();
// // // await prefs.clear();
// // Navigator.pushNamedAndRemoveUntil(context, AppRoutes.login, (Route<dynamic> route) => false, arguments: null);
// }
}

@ -1,13 +1,18 @@
import 'package:easy_localization/src/public_ext.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:mohem_flutter_app/api/eit_api_client.dart';
import 'package:mohem_flutter_app/app_state/app_state.dart';
import 'package:mohem_flutter_app/classes/utils.dart';
import 'package:mohem_flutter_app/config/routes.dart';
import 'package:mohem_flutter_app/extensions/string_extensions.dart';
import 'package:mohem_flutter_app/extensions/widget_extensions.dart';
import 'package:mohem_flutter_app/generated/locale_keys.g.dart';
import 'package:mohem_flutter_app/models/eit/get_eit_transaction_model.dart';
import 'package:mohem_flutter_app/models/sso_auth_model.dart';
import 'package:mohem_flutter_app/provider/dashboard_provider_model.dart';
import 'package:mohem_flutter_app/ui/my_attendance/dynamic_screens/dynamic_listview_screen.dart';
import 'package:mohem_flutter_app/ui/screens/ticket/ticket_detailed_screen.dart';
import 'package:mohem_flutter_app/widgets/shimmer/dashboard_shimmer_widget.dart';
import 'package:provider/provider.dart';
@ -117,8 +122,29 @@ class MenusWidget extends StatelessWidget {
),
],
).paddingOnly(left: 10, right: 10, bottom: 6, top: 6),
).onPress(() {
Navigator.pushNamed(context, AppRoutes.dynamicScreen, arguments: DynamicListViewParams(LocaleKeys.ticketBalance.tr(), "HMG_TKT_NEW_EIT_SS"));
).onPress(() async {
// Navigator.pushNamed(context, AppRoutes.dynamicScreen, arguments: DynamicListViewParams(LocaleKeys.ticketBalance.tr(), "HMG_TKT_NEW_EIT_SS"));
var pro = Provider.of<DashboardProviderModel>(context, listen: false);
// if (menuEntry.menuName == "HMG_TICKET_REQUESTS") {
Utils.showLoading(context);
//Ticket Work
if (pro.ticketBookingResponse != null && pro.ticketBookingResponse!.success) {
SSOAuthModel? ssoToken = await pro.fetchSSOAuthRedirection(clientID: pro.ticketBookingResponse!.clientId);
if (ssoToken != null) {
dynamic url = await pro.fetchURLRedirection(token: ssoToken.data!.accessToken!, refreshToken: ssoToken.data!.refreshToken!);
await pro.fetchTicketAccuralBalance(context, DateTime.now());
pro.ticketHistoryTransactionList = await EITApiClient().getEITTransactions("HMG_TICKET_ITENARY_HR_EIT_SS", isCompleteList: true);
Utils.hideLoading(context);
// Here Need Work
Navigator.push(context, MaterialPageRoute(builder: (BuildContext context) => TicketDetailedScreen(url: url, jwtToken: ssoToken.data!.accessToken)));
}
//}
} else {
Navigator.pushNamed(context, AppRoutes.dynamicScreen, arguments: DynamicListViewParams(LocaleKeys.ticketBalance.tr(), "HMG_TKT_NEW_EIT_SS"));
}
}),
],
);

@ -92,7 +92,7 @@ class ServicesWidget extends StatelessWidget {
aspectRatio: 105 / 105,
child:
data.isServicesMenusLoading
? ServicesMenuShimmer()
? const ServicesMenuShimmer()
: Container(
decoration: BoxDecoration(
color: Colors.white,
@ -254,6 +254,8 @@ class ServicesWidget extends StatelessWidget {
Navigator.pushNamed(context, AppRoutes.dynamicScreen, arguments: DynamicListViewParams(menuEntry.prompt!, menuEntry.functionName!));
} else if (menuEntry.requestType == "PAYSLIP") {
Navigator.pushNamed(context, AppRoutes.monthlyPaySlip);
} else if (menuEntry.requestType == "CEI") {
Navigator.pushNamed(context, AppRoutes.childEducation, arguments: menuEntry);
}
} else {
if (menuEntry.menuName == "HMG_TICKET_REQUESTS") {
@ -262,11 +264,10 @@ class ServicesWidget extends StatelessWidget {
Utils.showLoading(context);
SSOAuthModel? ssoToken = await pro.fetchSSOAuthRedirection(clientID: pro.ticketBookingResponse!.clientId);
if (ssoToken != null) {
dynamic url = await pro.fetchURLRedirection(token: ssoToken.data!.accessToken!);
dynamic url = await pro.fetchURLRedirection(token: ssoToken.data!.accessToken!, refreshToken: ssoToken.data!.refreshToken!);
await pro.fetchTicketAccuralBalance(context, DateTime.now());
pro.ticketHistoryTransactionList = await EITApiClient().getEITTransactions("HMG_TICKET_ITENARY_HR_EIT_SS", isCompleteList: true);
Utils.hideLoading(context);
// Here Need Work
Navigator.push(context, MaterialPageRoute(builder: (BuildContext context) => TicketDetailedScreen(url: url, jwtToken: ssoToken.data!.accessToken)));
@ -311,7 +312,7 @@ class ServicesWidget extends StatelessWidget {
padding: const EdgeInsets.only(left: 21, right: 21, top: 13, bottom: 13),
scrollDirection: Axis.horizontal,
itemBuilder: (cxt, index) {
return AspectRatio(aspectRatio: 105 / 105, child: ServicesMenuShimmer());
return AspectRatio(aspectRatio: 105 / 105, child: const ServicesMenuShimmer());
},
separatorBuilder: (cxt, index) => 9.width,
itemCount: 4,

@ -326,7 +326,7 @@ class _AddLeaveBalanceScreenState extends State<AddLeaveBalanceScreen> {
displayText = displayText.replaceAll(" 00:00:00", "");
}
if (displayText.contains("/")) {
displayText = DateFormat('yyyy-MM-dd').format(DateFormat("yyyy/MM/dd").parse(displayText));
displayText = DateFormat('yyyy-MM-dd', "en_US").format(DateFormat("yyyy/MM/dd", "en_US").parse(DateUtil.replaceArabicNumber(displayText)));
}
}
return DynamicTextFieldWidget(
@ -336,11 +336,7 @@ class _AddLeaveBalanceScreenState extends State<AddLeaveBalanceScreen> {
isEnable: false,
onTap: () async {
if ((getabsenceDffStructureList![index].eSERVICESDV?.pVALUECOLUMNNAME != null)) {
if (getabsenceDffStructureList![index].isDefaultTypeIsCDPS) {
selectedDate = DateFormat("yyyy/MM/dd").parse(getabsenceDffStructureList![index].eSERVICESDV!.pVALUECOLUMNNAME!.replaceAll('/"', '').replaceAll(" 00:00:00", ""));
} else {
selectedDate = DateTime.parse(getabsenceDffStructureList![index].eSERVICESDV!.pVALUECOLUMNNAME!);
}
selectedDate = DateUtil.parseFlexibleDateTime(getabsenceDffStructureList![index].eSERVICESDV!.pVALUECOLUMNNAME) ?? selectedDate;
}
DateTime date = await _selectDate(context);
String dateString = date.toString().split(' ').first;
@ -353,14 +349,14 @@ class _AddLeaveBalanceScreenState extends State<AddLeaveBalanceScreen> {
pRETURNMSG: "null",
pRETURNSTATUS: getabsenceDffStructureList![index].dEFAULTVALUE,
pVALUECOLUMNNAME:
getabsenceDffStructureList![index].isDefaultTypeIsCDPS ? Utils.reverseFormatStandardDate(Utils.formatDate(dateString)) : DateFormat('yyyy-MM-ddThh:mm:ss.s').format(date));
getabsenceDffStructureList![index].isDefaultTypeIsCDPS ? Utils.reverseFormatStandardDate(Utils.formatDate(dateString)) : DateFormat('yyyy-MM-ddThh:mm:ss.s', "en_US").format(date));
} else {
eservicesdv = ESERVICESDV(
pIDCOLUMNNAME: dateString,
pRETURNMSG: "null",
pRETURNSTATUS: getabsenceDffStructureList![index].dEFAULTVALUE,
pVALUECOLUMNNAME:
getabsenceDffStructureList![index].isDefaultTypeIsCDPS ? Utils.reverseFormatStandardDate(Utils.formatDate(dateString)) : DateFormat('yyyy-MM-ddThh:mm:ss.s').format(date));
getabsenceDffStructureList![index].isDefaultTypeIsCDPS ? Utils.reverseFormatStandardDate(Utils.formatDate(dateString)) : DateFormat('yyyy-MM-ddThh:mm:ss.s', "en_US").format(date));
}
getabsenceDffStructureList![index].eSERVICESDV = eservicesdv;
setState(() {});
@ -374,7 +370,7 @@ class _AddLeaveBalanceScreenState extends State<AddLeaveBalanceScreen> {
).paddingOnly(bottom: 12);
} else if (model.fORMATTYPE == "Y") {
String displayText = model.eSERVICESDV?.pIDCOLUMNNAME ?? "";
if (getabsenceDffStructureList![index].isDefaultTypeIsCDPS) {
if (getabsenceDffStructureList[index].isDefaultTypeIsCDPS) {
displayText = Utils.reverseFormatDate(displayText);
// if (displayText.contains(" 00:00:00")) {
// displayText = displayText.replaceAll(" 00:00:00", "");
@ -390,19 +386,7 @@ class _AddLeaveBalanceScreenState extends State<AddLeaveBalanceScreen> {
isEnable: false,
onTap: () async {
if ((getabsenceDffStructureList![index].eSERVICESDV?.pVALUECOLUMNNAME != null)) {
if (getabsenceDffStructureList![index].isDefaultTypeIsCDPS) {
String tempDate = getabsenceDffStructureList![index].eSERVICESDV!.pVALUECOLUMNNAME!;
if (tempDate.contains("00:00:00")) {
tempDate = tempDate.replaceAll("00:00:00", '').trim();
}
if (tempDate.contains("/")) {
selectedDate = DateFormat("yyyy/MM/dd").parse(tempDate);
} else {
selectedDate = DateFormat("yyyy-MM-dd").parse(tempDate);
}
} else {
selectedDate = DateTime.parse(getabsenceDffStructureList![index].eSERVICESDV!.pVALUECOLUMNNAME!);
}
selectedDate = DateUtil.parseFlexibleDateTime(getabsenceDffStructureList![index].eSERVICESDV!.pVALUECOLUMNNAME) ?? selectedDate;
}
DateTime date = await _selectDate(context);
String dateString = date.toString().split(' ').first;
@ -414,14 +398,14 @@ class _AddLeaveBalanceScreenState extends State<AddLeaveBalanceScreen> {
pRETURNMSG: "null",
pRETURNSTATUS: getabsenceDffStructureList![index].dEFAULTVALUE,
pVALUECOLUMNNAME:
getabsenceDffStructureList![index].isDefaultTypeIsCDPS ? Utils.reverseFormatStandardDate(Utils.formatDate(dateString)) : DateFormat('yyyy-MM-ddThh:mm:ss.s').format(date));
getabsenceDffStructureList![index].isDefaultTypeIsCDPS ? Utils.reverseFormatStandardDate(Utils.formatDate(dateString)) : DateFormat('yyyy-MM-ddThh:mm:ss.s', "en_US").format(date));
} else {
eservicesdv = ESERVICESDV(
pIDCOLUMNNAME: dateString,
pRETURNMSG: "null",
pRETURNSTATUS: getabsenceDffStructureList![index].dEFAULTVALUE,
pVALUECOLUMNNAME:
getabsenceDffStructureList![index].isDefaultTypeIsCDPS ? Utils.reverseFormatStandardDate(Utils.formatDate(dateString)) : DateFormat('yyyy-MM-ddThh:mm:ss.s').format(date));
getabsenceDffStructureList![index].isDefaultTypeIsCDPS ? Utils.reverseFormatStandardDate(Utils.formatDate(dateString)) : DateFormat('yyyy-MM-ddThh:mm:ss.s', "en_US").format(date));
}
getabsenceDffStructureList![index].eSERVICESDV = eservicesdv;
@ -512,7 +496,7 @@ class _AddLeaveBalanceScreenState extends State<AddLeaveBalanceScreen> {
displayText = displayText.replaceAll(" 00:00:00", "");
}
if (!displayText.contains("-")) {
displayText = DateFormat('yyyy-MM-dd').format(DateFormat("yyyy/MM/dd").parse(displayText));
displayText = DateFormat('yyyy-MM-dd', "en_US").format(DateFormat("yyyy/MM/dd", "en_US").parse(DateUtil.replaceArabicNumber(displayText)));
}
}
return DynamicTextFieldWidget(
@ -522,11 +506,7 @@ class _AddLeaveBalanceScreenState extends State<AddLeaveBalanceScreen> {
isEnable: false,
onTap: () async {
if ((getabsenceDffStructureList![index].eSERVICESDV?.pVALUECOLUMNNAME != null)) {
if (getabsenceDffStructureList![index].isDefaultTypeIsCDPS) {
selectedDate = DateFormat("yyyy/MM/dd").parse(getabsenceDffStructureList![index].eSERVICESDV!.pVALUECOLUMNNAME!.replaceAll('/"', '').replaceAll(" 00:00:00", ""));
} else {
selectedDate = DateTime.parse(getabsenceDffStructureList![index].eSERVICESDV!.pVALUECOLUMNNAME!);
}
selectedDate = DateUtil.parseFlexibleDateTime(getabsenceDffStructureList![index].eSERVICESDV!.pVALUECOLUMNNAME) ?? selectedDate;
}
DateTime date = await _selectDate(context);
String dateString = date.toString().split(' ').first;
@ -536,7 +516,7 @@ class _AddLeaveBalanceScreenState extends State<AddLeaveBalanceScreen> {
pRETURNMSG: "null",
pRETURNSTATUS: getabsenceDffStructureList![index].dEFAULTVALUE,
pVALUECOLUMNNAME:
getabsenceDffStructureList![index].isDefaultTypeIsCDPS ? Utils.reverseFormatStandardDate(Utils.formatDate(dateString)) : DateFormat('yyyy-MM-ddThh:mm:ss.s').format(date));
getabsenceDffStructureList![index].isDefaultTypeIsCDPS ? Utils.reverseFormatStandardDate(Utils.formatDate(dateString)) : DateFormat('yyyy-MM-ddThh:mm:ss.s', "en_US").format(date));
getabsenceDffStructureList![index].eSERVICESDV = eservicesdv;
setState(() {});
// if (model.cHILDSEGMENTSVSSplited?.isNotEmpty ?? false) {
@ -557,14 +537,14 @@ class _AddLeaveBalanceScreenState extends State<AddLeaveBalanceScreen> {
if (getabsenceDffStructureList[index].mOBILEENABLED != "Y") return;
if ((getabsenceDffStructureList![index].eSERVICESDV?.pVALUECOLUMNNAME != null)) {
var timeString = getabsenceDffStructureList![index].eSERVICESDV!.pVALUECOLUMNNAME!.split(":");
selectedDate = DateTime(0, 0, 0, int.parse(timeString[0]), int.parse(timeString[1]));
var timeString = DateUtil.replaceArabicNumber(getabsenceDffStructureList![index].eSERVICESDV!.pVALUECOLUMNNAME).split(":");
selectedDate = DateTime(0, 0, 0, int.tryParse(timeString[0]) ?? 0, timeString.length > 1 ? (int.tryParse(timeString[1]) ?? 0) : 0);
//DateTime.parse(getabsenceDffStructureList![index].eSERVICESDV!.pVALUECOLUMNNAME!);
}
TimeOfDay _time = await _selectTime(context);
DateTime tempTime = DateTime(0, 1, 1, _time.hour, _time.minute);
String time = DateFormat('HH:mm').format(tempTime).trim();
String time = DateFormat('HH:mm', "en_US").format(tempTime).trim();
// DateTime date1 = DateTime(date.year, date.month, date.day);
// getabsenceDffStructureList![index].fieldAnswer = date.toString();

@ -0,0 +1,107 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:mohem_flutter_app/api/dashboard_api_client.dart';
import 'package:mohem_flutter_app/classes/colors.dart';
import 'package:mohem_flutter_app/classes/utils.dart';
import 'package:mohem_flutter_app/extensions/int_extensions.dart';
import 'package:mohem_flutter_app/generated/locale_keys.g.dart';
import 'package:mohem_flutter_app/models/get_employee_parking_details_model.dart';
import 'package:mohem_flutter_app/widgets/app_bar_widget.dart';
class ParkingQrScreen extends StatefulWidget {
const ParkingQrScreen({Key? key}) : super(key: key);
@override
_RequestDetailsState createState() => _RequestDetailsState();
}
class _RequestDetailsState extends State<ParkingQrScreen> {
GetEmployeeParking? qrData;
@override
void initState() {
super.initState();
getTicketDetails();
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBarWidget(context, title: LocaleKeys.parkingQr.tr()),
body:
qrData?.getEmployeeParking == null
? Center(child: Text(LocaleKeys.noDataAvailable.tr()))
: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Center(
child: Container(
padding: const EdgeInsets.all(20.0),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
boxShadow: [BoxShadow(color: Colors.grey.withValues(alpha: 0.2), spreadRadius: 5, blurRadius: 10, offset: const Offset(0, 3))],
),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
// QR Code Image
if (qrData!.getEmployeeParking!.qrCodeImageBase64 != null && qrData!.getEmployeeParking!.qrCodeImageBase64!.isNotEmpty)
Image.memory(Utils.dataFromBase64String(qrData!.getEmployeeParking!.qrCodeImageBase64!), width: 300, height: 300, fit: BoxFit.contain)
else
Container(
width: 300,
height: 300,
color: MyColors.lightGreyEFColor,
child: Center(child: Text(LocaleKeys.noDataAvailable.tr(), style: const TextStyle(color: MyColors.grey67Color))),
),
10.height,
Container(height: 1, color: MyColors.lightGreyE3Color, margin: const EdgeInsets.symmetric(vertical: 10)),
20.height,
SizedBox(
width: double.infinity,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Employee Code
if (qrData!.getEmployeeParking!.employeeCode != null && qrData!.getEmployeeParking!.employeeCode!.isNotEmpty) ...[
Text(LocaleKeys.employeeNumber.tr(), style: const TextStyle(fontSize: 14, color: MyColors.grey67Color, fontWeight: FontWeight.w400)),
8.height,
Text(qrData!.getEmployeeParking!.employeeCode!, style: const TextStyle(fontSize: 18, color: MyColors.darkTextColor, fontWeight: FontWeight.w600)),
8.height,
],
if (qrData!.getEmployeeParking!.createdAt != null) ...[
Text(LocaleKeys.creationDate.tr(), style: const TextStyle(fontSize: 14, color: MyColors.grey67Color, fontWeight: FontWeight.w400)),
8.height,
Text(
DateFormat('dd MMM yyyy, hh:mm a').format(qrData!.getEmployeeParking!.createdAt!),
style: const TextStyle(fontSize: 16, color: MyColors.darkTextColor, fontWeight: FontWeight.w500),
),
],
],
),
),
],
),
),
),
),
),
);
}
void getTicketDetails() async {
try {
qrData = GetEmployeeParking();
Utils.showLoading(context);
qrData = await DashboardApiClient().getEmployeeParkingQrCode();
Utils.hideLoading(context);
setState(() {});
} catch (ex) {
Utils.hideLoading(context);
Utils.handleException(ex, context, null);
}
}
}

@ -1,7 +1,6 @@
import 'dart:io';
import 'package:easy_localization/easy_localization.dart';
import 'package:easy_localization/src/public_ext.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:mohem_flutter_app/api/leave_balance_api_client.dart';
@ -27,7 +26,7 @@ import 'package:mohem_flutter_app/widgets/dynamic_forms/dynamic_textfield_widget
class FamilyMemberScreenParams {
String? actionType;
int relationID;
int? relationID;
int? flag;
FamilyMemberScreenParams(this.relationID, {this.actionType, this.flag});
@ -77,7 +76,7 @@ class _AddUpdateFamilyMemberState extends State<AddUpdateFamilyMember> {
element?.getContactDetailsList = new GetContactDetailsList();
});
} else if (params!.actionType == "UPDATE") {
getContactDetailsList = await ProfileApiClient().getContactDetailsList(params!.relationID);
getContactDetailsList = await ProfileApiClient().getContactDetailsList(params!.relationID!);
getBasicDetDffStructureList?.forEach((element) {
element?.getContactDetailsList = getContactDetailsList?.singleWhere((userDetail) => userDetail?.aPPLICATIONCOLUMNNAME == element?.aPPLICATIONCOLUMNNAME);

@ -1,4 +1,4 @@
import 'package:easy_localization/src/public_ext.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:mohem_flutter_app/api/profile_api_client.dart';
@ -13,7 +13,6 @@ import 'package:mohem_flutter_app/models/dashboard/menu_entries.dart';
import 'package:mohem_flutter_app/models/get_employee_contacts.model.dart';
import 'package:mohem_flutter_app/provider/dashboard_provider_model.dart';
import 'package:mohem_flutter_app/ui/profile/add_update_family_member.dart';
import 'package:mohem_flutter_app/ui/profile/profile_screen.dart';
import 'package:mohem_flutter_app/widgets/app_bar_widget.dart';
import 'package:mohem_flutter_app/widgets/button/default_button.dart';
import 'package:provider/provider.dart';
@ -28,22 +27,11 @@ class FamilyMembers extends StatefulWidget {
class _FamilyMembersState extends State<FamilyMembers> {
List<GetEmployeeContactsList> getEmployeeContactsList = [];
dynamic? relationId;
int? flag;
GetMenuEntriesList menuEntries = GetMenuEntriesList();
int? relationId;
@override
void initState() {
super.initState();
List<GetMenuEntriesList> menuData = Provider.of<DashboardProviderModel>(context, listen: false).getMenuEntriesList!;
List<GetMenuEntriesList> arr = menuData.where((GetMenuEntriesList e) => e.requestType == 'CONTACT').toList();
if (arr.isNotEmpty) {
menuEntries = arr[0];
} else {
menuEntries = new GetMenuEntriesList();
}
getEmployeeContacts();
}
@ -59,7 +47,19 @@ class _FamilyMembersState extends State<FamilyMembers> {
}
}
GetMenuEntriesList _getContactMenuEntries(BuildContext context) {
List<GetMenuEntriesList> menuData = context.watch<DashboardProviderModel>().getMenuEntriesList ?? <GetMenuEntriesList>[];
List<GetMenuEntriesList> arr = menuData.where((GetMenuEntriesList e) => e.requestType == 'CONTACT').toList();
return arr.isNotEmpty ? arr.first : GetMenuEntriesList();
}
@override
Widget build(BuildContext context) {
GetMenuEntriesList menuEntries = _getContactMenuEntries(context);
bool canAddFamilyMember = menuEntries.addButton == 'Y';
bool canUpdateFamilyMember = menuEntries.updateButton == 'Y';
bool canDeleteFamilyMember = menuEntries.deleteButton == 'Y';
return Scaffold(
appBar: AppBarWidget(
context,
@ -95,16 +95,18 @@ class _FamilyMembersState extends State<FamilyMembers> {
child: Icon(
Icons.edit,
size: 14,
color: menuEntries.updateButton == 'Y' ? MyColors.grey67Color : MyColors.lightGreyColor,
color: canUpdateFamilyMember ? MyColors.grey67Color : MyColors.lightGreyColor,
)),
TextSpan(
text: LocaleKeys.update.tr(),
style: TextStyle(
color: menuEntries.updateButton == 'Y' ? MyColors.grey67Color : MyColors.lightGreyColor, fontSize: 12, letterSpacing: -0.36, fontWeight: FontWeight.w600),
color: canUpdateFamilyMember ? MyColors.grey67Color : MyColors.lightGreyColor, fontSize: 12, letterSpacing: -0.36, fontWeight: FontWeight.w600),
recognizer: TapGestureRecognizer()
..onTap = () async {
relationId = getEmployeeContactsList[index]!.cONTACTRELATIONSHIPID;
menuEntries.updateButton == 'Y' ? showUpdateAlertDialog(context, relationId, 2, "UPDATE") : null;
relationId = getEmployeeContactsList[index].cONTACTRELATIONSHIPID;
if (canUpdateFamilyMember && relationId != null) {
showUpdateAlertDialog(context, relationId, 2, "UPDATE");
}
})
],
),
@ -117,19 +119,21 @@ class _FamilyMembersState extends State<FamilyMembers> {
child: Icon(
Icons.delete,
size: 15,
color: menuEntries.updateButton == 'Y' ? MyColors.redColor : MyColors.lightGreyColor,
color: canDeleteFamilyMember ? MyColors.redColor : MyColors.lightGreyColor,
),
),
TextSpan(
text: LocaleKeys.remove.tr(),
style: TextStyle(
color: menuEntries.updateButton == 'Y' ? MyColors.redColor : MyColors.lightGreyColor, fontSize: 12, letterSpacing: -0.36, fontWeight: FontWeight.w600),
color: canDeleteFamilyMember ? MyColors.redColor : MyColors.lightGreyColor, fontSize: 12, letterSpacing: -0.36, fontWeight: FontWeight.w600),
),
],
),
).onPress(() {
relationId = getEmployeeContactsList[index]!.cONTACTRELATIONSHIPID;
menuEntries.updateButton == 'Y' ? showRemoveAlertDialog(context, relationId) : null;
relationId = getEmployeeContactsList[index].cONTACTRELATIONSHIPID;
if (canDeleteFamilyMember && relationId != null) {
showRemoveAlertDialog(context, relationId);
}
}),
],
),
@ -139,10 +143,13 @@ class _FamilyMembersState extends State<FamilyMembers> {
),
DefaultButton(
LocaleKeys.addNewFamilyMember.tr(),
menuEntries.updateButton == 'Y'
canAddFamilyMember
? () async {
Navigator.pushNamed(context, AppRoutes.addUpdateFamilyMember, arguments: FamilyMemberScreenParams( relationId, flag: 1, actionType: "ADD"));
// ProfileScreen();
Navigator.pushNamed(
context,
AppRoutes.addUpdateFamilyMember,
arguments: FamilyMemberScreenParams(null, flag: 1, actionType: "ADD"),
);
}
: null)
.insideContainer,
@ -164,6 +171,7 @@ class _FamilyMembersState extends State<FamilyMembers> {
LocaleKeys.ok.tr(),
),
onPressed: () {
Navigator.pop(context);
Navigator.pushNamed(
context,
AppRoutes.addUpdateFamilyMember,
@ -203,7 +211,7 @@ class _FamilyMembersState extends State<FamilyMembers> {
LocaleKeys.ok.tr(),
),
onPressed: () {
Navigator.pushNamed(context, AppRoutes.deleteFamilyMember, arguments: FamilyMemberScreenParams(relationId));
Navigator.pushNamed(context, AppRoutes.deleteFamilyMember, arguments: relationId);
// continueDynamicForms();
},
);

@ -2,6 +2,7 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:mohem_flutter_app/api/profile_api_client.dart';
import 'package:mohem_flutter_app/classes/colors.dart';
import 'package:mohem_flutter_app/classes/utils.dart';
import 'package:mohem_flutter_app/config/routes.dart';
import 'package:mohem_flutter_app/extensions/int_extensions.dart';
import 'package:mohem_flutter_app/extensions/string_extensions.dart';
@ -12,47 +13,64 @@ import 'package:mohem_flutter_app/models/get_employee_contacts.model.dart';
import 'package:mohem_flutter_app/ui/my_attendance/dynamic_screens/dynamic_listview_screen.dart';
import 'package:mohem_flutter_app/widgets/app_bar_widget.dart';
class ChildEducationAssistance extends StatelessWidget {
ChildEducationAssistance({Key? key}) : super(key: key);
class ChildEducationAssistance extends StatefulWidget {
const ChildEducationAssistance({Key? key}) : super(key: key);
@override
State<ChildEducationAssistance> createState() => _ChildEducationAssistanceState();
}
class _ChildEducationAssistanceState extends State<ChildEducationAssistance> {
GetMenuEntriesList? menuEntry;
List<GetEmployeeContactsList> empContactList = [];
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
menuEntry = ModalRoute.of(context)!.settings.arguments as GetMenuEntriesList;
getEmployeeContacts();
});
}
@override
Widget build(BuildContext context) {
menuEntry ??= ModalRoute.of(context)!.settings.arguments as GetMenuEntriesList;
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBarWidget(context, title: menuEntry!.prompt!),
body: FutureBuilder(
future: ProfileApiClient().getEmployeeContacts(),
builder: (BuildContext cxt, AsyncSnapshot<List<GetEmployeeContactsList>> snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(child: CircularProgressIndicator());
} else if (snapshot.hasData) {
List<GetEmployeeContactsList> empContactList = snapshot.data!;
return ListView.separated(
padding: const EdgeInsets.all(21),
separatorBuilder: (BuildContext cxt, int index) => 12.height,
itemCount: empContactList.length,
itemBuilder: (BuildContext context, int index) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
"${empContactList[index].cONTACTNAME}".toText16(color: MyColors.grey3AColor),
"${LocaleKeys.dateOfBirth.tr()}: ${empContactList[index].dATEOFBIRTH?.split(" ").first ?? ""}".toText14(color: MyColors.grey3AColor, weight: FontWeight.w400),
"${empContactList[index].rELATIONSHIP}".toText11(color: MyColors.textMixColor),
],
).objectContainerView(disablePadding: false, center: false).onPress(() {
Navigator.pushNamed(context, AppRoutes.dynamicScreen,
arguments: DynamicListViewParams(empContactList[index].cONTACTNAME!, menuEntry!.functionName!, pContactRelationshipId: empContactList[index].cONTACTRELATIONSHIPID));
});
appBar: AppBarWidget(context, title: menuEntry?.prompt ?? ""),
body: empContactList.isNotEmpty
? ListView.separated(
physics: const BouncingScrollPhysics(),
padding: const EdgeInsets.all(21),
separatorBuilder: (BuildContext cxt, int index) => 12.height,
itemCount: empContactList.length,
itemBuilder: (BuildContext context, int index) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
"${empContactList[index].cONTACTNAME}".toText16(color: MyColors.grey3AColor),
"${LocaleKeys.dateOfBirth.tr()}: ${empContactList[index].dATEOFBIRTH?.split(" ").first ?? ""}".toText14(color: MyColors.grey3AColor, weight: FontWeight.w400),
"${empContactList[index].rELATIONSHIP}".toText11(color: MyColors.textMixColor),
],
).objectContainerView(disablePadding: false, center: false).onPress(() {
Navigator.pushNamed(context, AppRoutes.dynamicScreen,
arguments: DynamicListViewParams(empContactList[index].cONTACTNAME!, menuEntry!.functionName!, pContactRelationshipId: empContactList[index].cONTACTRELATIONSHIPID));
});
} else {
return LocaleKeys.noDataAvailable.tr().toText16().center;
}
},
),
})
: Utils.getNoDataWidget(context),
);
}
void getEmployeeContacts() async {
try {
Utils.showLoading(context);
empContactList = await ProfileApiClient().getEmployeeContacts();
Utils.hideLoading(context);
setState(() {});
} catch (ex) {
Utils.hideLoading(context);
Utils.handleException(ex, context, null);
}
}
}

@ -0,0 +1,333 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:mohem_flutter_app/app_state/app_state.dart';
import 'package:mohem_flutter_app/classes/colors.dart';
import 'package:mohem_flutter_app/classes/inAppWebView.dart';
import 'package:mohem_flutter_app/classes/utils.dart';
import 'package:mohem_flutter_app/extensions/int_extensions.dart';
import 'package:mohem_flutter_app/extensions/string_extensions.dart';
import 'package:mohem_flutter_app/extensions/widget_extensions.dart';
import 'package:mohem_flutter_app/generated/locale_keys.g.dart';
import 'package:mohem_flutter_app/models/dashboard/courses_response_model.dart';
import 'package:mohem_flutter_app/provider/dashboard_provider_model.dart';
import 'package:mohem_flutter_app/theme/colors.dart' as theme_colors;
import 'package:mohem_flutter_app/widgets/app_bar_widget.dart';
import 'package:mohem_flutter_app/widgets/sso_webview_widget.dart';
import 'package:provider/provider.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';
class CoursesScreen extends StatefulWidget {
const CoursesScreen({Key? key}) : super(key: key);
@override
_CoursesScreenState createState() => _CoursesScreenState();
}
class _CoursesScreenState extends State<CoursesScreen> {
late DashboardProviderModel data;
final RefreshController _refreshController = RefreshController(initialRefresh: false);
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
data = Provider.of<DashboardProviderModel>(context, listen: false);
_onRefresh();
});
}
void _onRefresh() async {
await data.fetchCourses(context);
_refreshController.refreshCompleted();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBarWidget(
context,
title: LocaleKeys.courses.tr(),
),
body: Consumer<DashboardProviderModel>(
builder: (context, provider, child) {
return SmartRefresher(
enablePullDown: true,
enablePullUp: false,
controller: _refreshController,
onRefresh: _onRefresh,
child: provider.isCoursesLoading
? _buildShimmerLoading()
: provider.coursesList.isEmpty
? _buildEmptyState()
: _buildCoursesList(provider.coursesList),
);
},
),
);
}
Widget _buildShimmerLoading() {
return ListView.builder(
padding: const EdgeInsets.all(21),
itemCount: 5,
itemBuilder: (context, index) {
return Container(
margin: const EdgeInsets.only(bottom: 12),
height: 150,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(15),
boxShadow: [
BoxShadow(
color: const Color(0xff000000).withOpacity(.05),
blurRadius: 26,
offset: const Offset(0, -3),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
height: 20,
width: 200,
decoration: BoxDecoration(
color: Colors.grey[300],
borderRadius: BorderRadius.circular(4),
),
).toShimmer(),
12.height,
Container(
height: 14,
width: 100,
decoration: BoxDecoration(
color: Colors.grey[300],
borderRadius: BorderRadius.circular(4),
),
).toShimmer(),
const Spacer(),
Container(
height: 40,
decoration: BoxDecoration(
color: Colors.grey[300],
borderRadius: BorderRadius.circular(6),
),
).toShimmer(),
],
).paddingAll(14),
);
},
);
}
Widget _buildEmptyState() {
return Utils.getNoDataWidget(context);
}
Widget _buildCoursesList(List<CourseStatus> courses) {
return ListView.separated(
physics: const BouncingScrollPhysics(),
shrinkWrap: true,
padding: const EdgeInsets.all(21),
itemBuilder: (BuildContext context, int index) {
return _buildCourseCard(courses[index]);
},
separatorBuilder: (BuildContext context, int index) => 12.height,
itemCount: courses.length,
);
}
Widget _buildCourseCard(CourseStatus course) {
bool isArabic = AppState().isArabic(context);
String courseName = isArabic && course.cNameAr != null && course.cNameAr!.isNotEmpty
? course.cNameAr!
: course.cFullname ?? '';
String status = course.cStatus ?? 'Unknown';
Color statusColor = _getStatusColor(status);
return InkWell(
onTap: () => _openCourse(course.cUrl, course.token),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Course Title
Row(
children: [
Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: MyColors.lightGreyEFColor,
borderRadius: BorderRadius.circular(8),
),
child: const Icon(
Icons.school_rounded,
color: MyColors.gradiantStartColor,
size: 20,
),
),
12.width,
Expanded(
child: courseName.toText14(isBold: true, color: MyColors.darkTextColor),
),
],
),
12.height,
// Status Badge
Row(
children: [
Icon(
_getStatusIcon(status),
size: 16,
color: statusColor,
),
6.width,
LocaleKeys.status.tr().toText11(color: MyColors.grey98Color),
8.width,
Container(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
decoration: BoxDecoration(
color: statusColor.withOpacity(0.1),
borderRadius: BorderRadius.circular(12),
border: Border.all(
color: statusColor.withOpacity(0.3),
width: 1,
),
),
child: status.toText10(color: statusColor, isBold: true),
),
],
),
10.height,
// Start Date
if (course.cEnddate != null && course.cEnddate!.isNotEmpty)
Row(
children: [
const Icon(
Icons.calendar_month_rounded,
size: 16,
color: MyColors.darkIconColor,
),
6.width,
LocaleKeys.endDateT.tr().toText11(color: MyColors.grey98Color),
8.width,
Expanded(
child: _formatDate(course.cEnddate!).toText11(
color: MyColors.darkTextColor,
isBold: true,
),
),
],
),
if (course.cStartdate != null && course.cStartdate!.isNotEmpty) 14.height,
// Open Button
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
LocaleKeys.open.tr().toText12(color: MyColors.gradiantStartColor, isUnderLine: true),
6.width,
RotatedBox(
quarterTurns: AppState().isArabic(context) ? 2 : 4,
child: SvgPicture.asset(
"assets/images/arrow_next.svg",
color: MyColors.gradiantStartColor,
width: 16,
height: 16,
),
),
],
),
],
).objectContainerView(),
);
}
IconData _getStatusIcon(String status) {
if (status.toLowerCase().contains('passed')) {
return Icons.check_circle_rounded;
} else if (status.toLowerCase().contains('not passed') || status.toLowerCase().contains('failed')) {
return Icons.cancel_rounded;
} else if (status.toLowerCase().contains('in progress')) {
return Icons.pending_rounded;
} else {
return Icons.info_rounded;
}
}
Color _getStatusColor(String status) {
if (status.toLowerCase().contains('passed') && !status.toLowerCase().contains('not passed')) {
return Colors.green;
} else if (status.toLowerCase().contains('not passed') || status.toLowerCase().contains('failed')) {
return Colors.red;
} else if (status.toLowerCase().contains('in progress')) {
return Colors.yellow[700]!;
} else {
return MyColors.grey98Color;
}
}
DateTime? _parseDate(String? date) {
if (date == null || date.isEmpty) return null;
try {
return DateTime.parse(date.replaceAll(' ', 'T'));
} catch (e) {
try {
DateFormat format = DateFormat('yyyy-MM-dd HH:mm:ss');
return format.parse(date);
} catch (e) {
return null;
}
}
}
String _formatDate(String date) {
DateTime? dateTime = _parseDate(date);
if (dateTime == null) return date;
bool isArabic = AppState().isArabic(context);
DateFormat format = DateFormat('dd MMM yyyy, hh:mm a', isArabic ? 'ar' : 'en');
return format.format(dateTime);
}
void _openCourse(String? url, String? jwtToken) {
Navigator.push(context, MaterialPageRoute(builder: (BuildContext context) => SsoLoginWebView(url: url, jwtToken: jwtToken, ssoType: SsoType.forCourses)));
//Utils.showToast(LocaleKeys.courseUrlNotAvailable.tr());
// return;
// }
//
// MyInAppBrowser browser = MyInAppBrowser(
// onExitCallback: () {},
// onLoadStartCallback: (String url) {},
// );
//
// var settings = InAppBrowserClassSettings(
// webViewSettings: InAppWebViewSettings(
// useShouldOverrideUrlLoading: false,
// transparentBackground: false,
// ),
// browserSettings: InAppBrowserSettings(
// hideUrlBar: true,
// hideTitleBar: false,
// toolbarTopBackgroundColor: theme_colors.primaryColor,
// ),
// );
//
// browser.openUrlRequest(
// urlRequest: URLRequest(url: WebUri(url)),
// settings: settings,
// );
}
@override
void dispose() {
_refreshController.dispose();
super.dispose();
}
}

@ -150,7 +150,9 @@ class _MowadhafhiHRRequestState extends State<MowadhafhiHRRequest> {
isReadOnly: false,
onChange: (String value) {
debugPrint(value);
description = value;
setState(() {
description = value;
});
},
),
],
@ -171,7 +173,7 @@ class _MowadhafhiHRRequestState extends State<MowadhafhiHRRequest> {
}
bool checkValidation() {
if (selectedServiceType == null || selectedDepartment == null || selectedSection == null || selectedTopic == null) {
if (selectedServiceType == null || selectedDepartment == null || selectedSection == null || selectedTopic == null || description == "") {
return false;
} else {
return true;
@ -190,10 +192,78 @@ class _MowadhafhiHRRequestState extends State<MowadhafhiHRRequest> {
title.toText16().expanded,
6.width,
SimpleButton(LocaleKeys.add.tr(), () async {
FilePickerResult? result = await FilePicker.platform.pickFiles(allowMultiple: true);
FilePickerResult? result = await FilePicker.platform.pickFiles(
allowMultiple: true,
);
if (result != null) {
attachmentFiles = attachmentFiles + result.paths.map((path) => File(path!)).toList();
attachmentFiles = attachmentFiles.toSet().toList();
// Maximum file size: 2 MB (in bytes)
const int maxFileSizeInBytes = 2 * 1024 * 1024; // 2 MB = 2097152 bytes
List<File> newFiles = [];
List<String> oversizedFiles = [];
for (PlatformFile platformFile in result.files) {
if (platformFile.path != null) {
File file = File(platformFile.path!);
// Get file size - check multiple sources for iOS compatibility
int fileSize = 0;
// Method 1: Check platformFile.size first
if (platformFile.size > 0) {
fileSize = platformFile.size;
debugPrint('Using platformFile.size: $fileSize bytes');
}
// Method 2: Always verify with file.length() as well
try {
int fileLengthSize = await file.length();
debugPrint('Using file.length(): $fileLengthSize bytes');
// Use the maximum of both to ensure we catch the real size
if (fileLengthSize > fileSize) {
fileSize = fileLengthSize;
debugPrint('Using larger value from file.length()');
}
} catch (e) {
debugPrint('Error getting file.length(): $e');
// If file.length() fails, rely on platformFile.size
if (fileSize == 0) {
debugPrint('Cannot determine file size, rejecting file: ${platformFile.name}');
oversizedFiles.add('${platformFile.name} (unknown size)');
continue;
}
}
double fileSizeMB = fileSize / (1024 * 1024);
debugPrint('Final file size - ${platformFile.name}: $fileSize bytes (${fileSizeMB.toStringAsFixed(2)} MB)');
// STRICT validation: Only accept files that are 2 MB or less
if (fileSize > 0 && fileSize <= maxFileSizeInBytes) {
debugPrint('✓ File accepted: ${platformFile.name}');
newFiles.add(file);
} else if (fileSize > maxFileSizeInBytes) {
debugPrint('✗ File REJECTED (too large): ${platformFile.name} - ${fileSizeMB.toStringAsFixed(2)} MB');
oversizedFiles.add('${platformFile.name} (${fileSizeMB.toStringAsFixed(2)} MB)');
} else {
debugPrint('✗ File REJECTED (invalid size): ${platformFile.name}');
oversizedFiles.add('${platformFile.name} (invalid)');
}
}
}
// Only add valid files
if (newFiles.isNotEmpty) {
attachmentFiles = attachmentFiles + newFiles;
attachmentFiles = attachmentFiles.toSet().toList();
debugPrint('Total files attached: ${attachmentFiles.length}');
}
// Show error message for rejected files
if (oversizedFiles.isNotEmpty) {
String fileList = oversizedFiles.join('\n');
Utils.showToast('Max 2MB File allowed.');
debugPrint('Total rejected files: ${oversizedFiles.length}');
}
setState(() {});
}
}, fontSize: 14),

@ -5,14 +5,17 @@ import 'package:flutter/material.dart';
import 'package:mohem_flutter_app/app_state/app_state.dart';
import 'package:mohem_flutter_app/classes/colors.dart';
import 'package:mohem_flutter_app/classes/date_uitl.dart';
import 'package:mohem_flutter_app/classes/file_process.dart';
import 'package:mohem_flutter_app/classes/utils.dart';
import 'package:mohem_flutter_app/extensions/int_extensions.dart';
import 'package:mohem_flutter_app/extensions/string_extensions.dart';
import 'package:mohem_flutter_app/extensions/widget_extensions.dart';
import 'package:mohem_flutter_app/generated/locale_keys.g.dart';
import 'package:mohem_flutter_app/models/dashboard/get_accural_ticket_balance_model.dart';
import 'package:mohem_flutter_app/models/eit/get_eit_transaction_model.dart';
import 'package:mohem_flutter_app/models/eit_attachment_ticket_model.dart';
import 'package:mohem_flutter_app/provider/dashboard_provider_model.dart';
import 'package:mohem_flutter_app/widgets/app_bar_widget.dart';
import 'package:mohem_flutter_app/widgets/balances_dashboard_widget.dart';
import 'package:mohem_flutter_app/widgets/button/default_button.dart';
import 'package:mohem_flutter_app/widgets/item_detail_view_widget.dart';
import 'package:mohem_flutter_app/widgets/sso_webview_widget.dart';
@ -55,26 +58,27 @@ class _TicketDetailedScreenState extends State<TicketDetailedScreen> {
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBarWidget(context, title: "Ticket Details"),
appBar: AppBarWidget(context, title: LocaleKeys.ticketDetails.tr()),
body: Column(
children: <Widget>[
ListView(
padding: const EdgeInsets.all(21),
physics: const BouncingScrollPhysics(),
children: <Widget>[
if (dashboardProviderModel == null && dashboardProviderModel?.accrualTicketBalanceList == null) ...<Widget>[Utils.getNoDataWidget(context).paddingOnly(top: 50)] else ...<Widget>[
Container(
padding: const EdgeInsets.all(16.0),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12.0),
boxShadow: <BoxShadow>[BoxShadow(color: Colors.grey.withOpacity(0.2), spreadRadius: 2, blurRadius: 5, offset: const Offset(0, 3))],
),
child: Column(
children: <Widget>[
Row(
children: <Widget>[
"Current Ticket Balance".toText20().expanded,
Expanded(
child: ListView(
padding: const EdgeInsets.all(21),
physics: const BouncingScrollPhysics(),
children: <Widget>[
if (dashboardProviderModel == null && dashboardProviderModel?.accrualTicketBalanceList == null) ...<Widget>[Utils.getNoDataWidget(context).paddingOnly(top: 50)] else ...<Widget>[
Container(
padding: const EdgeInsets.all(16.0),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12.0),
boxShadow: <BoxShadow>[BoxShadow(color: Colors.grey.withOpacity(0.2), spreadRadius: 2, blurRadius: 5, offset: const Offset(0, 3))],
),
child: Column(
children: <Widget>[
Row(
children: <Widget>[
Expanded(child: LocaleKeys.currentTicketBalance.tr().toText20()),
Row(
children: <Widget>[
const Icon(Icons.calendar_month_rounded, color: MyColors.darkIconColor, size: 16),
@ -112,21 +116,19 @@ class _TicketDetailedScreenState extends State<TicketDetailedScreen> {
),
),
const SizedBox(height: 21),
dashboardProviderModel == null && dashboardProviderModel!.ticketHistoryTransactionList == null
? const SizedBox()
: ListView(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
(dashboardProviderModel != null && dashboardProviderModel!.ticketHistoryTransactionList != null && dashboardProviderModel!.ticketHistoryTransactionList!.isNotEmpty)
? Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
"Tickets History".toText20().expanded,
LocaleKeys.ticketHistory.tr().toText20(),
12.height,
ListView.separated(
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
padding: EdgeInsets.zero,
itemBuilder: (BuildContext cxt, int cardIndex) {
var transactionDetails = dashboardProviderModel!.ticketHistoryTransactionList![cardIndex];
const allowedSegmentNames = <String>{
List<CollectionTransaction> transactionDetails = dashboardProviderModel!.ticketHistoryTransactionList![cardIndex];
const Set<String> allowedSegmentNames = <String>{
"TICKETS_ROUTE",
"TRAVELER_NAME",
"TICKETS_EFFECTIVE_DATE",
@ -135,11 +137,22 @@ class _TicketDetailedScreenState extends State<TicketDetailedScreen> {
"TICKET_COMP_SHARE",
"TICKET_EMP_SHARE",
};
var uniqueDetails =
// Get items for display
List<CollectionTransaction> uniqueDetails =
transactionDetails
.where((item) => item.dISPLAYFLAG != 'N' && item.sEGMENTPROMPT != null && item.sEGMENTPROMPT!.isNotEmpty && allowedSegmentNames.contains(item.sEGMENTNAME))
.where(
(CollectionTransaction item) =>
item.dISPLAYFLAG != 'N' && item.sEGMENTPROMPT != null && item.sEGMENTPROMPT!.isNotEmpty && allowedSegmentNames.contains(item.sEGMENTNAME),
)
.toList();
// Get PEI_EXTRA_INFO_ID value for View PDF
CollectionTransaction? peiExtraInfoItem = transactionDetails.firstWhere(
(CollectionTransaction item) => item.aPPLICATIONCOLUMNNAME == "PEI_EXTRA_INFO_ID",
orElse: () => CollectionTransaction(),
);
num? peiExtraInfoId = peiExtraInfoItem.nUMBERVALUE;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
@ -148,15 +161,15 @@ class _TicketDetailedScreenState extends State<TicketDetailedScreen> {
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: (uniqueDetails.length / 2).ceil(),
itemBuilder: (context, rowIndex) {
itemBuilder: (BuildContext context, int rowIndex) {
int firstIndex = rowIndex * 2;
int? secondIndex = (firstIndex + 1 < uniqueDetails.length) ? firstIndex + 1 : null;
bool isLastRow = (rowIndex == (uniqueDetails.length / 2).ceil() - 1);
var item1 = uniqueDetails[firstIndex];
var child1 = ItemDetailViewCol(item1.sEGMENTPROMPT!, item1.vARCHAR2VALUE ?? item1.nUMBERVALUE?.toString() ?? "");
CollectionTransaction item1 = uniqueDetails[firstIndex];
ItemDetailViewCol child1 = ItemDetailViewCol(item1.sEGMENTPROMPT!, item1.vARCHAR2VALUE ?? item1.nUMBERVALUE?.toString() ?? "");
Widget child2;
if (secondIndex != null) {
var item2 = uniqueDetails[secondIndex];
CollectionTransaction item2 = uniqueDetails[secondIndex];
child2 = ItemDetailViewCol(item2.sEGMENTPROMPT!, item2.vARCHAR2VALUE ?? item2.nUMBERVALUE?.toString() ?? "");
} else {
child2 = const SizedBox(); // Empty widget if there is no second item
@ -164,6 +177,40 @@ class _TicketDetailedScreenState extends State<TicketDetailedScreen> {
return ItemDetailGrid(child1, child2, isItLast: isLastRow);
},
),
// View PDF link at the bottom
if (peiExtraInfoId != null) ...[
const SizedBox(height: 5),
Align(
alignment: Alignment.centerRight,
child: GestureDetector(
onTap: () async {
Utils.showLoading(context);
try {
GetEitAttachmentTicket? result = await dashboardProviderModel!.getTicketEitPDFDownload(peiExtraInfoId: peiExtraInfoId.toString());
if (result != null && result.getEitAttachmentList != null && result.getEitAttachmentList!.isNotEmpty) {
String? base64Data = result.getEitAttachmentList!.first.fileData;
if (base64Data != null && base64Data.isNotEmpty) {
String fileName = result.getEitAttachmentList!.first.fileName!;
await FileProcess.downloadFile(base64Data, fileName);
Utils.hideLoading(context);
FileProcess.openFile(fileName);
} else {
Utils.hideLoading(context);
Utils.showToast("PDF data not available");
}
} else {
Utils.hideLoading(context);
Utils.showToast("No attachment found");
}
} catch (e) {
Utils.hideLoading(context);
Utils.showToast("Something Went Wrong");
}
},
child: Padding(padding: const EdgeInsets.only(top: 8.0, left: 0.0, bottom: 8.0), child: "View PDF".toText14(isUnderLine: true, isBold: true)),
),
),
],
],
).objectContainerView();
},
@ -171,13 +218,15 @@ class _TicketDetailedScreenState extends State<TicketDetailedScreen> {
itemCount: dashboardProviderModel!.ticketHistoryTransactionList!.length,
),
],
),
)
: const SizedBox(),
],
],
],
).expanded,
DefaultButton("Proceed For Booking", () {
),
),
DefaultButton(LocaleKeys.proceedBooking.tr(), () {
if (widget.url != null && widget.jwtToken != null) {
Navigator.push(context, MaterialPageRoute(builder: (BuildContext context) => SsoLoginWebView(url: widget.url, jwtToken: widget.jwtToken)));
Navigator.push(context, MaterialPageRoute(builder: (BuildContext context) => SsoLoginWebView(url: widget.url, jwtToken: widget.jwtToken, ssoType: SsoType.forTicket)));
}
}).insideContainer,
],

@ -21,7 +21,11 @@ class ApprovalLevelfragment extends StatelessWidget {
@override
Widget build(BuildContext context) {
if (wFHistory.isNotEmpty) wFHistory = wFHistory.reversed.toList();
if (wFHistory.isNotEmpty) {
//TODO: This COde is Written For Future. If Needed Enable to Filter The Empty Action Requests.
// wFHistory = wFHistory.where((item) => item.action != null && item.action!.isNotEmpty).toList();
wFHistory = wFHistory.reversed.toList();
}
return Container(
width: double.infinity,
height: double.infinity,
@ -79,7 +83,8 @@ class ApprovalLevelfragment extends StatelessWidget {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
history.name!.toText16(),
(history.name ?? history.approvalLevel ?? "").toText16(),
// history.name!.toText16(),
if ((history.notes ?? "").isNotEmpty) history.notes!.toText12(color: MyColors.grey57Color),
4.height,
Row(
@ -164,8 +169,8 @@ class ApprovalLevelfragment extends StatelessWidget {
if (wFHistory[index].date!.isEmpty || wFHistory[index].action!.toLowerCase() == "NO ACTION" || wFHistory[index + 1].date! == "") {
return "";
} else {
DateTime dateTimeTo = DateUtil.convertSimpleStringDateToDate(wFHistory[index].date!);
DateTime dateTimeFrom = DateUtil.convertSimpleStringDateToDate(wFHistory[index + 1].date!);
DateTime dateTimeTo = DateUtil.convertSimpleStringDateToDate(wFHistory[index].date!, isITG: true);
DateTime dateTimeFrom = DateUtil.convertSimpleStringDateToDate(wFHistory[index + 1].date!, isITG: true);
Duration duration = dateTimeTo.difference(dateTimeFrom);
return "Action duration: " + DateUtil.formatDuration(duration);
}

@ -5,6 +5,7 @@ import 'package:flutter_svg/svg.dart';
import 'package:mohem_flutter_app/api/worklist/worklist_api_client.dart';
import 'package:mohem_flutter_app/app_state/app_state.dart';
import 'package:mohem_flutter_app/classes/colors.dart';
import 'package:mohem_flutter_app/classes/consts.dart';
import 'package:mohem_flutter_app/classes/date_uitl.dart';
import 'package:mohem_flutter_app/classes/utils.dart';
import 'package:mohem_flutter_app/config/routes.dart';
@ -21,6 +22,8 @@ import 'package:mohem_flutter_app/provider/dashboard_provider_model.dart';
import 'package:mohem_flutter_app/widgets/app_bar_widget.dart';
import 'package:mohem_flutter_app/widgets/bottom_sheet.dart';
import 'package:mohem_flutter_app/widgets/bottom_sheets/worklist_advance_search_bottom_sheet.dart';
import 'package:mohem_flutter_app/widgets/dynamic_forms/dynamic_textfield_widget.dart';
import 'package:mohem_flutter_app/widgets/sso_webview_widget.dart';
import 'package:provider/provider.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';
@ -107,13 +110,13 @@ class _WorkListScreenState extends State<WorkListScreen> {
),
WorkListItemTypeModelData(
value: 0,
name: 'COC',
name: 'ENSAT',
fullName: LocaleKeys.itemCreation.tr(),
active: false,
color: [Color(0xff787299), Color(0xff1AB170)],
color: [const Color(0xff787299), Color(0xff1AB170)],
icon: "assets/images/miss_swipe.svg",
key: 'COC',
disable: true,
disable: false,
),
WorkListItemTypeModelData(
value: 0,
@ -135,7 +138,6 @@ class _WorkListScreenState extends State<WorkListScreen> {
key: 'HMG_FA_D',
disable: false,
),
];
int? workListItemIndex;
@ -150,6 +152,7 @@ class _WorkListScreenState extends State<WorkListScreen> {
final ScrollController _controller = ScrollController();
int pNotificationType = 1;
String prPoFilterText = "";
ScrollController? _scrollController;
@override
@ -231,6 +234,12 @@ class _WorkListScreenState extends State<WorkListScreen> {
if ((itgFormsModel?.requestType?.length ?? 0) > 0) {
itgRequestTypeIndex = 0;
}
} else if (workListItemTypes[workListItemIndex!].key == "COC") {
String? enSAToken = await DashboardProviderModel().getENSATItgToken();
Utils.hideLoading(context);
dynamic url = "${ApiConsts.enSATLiveURL}?empId=${AppState().getUserName}&token=$enSAToken";
Navigator.push(context, MaterialPageRoute(builder: (BuildContext context) => SsoLoginWebView(url: url, jwtToken: enSAToken, ssoType: SsoType.forEnsat)));
} else {
itgRequestTypeIndex = null;
List<WorkListResponseModel>? _list = await WorkListApiClient().getWorkList(pageNumber, workListItemTypes[workListItemIndex!].key, pNotificationType.toString());
@ -311,6 +320,7 @@ class _WorkListScreenState extends State<WorkListScreen> {
}
if (workListItemIndex != index && !workListItemTypes[index].disable) {
workListItemIndex = index;
prPoFilterText = "";
pageNumber = 1;
if (workListItemTypes[index].value == 0) {
workList = [];
@ -345,6 +355,20 @@ class _WorkListScreenState extends State<WorkListScreen> {
.paddingOnly(left: 21, right: 21),
],
),
if (_isPrOrPoSelected())
DynamicTextFieldWidget(
"",
_getPrPoFilterHint(),
isEnable: true,
isPopup: false,
lines: 1,
isInputTypeNum: false,
isReadOnly: false,
onChange: (String value) {
prPoFilterText = value;
setState(() {});
},
).paddingOnly(left: 21, right: 21, top: 10),
SmartRefresher(
enablePullDown: true,
enablePullUp: false,
@ -397,16 +421,16 @@ class _WorkListScreenState extends State<WorkListScreen> {
],
)
: workList != null
? ((workList!).isEmpty
? ((_getDisplayedWorkList()).isEmpty
? Utils.getNoDataWidget(context).paddingOnly(top: 100)
: ListView.separated(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemBuilder: (context, index) {
return rowItem(workListItemTypes[workListItemIndex!], workList![index], index);
return rowItem(workListItemTypes[workListItemIndex!], _getDisplayedWorkList()[index], index);
},
separatorBuilder: (context, index) => 12.height,
itemCount: workList?.length ?? 0,
itemCount: _getDisplayedWorkList().length,
padding: const EdgeInsets.all(21),
))
: const SizedBox(),
@ -500,7 +524,7 @@ class _WorkListScreenState extends State<WorkListScreen> {
}
}
Utils.showLoading(context);
workList = await WorkListApiClient().getWorkList(
List<WorkListResponseModel>? responseList = await WorkListApiClient().getWorkList(
pageNumber,
selectedItemTypeID,
selectedViewID.toString(),
@ -509,6 +533,8 @@ class _WorkListScreenState extends State<WorkListScreen> {
pSentDate: searchByDate,
pSearchItemType: searchByInput,
);
workList = responseList;
prPoFilterText = "";
workListItemIndex = index;
AppState().setWorkList = workList;
Utils.hideLoading(context);
@ -518,11 +544,35 @@ class _WorkListScreenState extends State<WorkListScreen> {
);
}
bool _isPrOrPoSelected() {
if (workListItemIndex == null) return false;
String key = workListItemTypes[workListItemIndex!].key ?? "";
return key == "REQAPPRV" || key == "POAPPRV";
}
List<WorkListResponseModel> _getDisplayedWorkList() {
List<WorkListResponseModel> source = workList ?? [];
if (!_isPrOrPoSelected()) return source;
String query = prPoFilterText.trim().toLowerCase();
if (query.isEmpty) return source;
return source.where((item) => (item.sUBJECT ?? "").toLowerCase().contains(query)).toList();
}
String _getPrPoFilterHint() {
if (workListItemIndex == null) return "filterEnterPrDetailsHere".tr();
String key = workListItemTypes[workListItemIndex!].key;
if (key == "POAPPRV") {
return "filterEnterPoDetailsHere".tr();
}
return "filterEnterPrDetailsHere".tr();
}
Widget rowItem(WorkListItemTypeModelData data, WorkListResponseModel workData, int index) {
return InkWell(
onTap: () async {
AppState().setWorkListIndex = index;
var data = workList![index];
var data = workData;
var shouldReloadData = await Navigator.pushNamed(context, AppRoutes.workListDetail, arguments: workData);
if (shouldReloadData != null) {
if (shouldReloadData.toString() == "delegate_reload") {
@ -535,7 +585,7 @@ class _WorkListScreenState extends State<WorkListScreen> {
setState(() {});
}
} else {
workList!.remove(data);
workList!.removeWhere((item) => item.nOTIFICATIONID == data.nOTIFICATIONID);
AppState().setWorkList = workList;
if (data.iTEMTYPE == "ITG") {
} else {

@ -602,6 +602,7 @@ class InfoFragment extends StatelessWidget {
ItemDetailViewCol(
LocaleKeys.responder.tr(), workListData!.rESPONDER ?? ""),
),
Column(
children: getPRHeaderValues(),
)

@ -13,7 +13,8 @@ import 'package:mohem_flutter_app/models/get_item_creation_ntf_body_list_model.d
import 'package:mohem_flutter_app/models/get_mo_notification_body_list_model.dart';
import 'package:mohem_flutter_app/models/get_po_notification_body_list_model.dart';
import 'package:mohem_flutter_app/models/get_pr_information_list.dart';
import 'package:mohem_flutter_app/models/get_pr_notification_body_list_model.dart' as get_pr_notification_body_list_model;
import 'package:mohem_flutter_app/models/get_pr_notification_body_list_model.dart'
as get_pr_notification_body_list_model;
import 'package:mohem_flutter_app/ui/work_list/item_history_screen.dart';
import 'package:mohem_flutter_app/widgets/button/default_button.dart';
import 'package:mohem_flutter_app/widgets/item_detail_view_widget.dart';
@ -51,250 +52,465 @@ class RequestFragment extends StatelessWidget {
Widget poLinesDataView(BuildContext context) {
return ExpandableNotifier(
child: ListView.separated(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemBuilder: (cxt, index) => ExpandablePanel(
header: poLinesList[index].iTEMDESCRIPTION!.toText14(),
collapsed: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
ItemDetailGrid(
ItemDetailViewCol(LocaleKeys.code.tr(), poLinesList[index].iTEMCODE ?? ""),
ItemDetailViewCol(LocaleKeys.mfg.tr(), poLinesList[index].mFG ?? ""),
),
ItemDetailGrid(
ItemDetailViewCol(LocaleKeys.lineType.tr(), poLinesList[index].lINETYPE?.toString() ?? ""),
ItemDetailViewCol(LocaleKeys.unit.tr(), poLinesList[index].uOM ?? ""),
),
ItemDetailGrid(
ItemDetailViewCol(LocaleKeys.price.tr(), poLinesList[index].uNITPRICE?.toString() ?? ""),
ItemDetailViewCol(LocaleKeys.lineAmount.tr(), poLinesList[index].lINEAMOUNT?.toString() ?? ""),
),
ItemDetailGrid(
ItemDetailViewCol(LocaleKeys.quantity.tr(), poLinesList[index].qUANTITY?.toString() ?? ""),
ItemDetailViewCol(LocaleKeys.lineDiscount.tr(), poLinesList[index].lINEDISCPERCENTAGE?.toString() ?? ""),
),
ItemDetailGrid(
ItemDetailViewCol(LocaleKeys.needByDate.tr(), poLinesList[index].nEEDBYDATE ?? ""),
ItemDetailViewCol(LocaleKeys.promisedDate.tr(), poLinesList[index].pROMISEDDATE ?? ""),
),
ItemDetailGrid(
ItemDetailViewCol(LocaleKeys.deliverToLocation.tr(), poLinesList[index].dELIVERTOLOCATION ?? ""),
ItemDetailViewCol(LocaleKeys.requisitionNumber.tr(), poLinesList[index].pRNUM ?? ""),
),
ItemDetailGrid(
ItemDetailViewCol(LocaleKeys.requester.tr(), poLinesList[index].rEQUESTOR ?? ""),
Container(),
),
12.height,
Row(
children: [
DefaultButton(
LocaleKeys.itemHistory.tr(),
() {
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemBuilder:
(cxt, index) =>
ExpandablePanel(
header: poLinesList[index].iTEMDESCRIPTION!.toText14(),
collapsed: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
ItemDetailGrid(
ItemDetailViewCol(
LocaleKeys.code.tr(),
poLinesList[index].iTEMCODE ?? "",
),
ItemDetailViewCol(
LocaleKeys.mfg.tr(),
poLinesList[index].mFG ?? "",
),
),
ItemDetailGrid(
ItemDetailViewCol(
LocaleKeys.lineType.tr(),
poLinesList[index].lINETYPE?.toString() ?? "",
),
ItemDetailViewCol(
LocaleKeys.unit.tr(),
poLinesList[index].uOM ?? "",
),
),
ItemDetailGrid(
ItemDetailViewCol(
LocaleKeys.price.tr(),
poLinesList[index].uNITPRICE?.toString() ?? "",
),
ItemDetailViewCol(
LocaleKeys.lineAmount.tr(),
poLinesList[index].lINEAMOUNT?.toString() ?? "",
),
),
ItemDetailGrid(
ItemDetailViewCol(
LocaleKeys.quantity.tr(),
poLinesList[index].qUANTITY?.toString() ?? "",
),
ItemDetailViewCol(
LocaleKeys.lineDiscount.tr(),
poLinesList[index].lINEDISCPERCENTAGE?.toString() ??
"",
),
),
ItemDetailGrid(
ItemDetailViewCol(
LocaleKeys.needByDate.tr(),
poLinesList[index].nEEDBYDATE ?? "",
),
ItemDetailViewCol(
LocaleKeys.promisedDate.tr(),
poLinesList[index].pROMISEDDATE ?? "",
),
),
ItemDetailGrid(
ItemDetailViewCol(
LocaleKeys.deliverToLocation.tr(),
poLinesList[index].dELIVERTOLOCATION ?? "",
),
ItemDetailViewCol(
LocaleKeys.requisitionNumber.tr(),
poLinesList[index].pRNUM ?? "",
),
),
ItemDetailGrid(
ItemDetailViewCol(
LocaleKeys.requester.tr(),
poLinesList[index].rEQUESTOR ?? "",
),
Container(),
),
12.height,
Row(
children: [
DefaultButton(LocaleKeys.itemHistory.tr(), () {
Navigator.pushNamed(
cxt,
AppRoutes.itemHistory,
arguments: ItemHistoryScreenParams(title: LocaleKeys.itemHistory.tr(), isMO: false, pItemId: poLinesList[index].iTEMID),
arguments: ItemHistoryScreenParams(
title: LocaleKeys.itemHistory.tr(),
isMO: false,
pItemId: poLinesList[index].iTEMID,
),
);
},
fontSize: 13,
).expanded,
12.width,
DefaultButton(
LocaleKeys.quotationAnalysis.tr(),
() {
}, fontSize: 13).expanded,
12.width,
DefaultButton(LocaleKeys.quotationAnalysis.tr(), () {
Navigator.pushNamed(
cxt,
AppRoutes.itemHistory,
arguments: ItemHistoryScreenParams(
isItemHistory: false, isMO: false, title: LocaleKeys.quotationAnalysis.tr(), pItemId: poLinesList[index].iTEMID, pPoHeaderId: poLinesList[index].pOHEADERID),
isItemHistory: false,
isMO: false,
title: LocaleKeys.quotationAnalysis.tr(),
pItemId: poLinesList[index].iTEMID,
pPoHeaderId: poLinesList[index].pOHEADERID,
),
);
}, fontSize: 13).expanded,
12.width,
DefaultButton("PR Details", () {
getPRDetails(
context,
poLinesList[index].pOLINEID.toString(),
);
},
fontSize: 13,
).expanded,
12.width,
DefaultButton(
"PR Details",
() {
getPRDetails(context, poLinesList[index].pOLINEID.toString());
},
fontSize: 13,
).expanded,
],
)
],
),
expanded: const SizedBox(),
).objectContainerView(),
separatorBuilder: (cxt, index) => 12.height,
itemCount: poLinesList.length),
}, fontSize: 13).expanded,
],
),
],
),
expanded: const SizedBox(),
).objectContainerView(),
separatorBuilder: (cxt, index) => 12.height,
itemCount: poLinesList.length,
),
);
}
Widget prLinesDataView() {
return ExpandableNotifier(
child: ListView.separated(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemBuilder: (cxt, index) => ExpandablePanel(
header: prLinesList[index].dESCRIPTION.toString().toText14(color: MyColors.textMixColor),
collapsed: Column(
children: [
ItemDetailGrid(
ItemDetailViewCol("Cost Center", prLinesList[index].cOSTCENTER ?? ""),
ItemDetailViewCol("Code", prLinesList[index].iTEMCODE ?? ""),
),
ItemDetailGrid(
ItemDetailViewCol("Unit", prLinesList[index].uOM ?? ""),
ItemDetailViewCol("Price (SAR)", prLinesList[index].uNITPRICE.toString() ?? ""),
),
ItemDetailGrid(
ItemDetailViewCol("Amount (SAR)", prLinesList[index].lINEAMOUNT.toString() ?? ""),
ItemDetailViewCol("Quantity", prLinesList[index].qUANTITY.toString() ?? ""),
),
ItemDetailGrid(
ItemDetailViewCol("AMU (Last 3 months)", prLinesList[index].iTEMAMU.toString() ?? ""),
Container(),
isItLast: true,
),
// ItemDetailGrid(
// ItemDetailViewCol(getPrNotificationBodyList.pRHeader![1].hDRATTRIBUTENAME!, getPrNotificationBodyList.pRHeader![1].hDRATTRIBUTEVALUE ?? ""),
// Container(),
// isItLast: true,
// ),
],
),
expanded: const SizedBox(),
).objectContainerView(),
separatorBuilder: (cxt, index) => 12.height,
itemCount: prLinesList.length),
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemBuilder:
(cxt, index) =>
ExpandablePanel(
header: prLinesList[index].dESCRIPTION.toString().toText14(
color: MyColors.textMixColor,
),
collapsed: Column(
children: [
ItemDetailGrid(
ItemDetailViewCol(
LocaleKeys.costCenter.tr(),
prLinesList[index].cOSTCENTER ?? "",
),
ItemDetailViewCol(
LocaleKeys.code.tr(),
prLinesList[index].iTEMCODE ?? "",
),
),
ItemDetailGrid(
ItemDetailViewCol(
LocaleKeys.unit.tr(),
prLinesList[index].uOM ?? "",
),
ItemDetailViewCol(
LocaleKeys.priceSAR.tr(),
prLinesList[index].uNITPRICE.toString() ?? "",
),
),
ItemDetailGrid(
ItemDetailViewCol(
LocaleKeys.amountSAR.tr(),
prLinesList[index].lINEAMOUNT.toString() ?? "",
),
ItemDetailViewCol(
LocaleKeys.quantity.tr(),
prLinesList[index].qUANTITY.toString() ?? "",
),
),
ItemDetailGrid(
ItemDetailViewCol(
LocaleKeys.destination_type.tr(),
prLinesList[index].dESTINATIONTYPE ?? "",
),
ItemDetailViewCol(
LocaleKeys.destination_organization_name.tr(),
prLinesList[index].dESTINATIONORGANIZATIONNAME ?? "",
),
),
ItemDetailGrid(
ItemDetailViewCol(
LocaleKeys.amuLastThreeMonths.tr(),
prLinesList[index].iTEMAMU.toString() ?? "",
),
Container(),
isItLast: true,
),
// ItemDetailGrid(
// ItemDetailViewCol(getPrNotificationBodyList.pRHeader![1].hDRATTRIBUTENAME!, getPrNotificationBodyList.pRHeader![1].hDRATTRIBUTEVALUE ?? ""),
// Container(),
// isItLast: true,
// ),
],
),
expanded: const SizedBox(),
).objectContainerView(),
separatorBuilder: (cxt, index) => 12.height,
itemCount: prLinesList.length,
),
);
}
Widget moNotificationDataView() {
return ListView.separated(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemBuilder: (cxt, index) => Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
ItemDetailGrid(
ItemDetailViewCol(LocaleKeys.code.tr(), moNotificationBodyList[index].iTEMCODE ?? ""),
ItemDetailViewCol(LocaleKeys.unit.tr(), moNotificationBodyList[index].uOM ?? ""),
),
ItemDetailGrid(
ItemDetailViewCol(LocaleKeys.quantity.tr(), moNotificationBodyList[index].qUANTITY?.toString() ?? ""),
ItemDetailViewCol(LocaleKeys.dateRequired.tr(), moNotificationBodyList[index].dATEREQUIRED ?? ""),
),
ItemDetailGrid(
ItemDetailViewCol(LocaleKeys.lineStatus.tr(), moNotificationBodyList[index].lINESTATUS ?? ""),
ItemDetailViewCol(LocaleKeys.statusDate.tr(), moNotificationBodyList[index].sTATUSDATE ?? ""),
),
ItemDetailGrid(
ItemDetailViewCol(LocaleKeys.transactionType.tr(), moNotificationBodyList[index].tRANSACTIONTYPENAME ?? ""),
ItemDetailViewCol(LocaleKeys.operatingUnit.tr(), moNotificationBodyList[index].oPERATINGUNIT ?? ""),
),
ItemDetailGrid(
ItemDetailViewCol(LocaleKeys.organizationCode.tr(), moNotificationBodyList[index].oRGANIZATIONCODE ?? ""),
ItemDetailViewCol(LocaleKeys.organization.tr(), moNotificationBodyList[index].oRGANIZATIONNAME ?? ""),
),
ItemDetailGrid(
ItemDetailViewCol(LocaleKeys.fromSubInventory.tr(), moNotificationBodyList[index].fROMSUBINVENTORY ?? ""),
ItemDetailViewCol(LocaleKeys.fromLocator.tr(), moNotificationBodyList[index].fROMLOCATOR ?? ""),
),
ItemDetailGrid(
ItemDetailViewCol(LocaleKeys.toSubInventory.tr(), moNotificationBodyList[index].tOSUBINVENTORY ?? ""),
ItemDetailViewCol(LocaleKeys.toLocator.tr(), moNotificationBodyList[index].tOLOCATOR ?? ""),
),
ItemDetailGrid(ItemDetailViewCol(LocaleKeys.shipToLocator.tr(), moNotificationBodyList[index].sHIPTOLOCATION ?? ""), Container()),
12.height,
DefaultButton(LocaleKeys.itemHistory.tr(), () {
Navigator.pushNamed(
cxt,
AppRoutes.itemHistory,
arguments: ItemHistoryScreenParams(title: LocaleKeys.itemHistory.tr(), pItemId: moNotificationBodyList[index].iTEMID, pOrgId: moNotificationBodyList[index].oRGID),
);
})
],
).objectContainerView(title: moNotificationBodyList[index].dESCRIPTION ?? ""),
separatorBuilder: (cxt, index) => 12.height,
itemCount: moNotificationBodyList.length);
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemBuilder:
(cxt, index) => Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
ItemDetailGrid(
ItemDetailViewCol(
LocaleKeys.code.tr(),
moNotificationBodyList[index].iTEMCODE ?? "",
),
ItemDetailViewCol(
LocaleKeys.unit.tr(),
moNotificationBodyList[index].uOM ?? "",
),
),
ItemDetailGrid(
ItemDetailViewCol(
LocaleKeys.quantity.tr(),
moNotificationBodyList[index].qUANTITY?.toString() ?? "",
),
ItemDetailViewCol(
LocaleKeys.dateRequired.tr(),
moNotificationBodyList[index].dATEREQUIRED ?? "",
),
),
ItemDetailGrid(
ItemDetailViewCol(
LocaleKeys.lineStatus.tr(),
moNotificationBodyList[index].lINESTATUS ?? "",
),
ItemDetailViewCol(
LocaleKeys.statusDate.tr(),
moNotificationBodyList[index].sTATUSDATE ?? "",
),
),
ItemDetailGrid(
ItemDetailViewCol(
LocaleKeys.transactionType.tr(),
moNotificationBodyList[index].tRANSACTIONTYPENAME ?? "",
),
ItemDetailViewCol(
LocaleKeys.operatingUnit.tr(),
moNotificationBodyList[index].oPERATINGUNIT ?? "",
),
),
ItemDetailGrid(
ItemDetailViewCol(
LocaleKeys.organizationCode.tr(),
moNotificationBodyList[index].oRGANIZATIONCODE ?? "",
),
ItemDetailViewCol(
LocaleKeys.organization.tr(),
moNotificationBodyList[index].oRGANIZATIONNAME ?? "",
),
),
ItemDetailGrid(
ItemDetailViewCol(
LocaleKeys.fromSubInventory.tr(),
moNotificationBodyList[index].fROMSUBINVENTORY ?? "",
),
ItemDetailViewCol(
LocaleKeys.fromLocator.tr(),
moNotificationBodyList[index].fROMLOCATOR ?? "",
),
),
ItemDetailGrid(
ItemDetailViewCol(
LocaleKeys.toSubInventory.tr(),
moNotificationBodyList[index].tOSUBINVENTORY ?? "",
),
ItemDetailViewCol(
LocaleKeys.toLocator.tr(),
moNotificationBodyList[index].tOLOCATOR ?? "",
),
),
ItemDetailGrid(
ItemDetailViewCol(
LocaleKeys.shipToLocator.tr(),
moNotificationBodyList[index].sHIPTOLOCATION ?? "",
),
Container(),
),
12.height,
DefaultButton(LocaleKeys.itemHistory.tr(), () {
Navigator.pushNamed(
cxt,
AppRoutes.itemHistory,
arguments: ItemHistoryScreenParams(
title: LocaleKeys.itemHistory.tr(),
pItemId: moNotificationBodyList[index].iTEMID,
pOrgId: moNotificationBodyList[index].oRGID,
),
);
}),
],
).objectContainerView(
title: moNotificationBodyList[index].dESCRIPTION ?? "",
),
separatorBuilder: (cxt, index) => 12.height,
itemCount: moNotificationBodyList.length,
);
}
Widget itemCreationLinesView() {
return ListView.separated(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemBuilder: (cxt, index) => Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
ItemDetailGrid(
ItemDetailViewCol(LocaleKeys.productName.tr(), itemCreationLines[index].pRODUCTNAME ?? ""),
ItemDetailViewCol(LocaleKeys.productDescription.tr(), itemCreationLines[index].pRODUCTDESCRIPTION ?? ""),
),
ItemDetailGrid(
ItemDetailViewCol(LocaleKeys.unitPrice.tr(), itemCreationLines[index].uNITPRICE?.toString() ?? ""),
ItemDetailViewCol(LocaleKeys.manufacturerName.tr(), itemCreationLines[index].uSERMANUFACTURERNAME ?? ""),
),
ItemDetailGrid(
ItemDetailViewCol(LocaleKeys.manufacturerPartName.tr(), itemCreationLines[index].uSERMFGPARTNUM ?? ""),
ItemDetailViewCol(LocaleKeys.supplierName.tr(), itemCreationLines[index].sUPPLIERNAME ?? ""),
),
ItemDetailGrid(
ItemDetailViewCol(LocaleKeys.supplierContact.tr(), itemCreationLines[index].sUPPLIERCONTACT ?? ""),
ItemDetailViewCol(LocaleKeys.chargeToPatient.tr(), itemCreationLines[index].cHARGETOPATIENT ?? ""),
),
ItemDetailGrid(
ItemDetailViewCol(LocaleKeys.justification.tr(), itemCreationLines[index].jUSTIFICATION ?? ""),
ItemDetailViewCol(LocaleKeys.itemCode.tr(), itemCreationLines[index].iTEMCODE ?? ""),
),
ItemDetailGrid(
ItemDetailViewCol(LocaleKeys.itemDescription.tr(), itemCreationLines[index].iTEMDESCRIPTION ?? ""),
ItemDetailViewCol(LocaleKeys.groupCode.tr(), itemCreationLines[index].iTEMGROUPCODE ?? ""),
),
ItemDetailGrid(
ItemDetailViewCol(LocaleKeys.groupDescription.tr(), itemCreationLines[index].iTEMGROUP ?? ""),
ItemDetailViewCol(LocaleKeys.subgroupCode.tr(), itemCreationLines[index].iTEMSUBGROUPCODE ?? ""),
),
ItemDetailGrid(
ItemDetailViewCol(LocaleKeys.subgroupDescription.tr(), itemCreationLines[index].iTEMSUBGROUP ?? ""),
ItemDetailViewCol(LocaleKeys.primaryUOM.tr(), itemCreationLines[index].pRIMARYUOM ?? ""),
),
ItemDetailGrid(
ItemDetailViewCol(LocaleKeys.manufacturerName.tr(), itemCreationLines[index].sTANDARDMANUFACTURERNAME ?? ""),
ItemDetailViewCol(LocaleKeys.manufacturerPartName.tr(), itemCreationLines[index].sTANDARDMFGPARTNUM ?? ""),
),
ItemDetailGrid(
ItemDetailViewCol(LocaleKeys.templateName.tr(), itemCreationLines[index].tEMPLATENAME ?? ""),
ItemDetailViewCol(LocaleKeys.itemCreationStatus.tr(), itemCreationLines[index].iTEMCREATIONSTATUS ?? ""),
),
ItemDetailGrid(
ItemDetailViewCol(LocaleKeys.standardizationApprovalStatus.tr(), itemCreationLines[index].sTANDARDSTATUS ?? ""),
ItemDetailViewCol(LocaleKeys.standardizationApprovalRejectionReason.tr(), itemCreationLines[index].sTANDARDREJECTREASON ?? ""),
isItLast: true,
),
],
).objectContainerView(title: itemCreationLines[index].iTEMDESCRIPTION!),
separatorBuilder: (cxt, index) => 12.height,
itemCount: itemCreationLines.length);
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemBuilder:
(cxt, index) => Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
ItemDetailGrid(
ItemDetailViewCol(
LocaleKeys.productName.tr(),
itemCreationLines[index].pRODUCTNAME ?? "",
),
ItemDetailViewCol(
LocaleKeys.productDescription.tr(),
itemCreationLines[index].pRODUCTDESCRIPTION ?? "",
),
),
ItemDetailGrid(
ItemDetailViewCol(
LocaleKeys.unitPrice.tr(),
itemCreationLines[index].uNITPRICE?.toString() ?? "",
),
ItemDetailViewCol(
LocaleKeys.manufacturerName.tr(),
itemCreationLines[index].uSERMANUFACTURERNAME ?? "",
),
),
ItemDetailGrid(
ItemDetailViewCol(
LocaleKeys.manufacturerPartName.tr(),
itemCreationLines[index].uSERMFGPARTNUM ?? "",
),
ItemDetailViewCol(
LocaleKeys.supplierName.tr(),
itemCreationLines[index].sUPPLIERNAME ?? "",
),
),
ItemDetailGrid(
ItemDetailViewCol(
LocaleKeys.supplierContact.tr(),
itemCreationLines[index].sUPPLIERCONTACT ?? "",
),
ItemDetailViewCol(
LocaleKeys.chargeToPatient.tr(),
itemCreationLines[index].cHARGETOPATIENT ?? "",
),
),
ItemDetailGrid(
ItemDetailViewCol(
LocaleKeys.justification.tr(),
itemCreationLines[index].jUSTIFICATION ?? "",
),
ItemDetailViewCol(
LocaleKeys.itemCode.tr(),
itemCreationLines[index].iTEMCODE ?? "",
),
),
ItemDetailGrid(
ItemDetailViewCol(
LocaleKeys.itemDescription.tr(),
itemCreationLines[index].iTEMDESCRIPTION ?? "",
),
ItemDetailViewCol(
LocaleKeys.groupCode.tr(),
itemCreationLines[index].iTEMGROUPCODE ?? "",
),
),
ItemDetailGrid(
ItemDetailViewCol(
LocaleKeys.groupDescription.tr(),
itemCreationLines[index].iTEMGROUP ?? "",
),
ItemDetailViewCol(
LocaleKeys.subgroupCode.tr(),
itemCreationLines[index].iTEMSUBGROUPCODE ?? "",
),
),
ItemDetailGrid(
ItemDetailViewCol(
LocaleKeys.subgroupDescription.tr(),
itemCreationLines[index].iTEMSUBGROUP ?? "",
),
ItemDetailViewCol(
LocaleKeys.primaryUOM.tr(),
itemCreationLines[index].pRIMARYUOM ?? "",
),
),
ItemDetailGrid(
ItemDetailViewCol(
LocaleKeys.manufacturerName.tr(),
itemCreationLines[index].sTANDARDMANUFACTURERNAME ?? "",
),
ItemDetailViewCol(
LocaleKeys.manufacturerPartName.tr(),
itemCreationLines[index].sTANDARDMFGPARTNUM ?? "",
),
),
ItemDetailGrid(
ItemDetailViewCol(
LocaleKeys.templateName.tr(),
itemCreationLines[index].tEMPLATENAME ?? "",
),
ItemDetailViewCol(
LocaleKeys.itemCreationStatus.tr(),
itemCreationLines[index].iTEMCREATIONSTATUS ?? "",
),
),
ItemDetailGrid(
ItemDetailViewCol(
LocaleKeys.standardizationApprovalStatus.tr(),
itemCreationLines[index].sTANDARDSTATUS ?? "",
),
ItemDetailViewCol(
LocaleKeys.standardizationApprovalRejectionReason.tr(),
itemCreationLines[index].sTANDARDREJECTREASON ?? "",
),
isItLast: true,
),
],
).objectContainerView(
title: itemCreationLines[index].iTEMDESCRIPTION!,
),
separatorBuilder: (cxt, index) => 12.height,
itemCount: itemCreationLines.length,
);
}
void getPRDetails(BuildContext context, String poLineID) async {
try {
Utils.showLoading(context);
GetPRInformationList? getPRInformationList = GetPRInformationList();
getPRInformationList = await WorkListApiClient().getPRDetailsForPO(poLineID);
getPRInformationList = await WorkListApiClient().getPRDetailsForPO(
poLineID,
);
Utils.hideLoading(context);
Navigator.pushNamed(
context,
AppRoutes.itemHistory,
arguments: ItemHistoryScreenParams(
isItemHistory: false, isMO: false, isPRInfo: true, getPRInformationList: getPRInformationList, title: "PR Details", pItemId: 0, pPoHeaderId: 0, pOLineID: poLineID),
isItemHistory: false,
isMO: false,
isPRInfo: true,
getPRInformationList: getPRInformationList,
title: "PR Details",
pItemId: 0,
pPoHeaderId: 0,
pOLineID: poLineID,
),
);
} catch (ex) {
Utils.hideLoading(context);

@ -11,7 +11,7 @@ import 'package:mohem_flutter_app/widgets/button/default_button.dart';
import 'package:mohem_flutter_app/widgets/dynamic_forms/dynamic_textfield_widget.dart';
class WorkListAdvanceSearch extends StatefulWidget {
Function(int, String, String, String) onSearch;
final Function(int, String, String, String) onSearch;
WorkListAdvanceSearch(this.onSearch, {Key? key}) : super(key: key);

@ -141,7 +141,7 @@ void galleryImageAndroid(Function(String, File) image) async {
}
void cameraImageAndroid(Function(String, File) image) async {
File _image = File(( await picker.pickMedia())?.path ?? "");
File _image = File((await picker.pickImage(source: ImageSource.camera, imageQuality: 20))?.path ?? "");
String fileName = _image.path;
var bytes = File(fileName).readAsBytesSync();
String base64Encode = base64.encode(bytes);
@ -159,7 +159,7 @@ class _BottomSheet extends StatelessWidget {
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.symmetric(vertical: 12.0),
decoration: BoxDecoration( borderRadius: const BorderRadius.only(topLeft: Radius.circular(16.0), topRight: Radius.circular(16.0))),
decoration: const BoxDecoration( borderRadius: BorderRadius.only(topLeft: Radius.circular(16.0), topRight: Radius.circular(16.0))),
child: SafeArea(
top: false,
child: Column(

@ -8,6 +8,8 @@ import 'package:mohem_flutter_app/generated/locale_keys.g.dart';
import 'package:shimmer/shimmer.dart';
class GetAttendanceTrackingShimmer extends StatelessWidget {
const GetAttendanceTrackingShimmer({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
@ -17,13 +19,7 @@ class GetAttendanceTrackingShimmer extends StatelessWidget {
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(15),
boxShadow: [
BoxShadow(
color: const Color(0xff000000).withOpacity(.05),
blurRadius: 26,
offset: const Offset(0, -3),
),
],
boxShadow: [BoxShadow(color: const Color(0xff000000).withOpacity(.05), blurRadius: 26, offset: const Offset(0, -3))],
),
child: Stack(
alignment: Alignment.center,
@ -44,15 +40,8 @@ class GetAttendanceTrackingShimmer extends StatelessWidget {
LocaleKeys.timeLeftToday.tr().toText10(color: Colors.white).toShimmer(),
9.height,
const ClipRRect(
borderRadius: BorderRadius.all(
Radius.circular(20),
),
child: LinearProgressIndicator(
value: 0.7,
minHeight: 8,
valueColor: const AlwaysStoppedAnimation<Color>(Colors.white),
backgroundColor: const Color(0xff196D73),
),
borderRadius: BorderRadius.all(Radius.circular(20)),
child: LinearProgressIndicator(value: 0.7, minHeight: 8, valueColor: const AlwaysStoppedAnimation<Color>(Colors.white), backgroundColor: const Color(0xff196D73)),
).toShimmer(),
],
).paddingOnly(top: 12, right: 15, left: 12),
@ -63,9 +52,7 @@ class GetAttendanceTrackingShimmer extends StatelessWidget {
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
LocaleKeys.checkIn.tr().toText12(color: Colors.white).toShimmer(),
],
children: [LocaleKeys.checkIn.tr().toText12(color: Colors.white).toShimmer()],
).paddingOnly(left: 12),
),
Container(
@ -85,6 +72,8 @@ class GetAttendanceTrackingShimmer extends StatelessWidget {
}
class MenuShimmer extends StatelessWidget {
const MenuShimmer({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
@ -92,13 +81,7 @@ class MenuShimmer extends StatelessWidget {
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(15),
boxShadow: [
BoxShadow(
color: const Color(0xff000000).withOpacity(.05),
blurRadius: 26,
offset: const Offset(0, -3),
),
],
boxShadow: [BoxShadow(color: const Color(0xff000000).withOpacity(.05), blurRadius: 26, offset: const Offset(0, -3))],
),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
@ -107,14 +90,11 @@ class MenuShimmer extends StatelessWidget {
LocaleKeys.workList.tr().toText12(color: Colors.white).toShimmer(),
Row(
children: [
Expanded(
flex: 3,
child: 123.toString().toText10(color: Colors.white, isBold: true).toShimmer(),
),
Expanded(flex: 3, child: 123.toString().toText10(color: Colors.white, isBold: true).toShimmer()),
12.width,
SvgPicture.asset("assets/images/arrow_next.svg", color: Colors.white).toShimmer()
SvgPicture.asset("assets/images/arrow_next.svg", color: Colors.white).toShimmer(),
],
)
),
],
).paddingOnly(left: 10, right: 10, bottom: 6, top: 6),
);
@ -122,6 +102,8 @@ class MenuShimmer extends StatelessWidget {
}
class ServicesHeaderShimmer extends StatelessWidget {
const ServicesHeaderShimmer({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Row(
@ -131,11 +113,7 @@ class ServicesHeaderShimmer extends StatelessWidget {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
LocaleKeys.otherCharges.tr().toText10().toShimmer(),
6.height,
LocaleKeys.services.tr().toText12(isBold: true).toShimmer(),
],
children: [LocaleKeys.otherCharges.tr().toText10().toShimmer(), 6.height, LocaleKeys.services.tr().toText12(isBold: true).toShimmer()],
),
),
LocaleKeys.viewAllServices.tr().toText12(isUnderLine: true).toShimmer(),
@ -145,19 +123,15 @@ class ServicesHeaderShimmer extends StatelessWidget {
}
class ServicesMenuShimmer extends StatelessWidget {
const ServicesMenuShimmer({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(15),
boxShadow: [
BoxShadow(
color: const Color(0xff000000).withOpacity(.05),
blurRadius: 26,
offset: const Offset(0, -3),
),
],
boxShadow: [BoxShadow(color: const Color(0xff000000).withOpacity(.05), blurRadius: 26, offset: const Offset(0, -3))],
),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
@ -173,21 +147,54 @@ class ServicesMenuShimmer extends StatelessWidget {
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Expanded(
child: LocaleKeys.attendance.tr().toText11(isBold: false).toShimmer(),
),
Expanded(child: LocaleKeys.attendance.tr().toText11(isBold: false).toShimmer()),
6.width,
SvgPicture.asset("assets/images/arrow_next.svg").paddingOnly(bottom: 4).toShimmer()
SvgPicture.asset("assets/images/arrow_next.svg").paddingOnly(bottom: 4).toShimmer(),
],
),
],
)
),
],
).paddingOnly(left: 10, right: 10, bottom: 10, top: 12),
);
}
}
class GreetingCardShimmer extends StatelessWidget {
const GreetingCardShimmer({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
height: 140,
decoration: BoxDecoration(color: const Color(0xFFFAF4E7), border: Border.all(width: 2, color: const Color(0xFFE7E7E7)), borderRadius: BorderRadius.circular(20)),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(width: 10),
Container(width: 65, height: 100, decoration: BoxDecoration(color: Colors.grey[300], borderRadius: BorderRadius.circular(10))).toShimmer().paddingOnly(top: 10),
const SizedBox(width: 10),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(width: 150, height: 16, decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(4))).toShimmer(),
const SizedBox(height: 8),
Container(width: 120, height: 16, decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(4))).toShimmer(),
],
).expanded,
Column(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.end,
children: [Container(width: 60, height: 12, decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(4))).toShimmer()],
),
],
).paddingOnly(left: 8, right: 8, top: 6, bottom: 12),
).paddingOnly(top: 14, bottom: 14);
}
}
class MarathonBannerShimmer extends StatelessWidget {
const MarathonBannerShimmer({Key? key}) : super(key: key);
@ -197,13 +204,7 @@ class MarathonBannerShimmer extends StatelessWidget {
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(15),
boxShadow: [
BoxShadow(
color: const Color(0xff000000).withOpacity(.05),
blurRadius: 26,
offset: const Offset(0, -3),
),
],
boxShadow: [BoxShadow(color: const Color(0xff000000).withOpacity(.05), blurRadius: 26, offset: const Offset(0, -3))],
),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
@ -219,15 +220,13 @@ class MarathonBannerShimmer extends StatelessWidget {
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Expanded(
child: LocaleKeys.attendance.tr().toText11(isBold: false).toShimmer(),
),
Expanded(child: LocaleKeys.attendance.tr().toText11(isBold: false).toShimmer()),
6.width,
SvgPicture.asset("assets/images/arrow_next.svg").paddingOnly(bottom: 4).toShimmer()
SvgPicture.asset("assets/images/arrow_next.svg").paddingOnly(bottom: 4).toShimmer(),
],
),
],
)
),
],
).paddingOnly(left: 10, right: 10, bottom: 10, top: 12),
);
@ -243,65 +242,43 @@ class ChatHomeShimmer extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
width: double.infinity,
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 16.0),
child: Column(
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Expanded(
child: Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey.shade100,
child: ListView.builder(
itemBuilder: (_, __) => Padding(
padding: const EdgeInsets.only(bottom: 8.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
if (!isDetailedScreen)
Container(
width: 48.0,
height: 48.0,
decoration: const BoxDecoration(color: Colors.white, borderRadius: BorderRadius.all(Radius.circular(40))),
),
if (!isDetailedScreen)
const Padding(
padding: EdgeInsets.symmetric(horizontal: 8.0),
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
width: double.infinity,
height: 20.0,
color: Colors.white,
),
const Padding(
padding: EdgeInsets.symmetric(vertical: 2.0),
),
Container(
width: double.infinity,
height: 15.0,
color: Colors.white,
),
const Padding(
padding: EdgeInsets.symmetric(vertical: 2.0),
),
Container(
width: 40.0,
height: 10.0,
color: Colors.white,
),
],
).expanded
],
width: double.infinity,
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 16.0),
child: Column(
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Expanded(
child: Shimmer.fromColors(
baseColor: Colors.white,
highlightColor: Colors.grey.shade100,
child: ListView.builder(
itemBuilder:
(_, __) => Padding(
padding: const EdgeInsets.only(bottom: 8.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
if (!isDetailedScreen) Container(width: 48.0, height: 48.0, decoration: const BoxDecoration(color: Colors.white, borderRadius: BorderRadius.all(Radius.circular(40)))),
if (!isDetailedScreen) const Padding(padding: EdgeInsets.symmetric(horizontal: 8.0)),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(width: double.infinity, height: 20.0, color: Colors.white),
const Padding(padding: EdgeInsets.symmetric(vertical: 2.0)),
Container(width: double.infinity, height: 15.0, color: Colors.white),
const Padding(padding: EdgeInsets.symmetric(vertical: 2.0)),
Container(width: 40.0, height: 10.0, color: Colors.white),
],
).expanded,
],
),
),
),
itemCount: 6,
),
itemCount: 6,
),
),
],
));
),
],
),
);
}
}

@ -1,13 +1,17 @@
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:mohem_flutter_app/classes/utils.dart';
import 'package:mohem_flutter_app/widgets/app_bar_widget.dart';
import 'package:webview_flutter/webview_flutter.dart';
// Enum for SSO types
enum SsoType { forTicket, forEnsat, forCourses }
class SsoLoginWebView extends StatefulWidget {
final String? url;
final String? jwtToken;
final SsoType ssoType;
SsoLoginWebView({this.url, this.jwtToken});
const SsoLoginWebView({Key? key, required this.url, this.jwtToken, required this.ssoType}) : super(key: key);
@override
State<SsoLoginWebView> createState() => _SsoLoginWebViewState();
@ -15,11 +19,27 @@ class SsoLoginWebView extends StatefulWidget {
class _SsoLoginWebViewState extends State<SsoLoginWebView> {
late final WebViewController _controller;
String? url;
bool _isTicketLoadingVisible = false;
void _showTicketLoading() {
if (widget.ssoType != SsoType.forTicket || _isTicketLoadingVisible || !mounted) return;
_isTicketLoadingVisible = true;
Utils.showLoading(context);
}
void _hideTicketLoading() {
if (widget.ssoType != SsoType.forTicket || !_isTicketLoadingVisible || !mounted) return;
_isTicketLoadingVisible = false;
Utils.hideLoading(context);
}
@override
void initState() {
// TODO: implement initState
super.initState();
url = widget.url ?? "";
_controller =
WebViewController()
..setJavaScriptMode(JavaScriptMode.unrestricted)
@ -27,35 +47,72 @@ class _SsoLoginWebViewState extends State<SsoLoginWebView> {
NavigationDelegate(
onProgress: (int progress) {
print("WebView is loading (progress: $progress%)");
if (widget.ssoType == SsoType.forEnsat && progress == 100) {
Utils.hideLoading(context);
}
},
onPageStarted: (String url) {
print("Page started loading: $url");
_showTicketLoading();
},
onPageFinished: (String url) {
print("Page finished loading: $url");
_hideTicketLoading();
},
onHttpError: (HttpResponseError error) {
print("HTTP error: ${error.toString()} for URL: ${error.response!.statusCode}");
_hideTicketLoading();
},
onWebResourceError: (WebResourceError error) {
print("Web resource error: ${error.description} for URL: ${error.errorType}");
_hideTicketLoading();
},
),
)
..loadHtmlString('''
);
// Load content based on SSO type
if (widget.ssoType == SsoType.forEnsat) {
// For ENSAT, just load the URL directly (GET request)
_controller.loadRequest(Uri.parse(url!));
} else {
if (widget.ssoType == SsoType.forTicket) {
WidgetsBinding.instance.addPostFrameCallback((_) {
_showTicketLoading();
});
}
// For Paxes (Ticket, Courses), use HTML form POST
_controller.loadHtmlString(_buildHtmlContent());
}
}
// Build HTML content for the SSO form
String _buildHtmlContent() {
String formAction;
if (widget.ssoType == SsoType.forTicket) {
formAction = "https://www.paxes.com/sso/hmg";
} else {
formAction = url ?? "";
}
return '''
<!DOCTYPE html>
<html>
<body onload="document.forms[0].submit()">
<form method="POST" action="https://Paxes-release.techmaster.in/SSO/HMG">
<form method="POST" action="$formAction">
<input type="hidden" name="JWTToken" value="${widget.jwtToken}" />
</form>
<h1>Redirecting...</h1>
<h1></h1>
</body>
</html>''');
</html>''';
}
@override
void dispose() {
_hideTicketLoading();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(appBar: AppBar(title: Text('Logging in...')), body: WebViewWidget(controller: _controller));
return Scaffold(appBar: AppBarWidget(context, title: "MoheM", showWorkListSettingButton: false), body: SafeArea(child: WebViewWidget(controller: _controller)));
}
}

@ -17,8 +17,8 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
#version: 3.7.1+300081
version: 3.9.3+1
version: 3.7.2+300082
#version: 3.9.3+1
environment:
sdk: ^3.7.0
@ -102,6 +102,9 @@ dependencies:
audio_waveforms: ^1.3.0
rxdart: ^0.27.7
#Speech to Text
speech_to_text: ^7.0.0
#Encryption
flutter_des: ^2.1.0
@ -109,6 +112,7 @@ dependencies:
just_audio: ^0.9.30
# safe_device: ^1.1.2
flutter_layout_grid: ^2.0.1
jiffy: ^6.4.4
#Huawei Dependencies
# huawei_hmsavailability: ^6.6.0+300

Loading…
Cancel
Save