@dasidev/dasi-ui 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (450) hide show
  1. package/README.md +346 -0
  2. package/bin/dasi-cli.cjs +184 -0
  3. package/dist/date-selector-test-BlukYeWl.js +91 -0
  4. package/dist/favicon.ico +0 -0
  5. package/dist/html2canvas.esm-CKxSAI8P.js +4886 -0
  6. package/dist/img/brand/ic_pln.svg +12 -0
  7. package/dist/img/brand/mapp_power_logo.svg +21 -0
  8. package/dist/img/common/pltu_ulumbu_flores_ntt.jpeg +0 -0
  9. package/dist/index-BQSA2aPs.js +126556 -0
  10. package/dist/index.es-DQWt-PZn.js +5769 -0
  11. package/dist/index.es.js +11 -0
  12. package/dist/index.umd.js +8564 -0
  13. package/dist/informasi-gudang-BmoEy2RL.js +164 -0
  14. package/dist/informasi-gudang-DXfS46Nh.js +50 -0
  15. package/dist/purify.es-C-9oolON.js +546 -0
  16. package/dist/scripts/pdf.worker.min.js +29 -0
  17. package/dist/scripts/pdf.worker.min.mjs +29 -0
  18. package/dist/scripts/pdf.worker.mjs +57722 -0
  19. package/dist/scripts/pdf.worker.mjs.map +1 -0
  20. package/dist/style.css +1 -0
  21. package/dist/test-schema-JFghGc0_.js +8 -0
  22. package/dist/test-schema-uusFsJe4.js +438 -0
  23. package/dist/types-l0sNRNKZ.js +1 -0
  24. package/package.json +178 -0
  25. package/src/App.vue +18 -0
  26. package/src/__tests__/index.test.ts +9 -0
  27. package/src/api/api.ts +117 -0
  28. package/src/assets/app-selector.svg +3 -0
  29. package/src/assets/dasi.png +0 -0
  30. package/src/assets/foto_ss.svg +21 -0
  31. package/src/assets/icons/circle-blue.svg +4 -0
  32. package/src/assets/icons/circle-gray.svg +15 -0
  33. package/src/assets/icons/circle-green.svg +4 -0
  34. package/src/assets/icons/circle-orange.svg +4 -0
  35. package/src/assets/icons/circle-purple.svg +4 -0
  36. package/src/assets/icons/circle-red.svg +15 -0
  37. package/src/assets/icons/harbor.svg +12 -0
  38. package/src/assets/icons/ic-box-red.svg +8 -0
  39. package/src/assets/icons/ic-chevron-right.svg +1 -0
  40. package/src/assets/icons/ic-loading.svg +9 -0
  41. package/src/assets/icons/ic-reset.svg +16 -0
  42. package/src/assets/icons/ic-sailing.svg +5 -0
  43. package/src/assets/icons/icon-app-selector.svg +3 -0
  44. package/src/assets/icons/icon-browser-check.svg +4 -0
  45. package/src/assets/icons/icon-calendar.svg +3 -0
  46. package/src/assets/icons/icon-chart-bar.svg +3 -0
  47. package/src/assets/icons/icon-chart-doc.svg +16 -0
  48. package/src/assets/icons/icon-chart-line.svg +10 -0
  49. package/src/assets/icons/icon-chart-mix.svg +15 -0
  50. package/src/assets/icons/icon-chart-pie.svg +11 -0
  51. package/src/assets/icons/icon-continue.svg +12 -0
  52. package/src/assets/icons/icon-dashboard-2.svg +17 -0
  53. package/src/assets/icons/icon-dashboard.svg +3 -0
  54. package/src/assets/icons/icon-data-kelistrikan.svg +19 -0
  55. package/src/assets/icons/icon-data-sentral.svg +11 -0
  56. package/src/assets/icons/icon-database.svg +5 -0
  57. package/src/assets/icons/icon-desktop.svg +3 -0
  58. package/src/assets/icons/icon-download.svg +13 -0
  59. package/src/assets/icons/icon-energi-primer.svg +12 -0
  60. package/src/assets/icons/icon-faba-apk2.svg +11 -0
  61. package/src/assets/icons/icon-faba.svg +11 -0
  62. package/src/assets/icons/icon-factory.svg +14 -0
  63. package/src/assets/icons/icon-globe-doc.svg +19 -0
  64. package/src/assets/icons/icon-ikk.svg +10 -0
  65. package/src/assets/icons/icon-kbb.svg +13 -0
  66. package/src/assets/icons/icon-kos.svg +16 -0
  67. package/src/assets/icons/icon-kpi-bod.svg +15 -0
  68. package/src/assets/icons/icon-kss.svg +14 -0
  69. package/src/assets/icons/icon-map.svg +12 -0
  70. package/src/assets/icons/icon-monitoring-harian.svg +13 -0
  71. package/src/assets/icons/icon-notification.svg +4 -0
  72. package/src/assets/icons/icon-overview.svg +17 -0
  73. package/src/assets/icons/icon-pltu.svg +13 -0
  74. package/src/assets/icons/icon-sebaran-sentral.svg +12 -0
  75. package/src/assets/icons/icon-select-data-kelistrikan.svg +19 -0
  76. package/src/assets/icons/icon-select-data-sentral.svg +11 -0
  77. package/src/assets/icons/icon-select-energi-primer.svg +12 -0
  78. package/src/assets/icons/icon-select-faba-apk2.svg +11 -0
  79. package/src/assets/icons/icon-select-ikk.svg +10 -0
  80. package/src/assets/icons/icon-select-kbb.svg +13 -0
  81. package/src/assets/icons/icon-select-kos.svg +16 -0
  82. package/src/assets/icons/icon-select-kpi-bod.svg +15 -0
  83. package/src/assets/icons/icon-select-kss.svg +14 -0
  84. package/src/assets/icons/icon-select-monitoring-harian.svg +13 -0
  85. package/src/assets/icons/icon-select-overview.svg +17 -0
  86. package/src/assets/icons/icon-select-sebaran-sentral.svg +12 -0
  87. package/src/assets/icons/icon-sentral-white.svg +13 -0
  88. package/src/assets/icons/icon-shipping.svg +5 -0
  89. package/src/assets/icons/icon-sort.svg +5 -0
  90. package/src/assets/icons/icon-tree-box.svg +14 -0
  91. package/src/assets/icons/icon-warehouse.svg +12 -0
  92. package/src/assets/icons/pin-green.svg +3 -0
  93. package/src/assets/icons/pin-orange.svg +3 -0
  94. package/src/assets/icons/pin-purple.svg +3 -0
  95. package/src/assets/icons/ship.svg +3 -0
  96. package/src/assets/icons/shipment/icon-antri.svg +15 -0
  97. package/src/assets/icons/shipment/icon-bongkar.svg +4 -0
  98. package/src/assets/icons/shipment/icon-invoice.svg +6 -0
  99. package/src/assets/icons/shipment/icon-loading.svg +8 -0
  100. package/src/assets/icons/shipment/icon-pembayaran.svg +13 -0
  101. package/src/assets/icons/shipment/icon-pengiriman.svg +4 -0
  102. package/src/assets/icons/shipment/icon-sailing.svg +4 -0
  103. package/src/assets/icons/shipment/icon-shipment-completed.svg +6 -0
  104. package/src/assets/icons/shipment/icon-shipment-in-progress.svg +6 -0
  105. package/src/assets/icons/shipment/icon-shipment-over-sla.svg +6 -0
  106. package/src/assets/icons/shipment/icon-spt.svg +4 -0
  107. package/src/assets/icons/shipment/icon-total-shipment.svg +4 -0
  108. package/src/assets/icons/upload_doc_icon.svg +42 -0
  109. package/src/assets/icons/upload_icon_blue.svg +14 -0
  110. package/src/assets/login-bg-day-min.jpg +0 -0
  111. package/src/assets/login-bg-night-min.jpg +0 -0
  112. package/src/assets/login-bg.jpg +0 -0
  113. package/src/assets/login-day.png +0 -0
  114. package/src/assets/login-night.png +0 -0
  115. package/src/assets/lucide-circle-plus-blue.svg +1 -0
  116. package/src/assets/pdf-logo.svg +11 -0
  117. package/src/assets/pemasok-card-bg.svg +6 -0
  118. package/src/assets/success_animation.gif +0 -0
  119. package/src/assets/success_animation.mp4 +0 -0
  120. package/src/assets/success_animation.webm +0 -0
  121. package/src/components/button/BtnAddOutline.vue +14 -0
  122. package/src/components/button/BtnCircle.vue +10 -0
  123. package/src/components/button/BtnOutline.vue +15 -0
  124. package/src/components/button/BtnPrimary.vue +25 -0
  125. package/src/components/button/BtnSecondary.vue +26 -0
  126. package/src/components/detail/AccountDetailTimeline.vue +144 -0
  127. package/src/components/detail/ApprovalInfo.vue +288 -0
  128. package/src/components/detail/DCI2.vue +164 -0
  129. package/src/components/detail/DetailContentHeader.vue +83 -0
  130. package/src/components/detail/DetailContentItem.vue +186 -0
  131. package/src/components/detail/DetailContentItems.vue +388 -0
  132. package/src/components/detail/DetailContentLoading.vue +12 -0
  133. package/src/components/detail/DetailContentTablet.vue +10 -0
  134. package/src/components/detail/DetailSheet.vue +294 -0
  135. package/src/components/detail/DetailTimeline.vue +191 -0
  136. package/src/components/detail/DocApprovalDialog.vue +29 -0
  137. package/src/components/detail/DocViewerContent.vue +991 -0
  138. package/src/components/dialog/ConfirmDialog.vue +96 -0
  139. package/src/components/dialog/DialogBase.vue +53 -0
  140. package/src/components/dialog/DialogSelect.vue +212 -0
  141. package/src/components/dialog/ErrorDialog.vue +63 -0
  142. package/src/components/dialog/FormDialog.vue +141 -0
  143. package/src/components/dialog/FormInputerDialog.vue +91 -0
  144. package/src/components/dialog/InfoDialog.vue +74 -0
  145. package/src/components/dialog/SuccessDialog.vue +51 -0
  146. package/src/components/examples/TestSchemaExample.vue +288 -0
  147. package/src/components/forms/auth/LoginForm.vue +806 -0
  148. package/src/components/forms/auth/PwdScore.vue +68 -0
  149. package/src/components/helper/ApiTester.vue +153 -0
  150. package/src/components/helper/ChangePwd.vue +150 -0
  151. package/src/components/helper/CheckboxElement.vue +43 -0
  152. package/src/components/helper/ConfigSwitcher.vue +54 -0
  153. package/src/components/helper/Copyright.vue +10 -0
  154. package/src/components/helper/ErrorScreen.vue +40 -0
  155. package/src/components/helper/LucideIcon.vue +27 -0
  156. package/src/components/helper/PdfViewer.vue +103 -0
  157. package/src/components/helper/PinInputer.vue +205 -0
  158. package/src/components/helper/PrivacyPolicy.vue +122 -0
  159. package/src/components/layout/PageActivityHeader.vue +48 -0
  160. package/src/components/layout/PageHeader.vue +70 -0
  161. package/src/components/loadings/LoadingDialog.vue +29 -0
  162. package/src/components/loadings/LoadingDialogSpin.vue +25 -0
  163. package/src/components/loadings/LoadingIndicator.vue +38 -0
  164. package/src/components/loadings/LoadingScreen.vue +23 -0
  165. package/src/components/notif/Notif.vue +103 -0
  166. package/src/components/notif/NotifItem.vue +41 -0
  167. package/src/components/pages/Header.vue +431 -0
  168. package/src/components/pages/Leftbar.vue +417 -0
  169. package/src/components/pages/PageActivity.vue +108 -0
  170. package/src/components/pages/PageActivityContent.vue +597 -0
  171. package/src/components/pages/PageContentTable.vue +589 -0
  172. package/src/components/pages/PageTab.vue +84 -0
  173. package/src/components/selector/BaseSelector.vue +1136 -0
  174. package/src/components/selector/ConfigDataSelector.vue +136 -0
  175. package/src/components/settings/SettingsItem.vue +38 -0
  176. package/src/components/tab/TabView.vue +11 -0
  177. package/src/components/tab/TabViewItem.vue +18 -0
  178. package/src/components/tab/TabViewItemBar.vue +9 -0
  179. package/src/components/tables/CellHover.vue +65 -0
  180. package/src/components/tables/DashboardDataTable.vue +707 -0
  181. package/src/components/tables/DataStatusTag.vue +52 -0
  182. package/src/components/tables/DataTable.vue +156 -0
  183. package/src/components/tables/DataTableAccordion.vue +249 -0
  184. package/src/components/tables/DataTableActionRow.vue +64 -0
  185. package/src/components/tables/DataTableCell.vue +272 -0
  186. package/src/components/tables/DataTableHeader.vue +60 -0
  187. package/src/components/tables/DataTableRow.vue +213 -0
  188. package/src/components/tables/ExpandedTable.vue +259 -0
  189. package/src/components/tables/PageTable.vue +73 -0
  190. package/src/components/tables/Pagination.vue +98 -0
  191. package/src/components/tables/dropdown/BaseDropdownTable.vue +140 -0
  192. package/src/components/tables/dropdown/DropdownTableActivity.vue +33 -0
  193. package/src/components/tables/dropdown/DropdownTableAsset.vue +30 -0
  194. package/src/components/tables/dropdown/DropdownTableConfig.vue +30 -0
  195. package/src/components/tables/dropdown/DropdownTableDataKonektor.vue +31 -0
  196. package/src/components/tables/dropdown/DropdownTableDataLabel.vue +30 -0
  197. package/src/components/tables/dropdown/DropdownTableDataSchema.vue +31 -0
  198. package/src/components/tables/dropdown/DropdownTableFabaPemanfaat.vue +30 -0
  199. package/src/components/tables/dropdown/DropdownTableGroup.vue +36 -0
  200. package/src/components/tables/dropdown/DropdownTableHalaman.vue +33 -0
  201. package/src/components/tables/dropdown/DropdownTableLevel.vue +66 -0
  202. package/src/components/tables/dropdown/DropdownTableOrganization.vue +47 -0
  203. package/src/components/tables/dropdown/DropdownTablePengelola.vue +28 -0
  204. package/src/components/tables/dropdown/DropdownTableQueryLayer.vue +29 -0
  205. package/src/components/tables/dropdown/DropdownTableSentral.vue +33 -0
  206. package/src/components/tables/dropdown/DropdownTableWarehouse.vue +30 -0
  207. package/src/components/tables/dropdown/TableDropdown.vue +52 -0
  208. package/src/components/ui/accordion/Accordion.vue +19 -0
  209. package/src/components/ui/accordion/AccordionContent.vue +24 -0
  210. package/src/components/ui/accordion/AccordionItem.vue +24 -0
  211. package/src/components/ui/accordion/AccordionTrigger.vue +42 -0
  212. package/src/components/ui/accordion/index.ts +4 -0
  213. package/src/components/ui/alert-dialog/AlertDialog.vue +14 -0
  214. package/src/components/ui/alert-dialog/AlertDialogAction.vue +20 -0
  215. package/src/components/ui/alert-dialog/AlertDialogCancel.vue +20 -0
  216. package/src/components/ui/alert-dialog/AlertDialogContent.vue +42 -0
  217. package/src/components/ui/alert-dialog/AlertDialogDescription.vue +25 -0
  218. package/src/components/ui/alert-dialog/AlertDialogFooter.vue +21 -0
  219. package/src/components/ui/alert-dialog/AlertDialogHeader.vue +16 -0
  220. package/src/components/ui/alert-dialog/AlertDialogTitle.vue +22 -0
  221. package/src/components/ui/alert-dialog/AlertDialogTrigger.vue +11 -0
  222. package/src/components/ui/alert-dialog/index.ts +9 -0
  223. package/src/components/ui/avatar/Avatar.vue +24 -0
  224. package/src/components/ui/avatar/AvatarFallback.vue +11 -0
  225. package/src/components/ui/avatar/AvatarImage.vue +9 -0
  226. package/src/components/ui/avatar/UsersAvatar.vue +28 -0
  227. package/src/components/ui/avatar/index.ts +24 -0
  228. package/src/components/ui/button/Button.vue +27 -0
  229. package/src/components/ui/button/index.ts +34 -0
  230. package/src/components/ui/calendar/Calendar.vue +325 -0
  231. package/src/components/ui/calendar/index.ts +22 -0
  232. package/src/components/ui/checkbox/Checkbox.vue +33 -0
  233. package/src/components/ui/checkbox/index.ts +1 -0
  234. package/src/components/ui/command/Command.vue +30 -0
  235. package/src/components/ui/command/CommandDialog.vue +21 -0
  236. package/src/components/ui/command/CommandEmpty.vue +20 -0
  237. package/src/components/ui/command/CommandGroup.vue +29 -0
  238. package/src/components/ui/command/CommandInput.vue +33 -0
  239. package/src/components/ui/command/CommandItem.vue +26 -0
  240. package/src/components/ui/command/CommandList.vue +27 -0
  241. package/src/components/ui/command/CommandSeparator.vue +23 -0
  242. package/src/components/ui/command/CommandShortcut.vue +14 -0
  243. package/src/components/ui/command/index.ts +9 -0
  244. package/src/components/ui/context-menu/ContextMenu.vue +15 -0
  245. package/src/components/ui/context-menu/ContextMenuCheckboxItem.vue +40 -0
  246. package/src/components/ui/context-menu/ContextMenuContent.vue +36 -0
  247. package/src/components/ui/context-menu/ContextMenuGroup.vue +11 -0
  248. package/src/components/ui/context-menu/ContextMenuItem.vue +34 -0
  249. package/src/components/ui/context-menu/ContextMenuLabel.vue +25 -0
  250. package/src/components/ui/context-menu/ContextMenuPortal.vue +11 -0
  251. package/src/components/ui/context-menu/ContextMenuRadioGroup.vue +19 -0
  252. package/src/components/ui/context-menu/ContextMenuRadioItem.vue +40 -0
  253. package/src/components/ui/context-menu/ContextMenuSeparator.vue +20 -0
  254. package/src/components/ui/context-menu/ContextMenuShortcut.vue +14 -0
  255. package/src/components/ui/context-menu/ContextMenuSub.vue +19 -0
  256. package/src/components/ui/context-menu/ContextMenuSubContent.vue +35 -0
  257. package/src/components/ui/context-menu/ContextMenuSubTrigger.vue +34 -0
  258. package/src/components/ui/context-menu/ContextMenuTrigger.vue +13 -0
  259. package/src/components/ui/context-menu/index.ts +14 -0
  260. package/src/components/ui/datetime/DatetimeRangeComponent.vue +52 -0
  261. package/src/components/ui/dialog/Dialog.vue +14 -0
  262. package/src/components/ui/dialog/DialogClose.vue +11 -0
  263. package/src/components/ui/dialog/DialogContent.vue +53 -0
  264. package/src/components/ui/dialog/DialogDescription.vue +24 -0
  265. package/src/components/ui/dialog/DialogFooter.vue +19 -0
  266. package/src/components/ui/dialog/DialogHeader.vue +16 -0
  267. package/src/components/ui/dialog/DialogScrollContent.vue +59 -0
  268. package/src/components/ui/dialog/DialogTitle.vue +29 -0
  269. package/src/components/ui/dialog/DialogTrigger.vue +11 -0
  270. package/src/components/ui/dialog/index.ts +9 -0
  271. package/src/components/ui/dropdown-menu/DropdownMenu.vue +14 -0
  272. package/src/components/ui/dropdown-menu/DropdownMenuCheckboxItem.vue +40 -0
  273. package/src/components/ui/dropdown-menu/DropdownMenuContent.vue +38 -0
  274. package/src/components/ui/dropdown-menu/DropdownMenuGroup.vue +11 -0
  275. package/src/components/ui/dropdown-menu/DropdownMenuItem.vue +28 -0
  276. package/src/components/ui/dropdown-menu/DropdownMenuLabel.vue +24 -0
  277. package/src/components/ui/dropdown-menu/DropdownMenuRadioGroup.vue +19 -0
  278. package/src/components/ui/dropdown-menu/DropdownMenuRadioItem.vue +41 -0
  279. package/src/components/ui/dropdown-menu/DropdownMenuSeparator.vue +22 -0
  280. package/src/components/ui/dropdown-menu/DropdownMenuShortcut.vue +14 -0
  281. package/src/components/ui/dropdown-menu/DropdownMenuSub.vue +19 -0
  282. package/src/components/ui/dropdown-menu/DropdownMenuSubContent.vue +30 -0
  283. package/src/components/ui/dropdown-menu/DropdownMenuSubTrigger.vue +33 -0
  284. package/src/components/ui/dropdown-menu/DropdownMenuTrigger.vue +13 -0
  285. package/src/components/ui/dropdown-menu/index.ts +16 -0
  286. package/src/components/ui/form/FormControl.vue +16 -0
  287. package/src/components/ui/form/FormDescription.vue +20 -0
  288. package/src/components/ui/form/FormItem.vue +25 -0
  289. package/src/components/ui/form/FormLabel.vue +23 -0
  290. package/src/components/ui/form/FormMessage.vue +16 -0
  291. package/src/components/ui/form/index.ts +6 -0
  292. package/src/components/ui/form/useFormField.ts +30 -0
  293. package/src/components/ui/hover-card/HoverCard.vue +14 -0
  294. package/src/components/ui/hover-card/HoverCardContent.vue +41 -0
  295. package/src/components/ui/hover-card/HoverCardTrigger.vue +11 -0
  296. package/src/components/ui/hover-card/index.ts +3 -0
  297. package/src/components/ui/input/Input.vue +24 -0
  298. package/src/components/ui/input/index.ts +1 -0
  299. package/src/components/ui/label/Label.vue +27 -0
  300. package/src/components/ui/label/index.ts +1 -0
  301. package/src/components/ui/pagination/PaginationEllipsis.vue +22 -0
  302. package/src/components/ui/pagination/PaginationFirst.vue +29 -0
  303. package/src/components/ui/pagination/PaginationLast.vue +29 -0
  304. package/src/components/ui/pagination/PaginationNext.vue +29 -0
  305. package/src/components/ui/pagination/PaginationPrev.vue +29 -0
  306. package/src/components/ui/pagination/index.ts +10 -0
  307. package/src/components/ui/pin-input/PinInput.vue +23 -0
  308. package/src/components/ui/pin-input/PinInputGroup.vue +18 -0
  309. package/src/components/ui/pin-input/PinInputInput.vue +18 -0
  310. package/src/components/ui/pin-input/PinInputSeparator.vue +15 -0
  311. package/src/components/ui/pin-input/index.ts +4 -0
  312. package/src/components/ui/popover/Popover.vue +15 -0
  313. package/src/components/ui/popover/PopoverContent.vue +48 -0
  314. package/src/components/ui/popover/PopoverTrigger.vue +11 -0
  315. package/src/components/ui/popover/index.ts +4 -0
  316. package/src/components/ui/preview/PreviewPdf.vue +118 -0
  317. package/src/components/ui/progress/ProgressCircle.vue +27 -0
  318. package/src/components/ui/progress/SemiCircularProgressBar.vue +83 -0
  319. package/src/components/ui/progress/TotalCalories.vue +31 -0
  320. package/src/components/ui/radio-group/RadioGroup.vue +25 -0
  321. package/src/components/ui/radio-group/RadioGroupItem.vue +37 -0
  322. package/src/components/ui/radio-group/index.ts +2 -0
  323. package/src/components/ui/scroll-area/ScrollArea.vue +29 -0
  324. package/src/components/ui/scroll-area/ScrollBar.vue +30 -0
  325. package/src/components/ui/scroll-area/index.ts +2 -0
  326. package/src/components/ui/select/Select.vue +15 -0
  327. package/src/components/ui/select/SelectContent.vue +52 -0
  328. package/src/components/ui/select/SelectGroup.vue +19 -0
  329. package/src/components/ui/select/SelectInline.vue +84 -0
  330. package/src/components/ui/select/SelectItem.vue +44 -0
  331. package/src/components/ui/select/SelectItemText.vue +11 -0
  332. package/src/components/ui/select/SelectLabel.vue +13 -0
  333. package/src/components/ui/select/SelectScrollDownButton.vue +24 -0
  334. package/src/components/ui/select/SelectScrollUpButton.vue +24 -0
  335. package/src/components/ui/select/SelectSeparator.vue +17 -0
  336. package/src/components/ui/select/SelectTrigger.vue +31 -0
  337. package/src/components/ui/select/SelectTriggerCustom.vue +23 -0
  338. package/src/components/ui/select/SelectValue.vue +11 -0
  339. package/src/components/ui/select/index.ts +12 -0
  340. package/src/components/ui/separator/Separator.vue +20 -0
  341. package/src/components/ui/separator/index.ts +1 -0
  342. package/src/components/ui/sheet/Sheet.vue +14 -0
  343. package/src/components/ui/sheet/SheetClose.vue +11 -0
  344. package/src/components/ui/sheet/SheetContent.vue +48 -0
  345. package/src/components/ui/sheet/SheetDescription.vue +22 -0
  346. package/src/components/ui/sheet/SheetFooter.vue +19 -0
  347. package/src/components/ui/sheet/SheetHeader.vue +16 -0
  348. package/src/components/ui/sheet/SheetTitle.vue +22 -0
  349. package/src/components/ui/sheet/SheetTrigger.vue +11 -0
  350. package/src/components/ui/sheet/index.ts +31 -0
  351. package/src/components/ui/skeleton/Skeleton.vue +28 -0
  352. package/src/components/ui/skeleton/index.ts +1 -0
  353. package/src/components/ui/sonner/Sonner.vue +22 -0
  354. package/src/components/ui/sonner/index.ts +1 -0
  355. package/src/components/ui/star/StarRating.vue +19 -0
  356. package/src/components/ui/switch/Switch.vue +37 -0
  357. package/src/components/ui/switch/index.ts +1 -0
  358. package/src/components/ui/table/Table.vue +16 -0
  359. package/src/components/ui/table/TableBody.vue +14 -0
  360. package/src/components/ui/table/TableCaption.vue +14 -0
  361. package/src/components/ui/table/TableCell.vue +21 -0
  362. package/src/components/ui/table/TableEmpty.vue +37 -0
  363. package/src/components/ui/table/TableFooter.vue +14 -0
  364. package/src/components/ui/table/TableHead.vue +14 -0
  365. package/src/components/ui/table/TableHeader.vue +14 -0
  366. package/src/components/ui/table/TableRow.vue +14 -0
  367. package/src/components/ui/table/index.ts +8 -0
  368. package/src/components/ui/tabs/Tabs.vue +15 -0
  369. package/src/components/ui/tabs/TabsContent.vue +22 -0
  370. package/src/components/ui/tabs/TabsList.vue +25 -0
  371. package/src/components/ui/tabs/TabsTrigger.vue +27 -0
  372. package/src/components/ui/tabs/index.ts +4 -0
  373. package/src/components/ui/tags-input/TagsInput.vue +22 -0
  374. package/src/components/ui/tags-input/TagsInputInput.vue +19 -0
  375. package/src/components/ui/tags-input/TagsInputItem.vue +22 -0
  376. package/src/components/ui/tags-input/TagsInputItemDelete.vue +24 -0
  377. package/src/components/ui/tags-input/TagsInputItemText.vue +19 -0
  378. package/src/components/ui/tags-input/index.ts +5 -0
  379. package/src/components/ui/textarea/Textarea.vue +24 -0
  380. package/src/components/ui/textarea/index.ts +1 -0
  381. package/src/components/ui/tooltip/Tooltip.vue +14 -0
  382. package/src/components/ui/tooltip/TooltipContent.vue +31 -0
  383. package/src/components/ui/tooltip/TooltipProvider.vue +11 -0
  384. package/src/components/ui/tooltip/TooltipTrigger.vue +11 -0
  385. package/src/components/ui/tooltip/index.ts +4 -0
  386. package/src/composables/useAppConfig.ts +332 -0
  387. package/src/composables/useDarkMode.ts +71 -0
  388. package/src/config/app.config.ts +318 -0
  389. package/src/config/examples/ecommerce.config.ts +132 -0
  390. package/src/config/examples/generic.config.ts +132 -0
  391. package/src/config/menu.config.ts +149 -0
  392. package/src/config/my-app.config.ts +134 -0
  393. package/src/config/test-config.ts +32 -0
  394. package/src/config/theme.config.ts +250 -0
  395. package/src/docs/index.ts +21 -0
  396. package/src/docs.scss +403 -0
  397. package/src/index.d.ts +5 -0
  398. package/src/index.ts +20 -0
  399. package/src/layouts/AuthLayout.vue +68 -0
  400. package/src/layouts/DefaultLayout.vue +119 -0
  401. package/src/layouts/DocsLayout.vue +681 -0
  402. package/src/layouts/FormGlobal.vue +50 -0
  403. package/src/layouts/GlobalDialog.vue +122 -0
  404. package/src/layouts/RakorConfirmDialog.vue +95 -0
  405. package/src/layouts/SettingsLayout.vue +115 -0
  406. package/src/lib/constants.ts +2 -0
  407. package/src/lib/detail.utils.ts +213 -0
  408. package/src/lib/form.utils.ts +1009 -0
  409. package/src/lib/page.flow.utils.ts +81 -0
  410. package/src/lib/page.utils.ts +865 -0
  411. package/src/lib/performance.utils.ts +302 -0
  412. package/src/lib/tablerow.utils.ts +51 -0
  413. package/src/lib/utils.ts +643 -0
  414. package/src/main.scss +717 -0
  415. package/src/main.ts +74 -0
  416. package/src/menu.ts +78 -0
  417. package/src/nestedlist_color.scss +161 -0
  418. package/src/router/index.ts +92 -0
  419. package/src/stores/auth.ts +117 -0
  420. package/src/stores/counter.ts +12 -0
  421. package/src/stores/dialog.ts +168 -0
  422. package/src/stores/form.ts +103 -0
  423. package/src/stores/tabs.ts +52 -0
  424. package/src/tw.scss +419 -0
  425. package/src/types/form.types.ts +348 -0
  426. package/src/types/types.ts +7 -0
  427. package/src/utils/config.utils.ts +149 -0
  428. package/src/views/NotFound.vue +30 -0
  429. package/src/views/PageActivity.vue +15 -0
  430. package/src/views/auth/LoginView.vue +7 -0
  431. package/src/views/auth/OauthCallback.vue +101 -0
  432. package/src/views/dashboard/index.vue +16 -0
  433. package/src/views/settings/AccountSettingsView.vue +70 -0
  434. package/src/views/settings/AuditLogsSettingsView.vue +116 -0
  435. package/src/views/settings/DeviceSettingsView.vue +70 -0
  436. package/src/views/settings/MainSettingsView.vue +12 -0
  437. package/src/views/settings/ProfileSettingsView.vue +104 -0
  438. package/src/vueform/config/informasi-gudang.ts +47 -0
  439. package/src/vueform/config/test-schema.ts +8 -0
  440. package/src/vueform/config/types.ts +768 -0
  441. package/src/vueform/customization/classes.js +46 -0
  442. package/src/vueform/customization/tailwind.classes.js +2117 -0
  443. package/src/vueform/elements/ConfigDataSelectorElement.vue +50 -0
  444. package/src/vueform/elements/DateSelectorElement.vue +323 -0
  445. package/src/vueform/elements/SelectorElement.vue +153 -0
  446. package/src/vueform/schemas/date-selector-test.ts +103 -0
  447. package/src/vueform/schemas/informasi-gudang.ts +160 -0
  448. package/src/vueform/schemas/test-schema.ts +483 -0
  449. package/src/vueform.config.js +77 -0
  450. package/src/vueform.validator.ts +77 -0
@@ -0,0 +1,806 @@
1
+ <script setup lang="ts">
2
+ import { onBeforeMount, onMounted, ref } from "vue";
3
+ import { cn } from "@/lib/utils";
4
+ import api from "@/api/api";
5
+ import { customAlphabet } from "nanoid";
6
+ import { PinInput, PinInputGroup, PinInputInput } from "@/components/ui/pin-input";
7
+ import BtnPrimary from "@/components/button/BtnPrimary.vue";
8
+ import BtnSecondary from "@/components/button/BtnSecondary.vue";
9
+ import { LucideX, Eye, EyeOff, LucideArrowLeft, LucideOctagonAlert } from "lucide-vue-next";
10
+ import BtnCircle from "@/components/button/BtnCircle.vue";
11
+ import PwdScore from "@/components/forms/auth/PwdScore.vue";
12
+ import { useRoute } from "vue-router";
13
+ import LoadingIndicator from "@/components/loadings/LoadingIndicator.vue";
14
+ import { useAuthStore } from "@/stores/auth";
15
+ import { useAppConfig } from "@/composables/useAppConfig";
16
+ import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle } from "@/components/ui/alert-dialog";
17
+ import PrivacyPolicy from "@/components/helper/PrivacyPolicy.vue";
18
+ import { Slide } from "go-captcha-vue";
19
+ import "go-captcha-vue/dist/style.css";
20
+
21
+ const route = useRoute();
22
+ const showPassword = ref(false);
23
+
24
+ // Initialize stores and configuration
25
+ const authStore = useAuthStore();
26
+ const { tokenKey, userKey, organizationKey, apiEndpoints } = useAppConfig();
27
+ const loginError = ref(null);
28
+ const isLoading = ref(false);
29
+ const isOtpLoading = ref(false);
30
+ const loginEmail = ref("");
31
+ const loginPwd = ref("");
32
+ const grecaptchaSiteKey = ref("");
33
+ const state = ref("login");
34
+ const changePwdType = ref("default");
35
+ const ssoUrl = ref("");
36
+ const initLoading = ref(true);
37
+ const initError = ref(false);
38
+ const stopingAllSession = ref(false);
39
+ const allSessionStoped = ref(false);
40
+
41
+ /**
42
+ * Soft lockout password
43
+ *
44
+ */
45
+ const lockoutInterval = ref(0);
46
+ const loginAttemp = ref(0);
47
+
48
+ /**
49
+ * Change pwd
50
+ *
51
+ */
52
+ const showPwd1 = ref(false);
53
+ const showPwd2 = ref(false);
54
+ const changePwdErr = ref<string | null>(null);
55
+ const isLoadingChangePwd = ref(false);
56
+ const pwd1Str = ref("");
57
+ const pwdScore = ref(0);
58
+
59
+ /**
60
+ * Forgot pwd
61
+ *
62
+ */
63
+ const forgotPwdErr = ref<string | null>(null);
64
+ const forgotPwdEmail = ref("");
65
+ const forgotPwdPwd = ref("");
66
+
67
+ /**
68
+ * OTP
69
+ *
70
+ */
71
+ const otp = ref<string[]>([]);
72
+ const resendInterval = ref(0);
73
+ const resendTried = ref(0);
74
+ const sendingOtpEmail = ref(false);
75
+ const otpEmailSent = ref(false);
76
+ const otpCompleted = () => {
77
+ sendOtp();
78
+ };
79
+
80
+ function sendOtp() {
81
+ isOtpLoading.value = true;
82
+ let uri = apiEndpoints.value.auth.login + "/otp";
83
+ let email = loginEmail.value;
84
+ if (state.value === "forgot_pwd_otp") {
85
+ uri = apiEndpoints.value.auth.forgotPassword + "/otp";
86
+ email = forgotPwdEmail.value;
87
+ }
88
+ api
89
+ .post(uri, {
90
+ email,
91
+ code: otp.value.join("")
92
+ })
93
+ .then(r => {
94
+ if (state.value === "forgot_pwd_otp") {
95
+ state.value = "change_pwd";
96
+ return;
97
+ }
98
+
99
+ // Login successfull, redirect to home
100
+ if (r.data.auth_token) localStorage.setItem(tokenKey.value, r.data.auth_token);
101
+ localStorage.setItem(userKey.value, r.data.user.name);
102
+ localStorage.setItem("app.user.default_app", r.data.user.defaultApp);
103
+
104
+ if (r.data.user.organization) localStorage.setItem(organizationKey.value, r.data.user.organization.name);
105
+ if (r.data.user.organization && r.data.user.organization.accessLevel) {
106
+ localStorage.setItem("app.user.organization.level", r.data.user.organization.accessLevel.code);
107
+ }
108
+
109
+ // Initialize WebSocket connection after successful login
110
+ // try {
111
+ // websocketStore.connect();
112
+ // } catch (error) {
113
+ // console.warn("Failed to initialize WebSocket connection:", error);
114
+ // }
115
+
116
+ const nextUri = r.data.user.defaultApp === "app1" ? "/dashboard/profile-sentral" : "/apk2/overview";
117
+ window.location.href =
118
+ route.query.next && String(route.query.next) !== "/" && String(route.query.next).substring(0, 1) === "/" && String(route.query.next).substring(0, 2) !== "//"
119
+ ? String(route.query.next)
120
+ : nextUri;
121
+ })
122
+ .catch(err => {
123
+ if (err.response && err.response.status === 406) {
124
+ changePwdType.value = err.response.data.type;
125
+ state.value = "change_pwd_default";
126
+ } else {
127
+ loginError.value = err.message;
128
+ }
129
+ })
130
+ .finally(() => {
131
+ isOtpLoading.value = false;
132
+ });
133
+ }
134
+
135
+ function loginSso() {
136
+ /**
137
+ * Save next routes
138
+ *
139
+ */
140
+ const afterLogin = route.query.next && String(route.query.next) !== "/" ? String(route.query.next) : "/";
141
+ sessionStorage.setItem("app.next", afterLogin);
142
+
143
+ /**
144
+ * Redirect to oauth login
145
+ *
146
+ */
147
+ window.location.href = ssoUrl.value;
148
+ }
149
+
150
+ function doLogin(e: any) {
151
+ // openCaptcha();
152
+ // privacyPolicyOpen.value = true;
153
+ // return;
154
+
155
+ try {
156
+ isLoading.value = true;
157
+ loginError.value = null;
158
+ sendingOtpEmail.value = true;
159
+ otpEmailSent.value = false;
160
+ captchaX.value = e.x;
161
+ captchaY.value = e.y;
162
+
163
+ api
164
+ .post(apiEndpoints.value.auth.login, {
165
+ email: loginEmail.value,
166
+ password: loginPwd.value,
167
+ captchaKey: captchaData.value.captKey,
168
+ captchaX: e.x,
169
+ captchaY: e.y
170
+ })
171
+ .then(r => {
172
+ /**
173
+ * User requried to verify email
174
+ *
175
+ */
176
+ if (!r.data.user) {
177
+ otp.value = [];
178
+ state.value = "login_otp";
179
+ resendTried.value += 1;
180
+ resendInterval.value = 15 * resendTried.value + 1;
181
+ otpEmailSent.value = true;
182
+ setTimeout(() => {
183
+ otpEmailSent.value = false;
184
+ updateInterval();
185
+ }, 2400);
186
+ return;
187
+ }
188
+
189
+ /**
190
+ * Login successfull, redirect to home
191
+ *
192
+ */
193
+ if (r.data.auth_token) localStorage.setItem(tokenKey.value, r.data.auth_token);
194
+ localStorage.setItem(userKey.value, r.data.user.name);
195
+ localStorage.setItem("app.user.default_app", r.data.user.defaultApp);
196
+
197
+ if (r.data.user.organization) localStorage.setItem(organizationKey.value, r.data.user.organization.name);
198
+ if (r.data.user.organization && r.data.user.organization.accessLevel) {
199
+ localStorage.setItem("app.user.organization.level", r.data.user.organization.accessLevel.code);
200
+ }
201
+
202
+ const nextUri = r.data.user.defaultApp === "app1" ? "/" : "/";
203
+ window.location.href =
204
+ route.query.next && String(route.query.next) !== "/" && String(route.query.next).substring(0, 1) === "/" && String(route.query.next).substring(0, 2) !== "//"
205
+ ? String(route.query.next)
206
+ : nextUri;
207
+ })
208
+ .catch(err => {
209
+ if (err.response && err.response.status === 406) {
210
+ changePwdType.value = err.response.data.type;
211
+ state.value = "change_pwd_default";
212
+ } else {
213
+ loginError.value = err.message;
214
+ loginAttemp.value += 1;
215
+ if (loginAttemp.value >= 3) {
216
+ lockoutInterval.value = 5 * loginAttemp.value + 1;
217
+ updateLockoutInterval();
218
+ }
219
+ }
220
+ })
221
+ .finally(() => {
222
+ isLoading.value = false;
223
+ sendingOtpEmail.value = false;
224
+ });
225
+ } catch (err: any) {
226
+ console.error(err);
227
+ isLoading.value = false;
228
+ loginError.value = err.message;
229
+ }
230
+ }
231
+
232
+ function login(_: FormData, form$: any) {
233
+ loginEmail.value = form$.data.email.toLowerCase();
234
+ loginPwd.value = form$.data.password;
235
+ openCaptcha();
236
+ }
237
+
238
+ function resendOtp() {
239
+ if (state.value === "forgot_pwd_otp") doSendForgotPwdEmail();
240
+ else login(new FormData(), { data: { email: loginEmail.value, password: loginPwd.value } });
241
+ }
242
+
243
+ function updateInterval() {
244
+ if (!resendInterval.value) return;
245
+ resendInterval.value -= 1;
246
+ setTimeout(() => {
247
+ updateInterval();
248
+ }, 1000);
249
+ }
250
+
251
+ function updateLockoutInterval() {
252
+ if (!lockoutInterval.value) return;
253
+ lockoutInterval.value -= 1;
254
+ setTimeout(() => {
255
+ updateLockoutInterval();
256
+ }, 1000);
257
+ }
258
+
259
+ function forgotPwd(formData: FormData, form$: any) {
260
+ forgotPwdEmail.value = form$.data.email.toLowerCase();
261
+ doSendForgotPwdEmail();
262
+ }
263
+
264
+ function doSendForgotPwdEmail() {
265
+ sendingOtpEmail.value = true;
266
+ otpEmailSent.value = false;
267
+ api
268
+ .post(apiEndpoints.value.auth.forgotPassword, {
269
+ email: forgotPwdEmail.value
270
+ })
271
+ .then(r => {
272
+ state.value = "forgot_pwd_otp";
273
+ resendTried.value += 1;
274
+ resendInterval.value = 15 * resendTried.value + 1;
275
+ otpEmailSent.value = true;
276
+ setTimeout(() => {
277
+ otpEmailSent.value = false;
278
+ updateInterval();
279
+ }, 2400);
280
+ })
281
+ .catch(err => {
282
+ forgotPwdErr.value = err.message;
283
+ })
284
+ .finally(() => {
285
+ sendingOtpEmail.value = false;
286
+ });
287
+ }
288
+
289
+ function stopAllSession() {
290
+ if (allSessionStoped.value) return;
291
+ stopingAllSession.value = true;
292
+ api
293
+ .post(apiEndpoints.value.auth.changePassword + "/stop-all-session", {
294
+ email: forgotPwdEmail.value,
295
+ password: forgotPwdPwd.value
296
+ })
297
+ .then(r => {
298
+ allSessionStoped.value = true;
299
+ })
300
+ .finally(() => {
301
+ stopingAllSession.value = false;
302
+ });
303
+ }
304
+
305
+ function changePwd(formData: FormData, form$: any) {
306
+ if (pwdScore.value < 4) {
307
+ changePwdErr.value = "Mohon gunakan password yang lebih sulit untuk ditebak";
308
+ return;
309
+ }
310
+ if (form$.data.password1 !== form$.data.password2) {
311
+ changePwdErr.value = "Kata sandi dan ulangi kata sandi tidak sama";
312
+ return;
313
+ }
314
+ isLoadingChangePwd.value = true;
315
+ let uri = apiEndpoints.value.auth.changePassword + "/default";
316
+ let email = loginEmail.value;
317
+ if (state.value === "change_pwd") {
318
+ uri = apiEndpoints.value.auth.changePassword + "/otp";
319
+ email = forgotPwdEmail.value;
320
+ }
321
+ forgotPwdPwd.value = form$.data.password1;
322
+ api
323
+ .post(uri, {
324
+ email,
325
+ code: otp.value.join(""),
326
+ password: forgotPwdPwd.value
327
+ })
328
+ .then(r => {
329
+ if (state.value === "change_pwd") {
330
+ state.value = "change_pwd_success";
331
+ allSessionStoped.value = false;
332
+ stopingAllSession.value = false;
333
+ loginError.value = null;
334
+ return;
335
+ }
336
+
337
+ // Login successfull, redirect to home
338
+ if (r.data.auth_token) localStorage.setItem(tokenKey.value, r.data.auth_token);
339
+ localStorage.setItem(userKey.value, r.data.user.name);
340
+ localStorage.setItem("app.user.default_app", r.data.user.defaultApp);
341
+
342
+ if (r.data.user.organization) localStorage.setItem(organizationKey.value, r.data.user.organization.name);
343
+ if (r.data.user.organization && r.data.user.organization.accessLevel) {
344
+ localStorage.setItem("app.user.organization.level", r.data.user.organization.accessLevel.code);
345
+ }
346
+
347
+ // Initialize WebSocket connection after successful login
348
+ // try {
349
+ // websocketStore.connect();
350
+ // } catch (error) {
351
+ // console.warn("Failed to initialize WebSocket connection:", error);
352
+ // }
353
+
354
+ const nextUri = r.data.user.defaultApp === "app1" ? "/" : "/";
355
+ window.location.href =
356
+ route.query.next && String(route.query.next) !== "/" && String(route.query.next).substring(0, 1) === "/" && String(route.query.next).substring(0, 2) !== "//"
357
+ ? String(route.query.next)
358
+ : nextUri;
359
+ })
360
+ .catch(err => {
361
+ changePwdErr.value = err.message;
362
+ })
363
+ .finally(() => {
364
+ isLoadingChangePwd.value = false;
365
+ });
366
+ }
367
+
368
+ function pwd1Inputed(e: any) {
369
+ changePwdErr.value = null;
370
+ pwd1Str.value = e.target.value;
371
+ }
372
+
373
+ function openForgotPwd() {
374
+ state.value = "forgot_pwd";
375
+ otp.value = [];
376
+ loginError.value = null;
377
+ }
378
+
379
+ /**
380
+ * Captcha
381
+ *
382
+ */
383
+ const captchaOpen = ref(false);
384
+ const captchaX = ref(0);
385
+ const captchaY = ref(0);
386
+ const captchaData = ref({
387
+ image: "",
388
+ thumb: "",
389
+ captKey: "",
390
+ thumbX: 0,
391
+ thumbY: 0,
392
+ thumbWidth: 0,
393
+ thumbHeight: 0
394
+ });
395
+ const captchaEvents = {
396
+ close: () => {
397
+ captchaOpen.value = false;
398
+ },
399
+ refresh: () => {
400
+ openCaptcha();
401
+ },
402
+ confirm: (e: any) => {
403
+ captchaOpen.value = false;
404
+ doLogin(e);
405
+ }
406
+ };
407
+
408
+ function openCaptcha() {
409
+ captchaOpen.value = true;
410
+ api.get(apiEndpoints.value.auth.captcha).then(r => {
411
+ captchaData.value = {
412
+ image: r.data.data.image_base64 || "",
413
+ thumb: r.data.data.tile_base64 || "",
414
+ captKey: r.data.data.captcha_key || "",
415
+ thumbX: r.data.data.tile_x || 0,
416
+ thumbY: r.data.data.tile_y || 0,
417
+ thumbWidth: r.data.data.tile_width || 0,
418
+ thumbHeight: r.data.data.tile_height || 0
419
+ };
420
+ });
421
+ }
422
+
423
+ /**
424
+ * Privacy policy
425
+ *
426
+ */
427
+ const privacyPolicyOpen = ref(false);
428
+ const privacyToken = ref<string | null>(null);
429
+ const privacyPolicyCanAgree = ref(false);
430
+
431
+ function privacyPolicyScrolled(e: any) {
432
+ // Hitung jika sudah mencapai bagian bawah elemen
433
+ const isAtBottom = e.target.scrollHeight - e.target.scrollTop <= e.target.clientHeight + 200;
434
+ if (isAtBottom) privacyPolicyCanAgree.value = true;
435
+ }
436
+
437
+ function agreePrivacy() {
438
+ initLoading.value = true;
439
+ // api.post('/auth/login/privacy/accept', {
440
+ // email: loginEmail.value,
441
+ // password: loginPwd.value,
442
+ // token: privacyToken.value,
443
+ // }).then(r => {
444
+ // if (state.value === 'forgot_pwd_otp') {
445
+ // otpToken.value = r.data.token
446
+ // state.value = 'change_pwd'
447
+ // return
448
+ // }
449
+
450
+ // /**
451
+ // * Login successful, set auth data and redirect to /pemilik
452
+ // *
453
+ // */
454
+ // localStorage.setItem('biomassa.user.name', r.data.nama)
455
+ // localStorage.setItem('biomassa.user.type', r.data.tipe_user)
456
+
457
+ // let path = '/';
458
+ // switch (r.data.tipe_user) {
459
+ // case 'SUPER_ADMIN':
460
+ // case 'ADMIN':
461
+ // path = '/master-user';
462
+ // break;
463
+ // case 'PEMETAAN_LAHAN':
464
+ // case 'MONITORING':
465
+ // path = '/peta-sebaran'; break;
466
+ // default: break;
467
+ // };
468
+ // router.push({ path });
469
+ // console.log('Login successful')
470
+ // }).catch(err => {
471
+ // handleLoginError(err);
472
+ // }).finally(() => {
473
+ // initLoading.value = false
474
+ // })
475
+ }
476
+
477
+ function disagreePrivacy() {
478
+ initLoading.value = true;
479
+ api
480
+ .post("/auth/login/privacy/not-accept", {
481
+ email: loginEmail.value,
482
+ password: loginPwd.value,
483
+ token: privacyToken.value
484
+ })
485
+ .finally(() => {
486
+ privacyToken.value = null;
487
+ initLoading.value = false;
488
+ });
489
+ }
490
+
491
+ function initLogin() {
492
+ initLoading.value = true;
493
+ initError.value = false;
494
+ api
495
+ .get(apiEndpoints.value.auth.init)
496
+ .then(r => {
497
+ /**
498
+ * Used to prevent CSRF attacks by
499
+ * ensuring the response matches the initial request
500
+ *
501
+ */
502
+ const { state } = r.data;
503
+
504
+ /**
505
+ * Save one-time only state
506
+ *
507
+ */
508
+ sessionStorage.setItem("oauth_state", state);
509
+
510
+ /**
511
+ * Save sso authorize url
512
+ *
513
+ */
514
+ ssoUrl.value = r.data.ssoUrl;
515
+ })
516
+ .catch(err => {
517
+ initError.value = true;
518
+ })
519
+ .finally(() => {
520
+ initLoading.value = false;
521
+ });
522
+ }
523
+
524
+ onMounted(() => {
525
+ initLogin();
526
+ });
527
+ </script>
528
+
529
+ <template>
530
+ <section v-if="initLoading" class="flex h-[440px] items-center justify-center">
531
+ <LoadingIndicator class="scale-90" />
532
+ </section>
533
+ <section v-else-if="initError" class="flex h-[440px] items-center justify-center">
534
+ <div class="text-center text-red-500">
535
+ <LucideOctagonAlert :size="40" :stroke-width="1.5" class="mx-auto mb-3" />
536
+ <h4 class="text-lg font-medium">Login Initilization Failed</h4>
537
+ <p class="mb-4 text-sm">Can not connect to Server, please check again your internet connection</p>
538
+ <BtnPrimary class="h-9 rounded-full py-0" v-on:click="initLogin">Coba Lagi</BtnPrimary>
539
+ </div>
540
+ </section>
541
+ <section v-else-if="['change_pwd_default', 'change_pwd'].includes(state)">
542
+ <div class="mb-4 flex flex-col space-y-2 text-left">
543
+ <h1 class="mb-[2px] text-2xl font-semibold leading-none">Ganti Kata Sandi</h1>
544
+ <p class="!mt-1 mb-4 text-[15px] leading-snug text-muted-foreground">
545
+ <template v-if="state === 'change_pwd_default'">
546
+ <template v-if="changePwdType === 'expired'"> Kata sandi Anda sudah kadaluarsa, anda harus mengganti kata sandi dengan kata sandi baru untuk masuk ke aplikasi. </template>
547
+ <template v-else>Kata sandi awal hanya dapat digunakan sekali. Silahkan masukan kata sandi baru.</template>
548
+ </template>
549
+ <template v-else>Silahkan masukan kata sandi baru.</template>
550
+ </p>
551
+ </div>
552
+ <div :class="cn('grid gap-6', $attrs.class ?? '')">
553
+ <div class="relative -mb-1 rounded-sm border-l-4 border-red-400 bg-red-50 px-4 py-2 pr-16 text-[15px] leading-tight text-red-500" v-if="changePwdErr">
554
+ <span>{{ changePwdErr }}</span>
555
+ <BtnCircle class="absolute right-2 top-1/2 h-6 w-6 -translate-y-1/2 bg-gray-200 opacity-70 transition hover:bg-slate-300 hover:opacity-100" v-on:click="changePwdErr = null">
556
+ <LucideX :size="16"></LucideX>
557
+ </BtnCircle>
558
+ </div>
559
+ <Vueform :endpoint="changePwd">
560
+ <TextElement
561
+ name="password1"
562
+ :input-type="showPwd1 ? 'text' : 'password'"
563
+ label="Kata Sandi Baru"
564
+ placeholder="Masukkan kata sandi..."
565
+ :floating="false"
566
+ :rules="['required']"
567
+ v-on:input="pwd1Inputed"
568
+ onpaste="return false;">
569
+ <template #addon-after>
570
+ <EyeOff :size="22" v-if="showPwd1" class="cursor-pointer text-slate-400" @click="showPwd1 = false" />
571
+ <Eye :size="22" v-else class="cursor-pointer text-slate-400" @click="showPwd1 = true" />
572
+ </template>
573
+ </TextElement>
574
+ <div class="col-span-12 -mt-2.5 px-1">
575
+ <PwdScore v-model="pwdScore" :password="pwd1Str" />
576
+ </div>
577
+ <TextElement
578
+ name="password2"
579
+ :input-type="showPwd2 ? 'text' : 'password'"
580
+ label="Ulangi Kata Sandi"
581
+ placeholder="Masukkan kata sandi..."
582
+ :floating="false"
583
+ :rules="['required']"
584
+ v-on:input="changePwdErr = null"
585
+ onpaste="return false;">
586
+ <template #addon-after>
587
+ <EyeOff :size="22" v-if="showPwd2" class="cursor-pointer text-slate-400" @click="showPwd2 = false" />
588
+ <Eye :size="22" v-else class="cursor-pointer text-slate-400" @click="showPwd2 = true" />
589
+ </template>
590
+ </TextElement>
591
+ <div class="relative col-span-12 mt-1 h-12 cursor-default overflow-hidden rounded-md !border-gray-300 !bg-gray-300 px-6 !text-gray-300 transition" v-if="isLoadingChangePwd">
592
+ <div class="bottom-0 left-0 right-0 top-0 bg-gray-300">
593
+ <svg class="absolute bottom-0 left-0 right-0 top-0 m-auto h-7 w-7 animate-spin text-black" fill="none" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
594
+ <circle class="opacity-15" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="2" />
595
+ <path class="opacity-15" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" />
596
+ </svg>
597
+ </div>
598
+ </div>
599
+ <ButtonElement size="lg" name="submit" button-class="mt-1 font-medium h-12 text-md" button-label="Tetapkan Kata Sandi" :submits="true" :full="true" v-else />
600
+ </Vueform>
601
+ </div>
602
+ </section>
603
+ <section v-else-if="['forgot_pwd'].includes(state)">
604
+ <div class="mb-4 flex flex-col space-y-2 text-left">
605
+ <h1 class="mb-[2px] text-2xl font-semibold leading-none">Lupa Kata Sandi</h1>
606
+ <p class="!mt-1 mb-4 text-[15px] leading-snug text-muted-foreground">Masukan alamat email Anda yang terdaftar pada aplikasi.</p>
607
+ </div>
608
+ <button class="-ml-[3px] mb-5 flex items-center px-0 py-1 text-[15px]" v-on:click="state = 'login'">
609
+ <LucideArrowLeft class="mr-2" :size="22" />
610
+ Kembali ke Login
611
+ </button>
612
+ <div :class="cn('grid gap-6', $attrs.class ?? '')">
613
+ <div class="relative -mb-1 rounded-sm border-l-4 border-red-400 bg-red-50 px-4 py-2 pr-16 text-[15px] leading-tight text-red-500" v-if="forgotPwdErr">
614
+ <span>{{ forgotPwdErr }}</span>
615
+ <BtnCircle class="absolute right-2 top-1/2 h-6 w-6 -translate-y-1/2 bg-gray-200 opacity-70 transition hover:bg-slate-300 hover:opacity-100" v-on:click="forgotPwdErr = null">
616
+ <LucideX :size="16"></LucideX>
617
+ </BtnCircle>
618
+ </div>
619
+ <Vueform :endpoint="forgotPwd">
620
+ <TextElement name="email" input-type="email" :rules="['required']" label="Email" placeholder="Masukkan email..." :floating="false" v-on:input="forgotPwdErr = null" />
621
+ <div class="relative col-span-12 mt-1 h-12 cursor-default overflow-hidden rounded-md !border-gray-300 !bg-gray-300 px-6 !text-gray-300 transition" v-if="sendingOtpEmail">
622
+ <div class="bottom-0 left-0 right-0 top-0 bg-gray-300">
623
+ <svg class="absolute bottom-0 left-0 right-0 top-0 m-auto h-7 w-7 animate-spin text-black" fill="none" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
624
+ <circle class="opacity-15" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="2" />
625
+ <path class="opacity-15" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" />
626
+ </svg>
627
+ </div>
628
+ </div>
629
+ <ButtonElement size="lg" name="submit" button-class="mt-1 font-medium h-12 text-md" button-label="Kirimkan Email" :submits="true" :full="true" v-else />
630
+ </Vueform>
631
+ </div>
632
+ </section>
633
+ <section v-else-if="['change_pwd_success'].includes(state)">
634
+ <div class="mb-4 flex flex-col space-y-2 text-left">
635
+ <h1 class="mb-2.5 text-xl font-semibold leading-none">Kata Sandi Sukses Dirubah</h1>
636
+ <div class="!mt-1 mb-4 text-[15px] text-muted-foreground">
637
+ <p>Kata sandi berhasil di rubah, sekarang Anda dapat masuk menggunakan kata sandi baru Anda.</p>
638
+ <br />
639
+ <p>
640
+ Apakah Anda ingin menghentikan semua sesi aktif?<br />
641
+ Perangkat yang sedang aktif akan diminta untuk masuk kembali dengan password baru Anda.
642
+ </p>
643
+ </div>
644
+ </div>
645
+ <BtnPrimary class="mb-5 w-full text-[16px]" :loading="stopingAllSession" :disabled="allSessionStoped" v-on:click="stopAllSession">
646
+ <template v-if="allSessionStoped">Semua Sesi Dihentikan</template>
647
+ <template v-else>Hentikan Semua Sesi</template>
648
+ </BtnPrimary>
649
+ <button class="-ml-[3px] mb-5 flex items-center px-0 py-1 text-[15px]" v-on:click="state = 'login'">
650
+ <LucideArrowLeft class="mr-2" :size="22" />
651
+ Kembali ke Login
652
+ </button>
653
+ </section>
654
+ <section v-else-if="['login_otp', 'forgot_pwd_otp'].includes(state)">
655
+ <div class="mb-3 flex flex-col space-y-2 text-left">
656
+ <h1 class="mb-[2px] text-2xl font-semibold leading-none">Verifikasi</h1>
657
+ <p class="!mt-1 mb-4 text-[15px] text-muted-foreground">
658
+ Masukan 8 digit kode verifikasi yang dikirimkan ke email Anda
659
+ <b>
660
+ <template v-if="state === 'login_otp'"> {{ loginEmail.split("@")[0].substring(0, 2) }}***@{{ loginEmail.split("@")[1] }} </template>
661
+ <template v-if="state === 'forgot_pwd_otp'"> {{ forgotPwdEmail.split("@")[0].substring(0, 2) }}***@{{ forgotPwdEmail.split("@")[1] }} </template> </b
662
+ >.
663
+ </p>
664
+ </div>
665
+ <div :class="cn('grid gap-6', $attrs.class ?? '')">
666
+ <div class="relative -mb-1 rounded-sm border-l-4 border-red-400 bg-red-50 px-4 py-2 text-[15px] text-red-500" v-if="loginError">
667
+ <span>{{ loginError }}</span>
668
+ <BtnCircle class="absolute right-2 top-1/2 h-6 w-6 -translate-y-1/2 bg-gray-200 opacity-70 transition hover:bg-slate-300 hover:opacity-100" v-on:click="loginError = null">
669
+ <LucideX :size="16"></LucideX>
670
+ </BtnCircle>
671
+ </div>
672
+ <PinInput id="otp-input" v-model="otp" placeholder="○" @complete="otpCompleted" :otp="true">
673
+ <PinInputGroup class="gap-1.5">
674
+ <template v-for="(id, index) in 8" :key="id">
675
+ <PinInputInput class="w-full rounded-md border py-3 text-xl" :index="index" />
676
+ </template>
677
+ </PinInputGroup>
678
+ </PinInput>
679
+ <div class="-mt-4 pl-2">
680
+ <div class="py-1 text-sm text-gray-400" v-if="sendingOtpEmail">Mengirimkan email...</div>
681
+ <div class="py-1 text-sm text-gray-400" v-else-if="otpEmailSent">Email terkirim!</div>
682
+ <button class="hover:text-primary_main_hover px-0 py-1 text-sm font-medium text-primary_main" v-else-if="!resendInterval" v-on:click="resendOtp">Kirim ulang email</button>
683
+ <div class="py-1 text-sm text-gray-400" v-else>Kirimkan ulang dalam {{ resendInterval }}</div>
684
+ </div>
685
+ <BtnPrimary class="text-md h-12 w-full" v-on:click="sendOtp" :loading="isOtpLoading"> Verifikasi Kode </BtnPrimary>
686
+ </div>
687
+ </section>
688
+ <section v-else>
689
+ <div class="mb-3 flex flex-col space-y-2 text-left">
690
+ <h1 class="mb-[2px] text-2xl font-semibold leading-none">Login</h1>
691
+ <p class="!mt-1 mb-4 text-[15px] text-muted-foreground">Silakan login terlebih dahulu untuk masuk aplikasi.</p>
692
+ </div>
693
+ <div :class="cn('grid gap-6', $attrs.class ?? '')">
694
+ <div class="relative -mb-1 rounded-sm border-l-4 border-red-400 bg-red-50 px-4 py-2 text-[15px] text-red-500" v-if="loginError">
695
+ <span>{{ loginError }}</span>
696
+ <BtnCircle class="absolute right-2 top-1/2 h-6 w-6 -translate-y-1/2 bg-gray-200 opacity-70 transition hover:bg-slate-300 hover:opacity-100" v-on:click="loginError = null">
697
+ <LucideX :size="16"></LucideX>
698
+ </BtnCircle>
699
+ </div>
700
+ <Vueform :endpoint="login">
701
+ <TextElement name="email" input-type="email" :rules="['required']" label="Email" placeholder="Masukkan email..." :floating="false" v-on:input="loginError = null" />
702
+ <TextElement
703
+ name="password"
704
+ :input-type="showPassword ? 'text' : 'password'"
705
+ label="Kata Sandi"
706
+ placeholder="Masukkan kata sandi..."
707
+ :floating="false"
708
+ :rules="['required']"
709
+ v-on:input="loginError = null"
710
+ onpaste="return false;">
711
+ <template #addon-after>
712
+ <EyeOff :size="22" v-if="showPassword" class="cursor-pointer text-slate-400" @click="showPassword = false" />
713
+ <Eye :size="22" v-else class="cursor-pointer text-slate-400" @click="showPassword = true" />
714
+ </template>
715
+ </TextElement>
716
+ <div class="col-span-12 -mt-2 mb-5">
717
+ <button class="hover:text-primary_main_hover ml-1 text-sm font-semibold text-primary_main" type="button" v-on:click="openForgotPwd">Lupa Kata Sandi?</button>
718
+ </div>
719
+ <div class="relative col-span-12 mt-1 h-12 cursor-default overflow-hidden rounded-md !border-gray-300 !bg-gray-300 px-6 !text-gray-300 transition" v-if="isLoading">
720
+ <div class="absolute bottom-0 left-0 right-0 top-0 bg-gray-300">
721
+ <svg class="absolute bottom-0 left-0 right-0 top-0 m-auto h-7 w-7 animate-spin text-black" fill="none" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
722
+ <circle class="opacity-15" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="2" />
723
+ <path class="opacity-15" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" />
724
+ </svg>
725
+ </div>
726
+ </div>
727
+ <div class="relative col-span-12 mt-1 h-12 cursor-default overflow-hidden rounded-md !border-gray-300 !bg-gray-300 px-6 !text-gray-300 transition" v-else-if="lockoutInterval">
728
+ <div class="absolute bottom-0 left-0 right-0 top-0 flex items-center justify-center bg-gray-200 leading-tight text-gray-400">
729
+ <div class="text-center">
730
+ <h4 class="text-[16px] font-medium">Akun terkunci</h4>
731
+ <p class="text-xs">Anda dapat login kembali dalam {{ lockoutInterval }}</p>
732
+ </div>
733
+ </div>
734
+ </div>
735
+ <ButtonElement
736
+ size="lg"
737
+ name="submit"
738
+ button-class="mt-1 font-medium h-11 !py-0 text-md !bg-blue-500 hover:!bg-blue-600 !transition !border-none"
739
+ button-label="Login Non-SSO"
740
+ :submits="true"
741
+ :full="true"
742
+ v-else />
743
+ </Vueform>
744
+ <div class="relative -mb-3 -mt-5">
745
+ <div class="absolute inset-0 flex items-center">
746
+ <span class="w-full border-t border-slate-300 dark:border-dark_border2"></span>
747
+ </div>
748
+ <div class="relative flex justify-center pt-1.5 text-sm">
749
+ <span class="bg-slate-100 px-2 text-muted-foreground text-slate-400 dark:bg-dark_bg dark:text-gray-500"> Atau login dengan </span>
750
+ </div>
751
+ </div>
752
+ <BtnSecondary
753
+ class="text-md h-11 border border-gray-200 bg-white !py-0 hover:shadow-sm dark:border-none dark:bg-dark_bg4 dark:text-dark_text dark:hover:bg-dark_bg6"
754
+ type="button"
755
+ v-on:click="loginSso">
756
+ Login SSO
757
+ </BtnSecondary>
758
+ </div>
759
+ </section>
760
+ <div :data-sitekey="grecaptchaSiteKey" class="g-recaptcha" data-size="invisible"></div>
761
+
762
+ <div class="fixed bottom-0 left-0 right-0 top-0 z-[99] !m-0 flex items-center justify-center bg-black/60" v-if="captchaOpen">
763
+ <Slide
764
+ :config="{
765
+ title: 'Verifikasi bukan robot',
766
+ buttonText: 'Verifikasi'
767
+ }"
768
+ :data="captchaData"
769
+ :events="captchaEvents"
770
+ ref="domRef" />
771
+ </div>
772
+
773
+ <!-- Privacy policy -->
774
+ <AlertDialog v-model:open="privacyPolicyOpen">
775
+ <AlertDialogContent class="w-full max-w-[940px]">
776
+ <AlertDialogHeader>
777
+ <AlertDialogTitle>Setujui Privacy Policy</AlertDialogTitle>
778
+ <AlertDialogDescription>
779
+ <div class="-mx-6">
780
+ <section class="h-[80vh] w-full overflow-auto border-b border-t" v-on:scroll="privacyPolicyScrolled">
781
+ <div class="px-6 pb-10 pt-4">
782
+ <PrivacyPolicy />
783
+ </div>
784
+ </section>
785
+ </div>
786
+ </AlertDialogDescription>
787
+ </AlertDialogHeader>
788
+ <AlertDialogFooter>
789
+ <AlertDialogCancel
790
+ class="h-10 border-none px-5 text-base font-medium text-gray-500 shadow-none hover:bg-slate-100 hover:text-slate-600"
791
+ :class="{ '!text-gray-300 hover:!bg-white': !privacyPolicyCanAgree }"
792
+ v-on:click="disagreePrivacy"
793
+ :disabled="!privacyPolicyCanAgree">
794
+ Tidak Setuju
795
+ </AlertDialogCancel>
796
+ <AlertDialogAction
797
+ class="h-10 border-none px-5 text-base font-medium shadow-none"
798
+ :class="{ '!bg-gray-200 !text-gray-400': !privacyPolicyCanAgree }"
799
+ v-on:click="agreePrivacy"
800
+ :disabled="!privacyPolicyCanAgree">
801
+ Setuju
802
+ </AlertDialogAction>
803
+ </AlertDialogFooter>
804
+ </AlertDialogContent>
805
+ </AlertDialog>
806
+ </template>