説明なし
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

laravel-user-management.js 28KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762
  1. /**
  2. * Page User management
  3. */
  4. 'use strict';
  5. // Datatable (js)
  6. document.addEventListener('DOMContentLoaded', function (e) {
  7. let borderColor, bodyBg, headingColor;
  8. borderColor = config.colors.borderColor;
  9. bodyBg = config.colors.bodyBg;
  10. headingColor = config.colors.headingColor;
  11. // Variable declaration for table
  12. const dt_user_table = document.querySelector('.datatables-users'),
  13. userView = baseUrl + 'app/user/view/account',
  14. offCanvasForm = document.getElementById('offcanvasAddUser');
  15. // Select2 initialization
  16. var select2 = $('.select2');
  17. if (select2.length) {
  18. var $this = select2;
  19. $this.wrap('<div class="position-relative"></div>').select2({
  20. placeholder: 'Select Country',
  21. dropdownParent: $this.parent()
  22. });
  23. }
  24. // ajax setup
  25. $.ajaxSetup({
  26. headers: {
  27. 'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
  28. }
  29. });
  30. // Users datatable
  31. if (dt_user_table) {
  32. const dt_user = new DataTable(dt_user_table, {
  33. processing: true,
  34. serverSide: true,
  35. ajax: {
  36. url: baseUrl + 'user-list',
  37. dataSrc: function (json) {
  38. // Ensure recordsTotal and recordsFiltered are numeric and not undefined/null
  39. if (typeof json.recordsTotal !== 'number') {
  40. json.recordsTotal = 0;
  41. }
  42. if (typeof json.recordsFiltered !== 'number') {
  43. json.recordsFiltered = 0;
  44. }
  45. // Fallback for empty data to avoid pagination NaN issue
  46. json.data = Array.isArray(json.data) ? json.data : [];
  47. return json.data;
  48. }
  49. },
  50. columns: [
  51. // columns according to JSON
  52. { data: 'id' },
  53. { data: 'id' },
  54. { data: 'name' },
  55. { data: 'email' },
  56. { data: 'email_verified_at' },
  57. { data: 'action' }
  58. ],
  59. columnDefs: [
  60. {
  61. // For Responsive
  62. className: 'control',
  63. searchable: false,
  64. orderable: false,
  65. responsivePriority: 2,
  66. targets: 0,
  67. render: function (data, type, full, meta) {
  68. return '';
  69. }
  70. },
  71. {
  72. searchable: false,
  73. orderable: false,
  74. targets: 1,
  75. render: function (data, type, full, meta) {
  76. return `<span>${full.fake_id}</span>`;
  77. }
  78. },
  79. {
  80. // User full name
  81. targets: 2,
  82. responsivePriority: 4,
  83. render: function (data, type, full, meta) {
  84. const { name } = full; // Destructuring to get 'name' from the 'full' object
  85. // For Avatar badge
  86. const stateNum = Math.floor(Math.random() * 6);
  87. const states = ['success', 'danger', 'warning', 'info', 'dark', 'primary', 'secondary'];
  88. const state = states[stateNum];
  89. // Extract initials from the name
  90. const initials = (name.match(/\b\w/g) || []).shift() + (name.match(/\b\w/g) || []).pop();
  91. const initialsUpper = initials.toUpperCase();
  92. // Create avatar badge using template literals
  93. const avatar = `<span class="avatar-initial rounded-circle bg-label-${state}">${initialsUpper}</span>`;
  94. // Create full output for row using template literals
  95. const rowOutput = `
  96. <div class="d-flex justify-content-start align-items-center user-name">
  97. <div class="avatar-wrapper">
  98. <div class="avatar avatar-sm me-4">
  99. ${avatar}
  100. </div>
  101. </div>
  102. <div class="d-flex flex-column">
  103. <a href="${userView}" class="text-truncate text-heading">
  104. <span class="fw-medium">${name}</span>
  105. </a>
  106. </div>
  107. </div>
  108. `;
  109. // Return the final output as HTML string
  110. return rowOutput;
  111. }
  112. },
  113. {
  114. // User email
  115. targets: 3,
  116. render: function (data, type, full, meta) {
  117. const email = full['email'];
  118. return '<span class="user-email">' + email + '</span>';
  119. }
  120. },
  121. {
  122. // email verify
  123. targets: 4,
  124. className: 'text-center',
  125. render: function (data, type, full, meta) {
  126. const verified = full['email_verified_at'];
  127. return `${
  128. verified
  129. ? '<i class="icon-base bx fs-4 bx-check-shield text-success"></i>'
  130. : '<i class="icon-base bx fs-4 bx-shield-x text-danger" ></i>'
  131. }`;
  132. }
  133. },
  134. {
  135. // Actions
  136. targets: -1,
  137. title: 'Actions',
  138. searchable: false,
  139. orderable: false,
  140. render: function (data, type, full, meta) {
  141. return (
  142. '<div class="d-flex align-items-center gap-4">' +
  143. `<button class="btn btn-sm btn-icon edit-record" data-id="${full['id']}" data-bs-toggle="offcanvas" data-bs-target="#offcanvasAddUser"><i class="icon-base bx bx-edit icon-22px"></i></button>` +
  144. `<button class="btn btn-sm btn-icon delete-record" data-id="${full['id']}"><i class="icon-base bx bx-trash icon-22px"></i></button>` +
  145. '<button class="btn btn-sm btn-icon dropdown-toggle hide-arrow" data-bs-toggle="dropdown"><i class="icon-base bx bx-dots-vertical-rounded icon-22px"></i></button>' +
  146. '<div class="dropdown-menu dropdown-menu-end m-0">' +
  147. '<a href="' +
  148. userView +
  149. '" class="dropdown-item">View</a>' +
  150. '<a href="javascript:;" class="dropdown-item">Suspend</a>' +
  151. '</div>' +
  152. '</div>'
  153. );
  154. }
  155. }
  156. ],
  157. order: [[2, 'desc']],
  158. layout: {
  159. topStart: {
  160. rowClass: 'row m-3 my-0 justify-content-between',
  161. features: [
  162. {
  163. pageLength: {
  164. menu: [7, 10, 20, 50, 70, 100],
  165. text: '_MENU_'
  166. }
  167. }
  168. ]
  169. },
  170. topEnd: {
  171. features: [
  172. {
  173. search: {
  174. placeholder: 'Search User',
  175. text: '_INPUT_'
  176. }
  177. },
  178. {
  179. buttons: [
  180. {
  181. extend: 'collection',
  182. className: 'btn btn-label-secondary dropdown-toggle',
  183. text: '<i class="icon-base bx bx-export me-2 bx-sm"></i>Export',
  184. buttons: [
  185. {
  186. extend: 'print',
  187. title: 'Users',
  188. text: '<i class="icon-base bx bx-printer me-2" ></i>Print',
  189. className: 'dropdown-item',
  190. exportOptions: {
  191. columns: [1, 2, 3, 4, 5],
  192. // prevent avatar to be print
  193. format: {
  194. body: function (inner, coldex, rowdex) {
  195. if (inner.length <= 0) return inner;
  196. // Check if inner is HTML content
  197. if (inner.indexOf('<') > -1) {
  198. const parser = new DOMParser();
  199. const doc = parser.parseFromString(inner, 'text/html');
  200. // Get all text content
  201. let text = '';
  202. // Handle specific elements
  203. const userNameElements = doc.querySelectorAll('.user-name');
  204. if (userNameElements.length > 0) {
  205. userNameElements.forEach(el => {
  206. // Get text from nested structure
  207. const nameText =
  208. el.querySelector('.fw-medium')?.textContent ||
  209. el.querySelector('.d-block')?.textContent ||
  210. el.textContent;
  211. text += nameText.trim() + ' ';
  212. });
  213. } else {
  214. // Get regular text content
  215. text = doc.body.textContent || doc.body.innerText;
  216. }
  217. return text.trim();
  218. }
  219. return inner;
  220. }
  221. }
  222. },
  223. customize: function (win) {
  224. win.document.body.style.color = config.colors.headingColor;
  225. win.document.body.style.borderColor = config.colors.borderColor;
  226. win.document.body.style.backgroundColor = config.colors.bodyBg;
  227. const table = win.document.body.querySelector('table');
  228. table.classList.add('compact');
  229. table.style.color = 'inherit';
  230. table.style.borderColor = 'inherit';
  231. table.style.backgroundColor = 'inherit';
  232. }
  233. },
  234. {
  235. extend: 'csv',
  236. title: 'Users',
  237. text: '<i class="icon-base bx bx-file me-2" ></i>Csv',
  238. className: 'dropdown-item',
  239. exportOptions: {
  240. columns: [1, 2, 3, 4, 5],
  241. format: {
  242. body: function (inner, coldex, rowdex) {
  243. if (inner.length <= 0) return inner;
  244. // Parse HTML content
  245. const parser = new DOMParser();
  246. const doc = parser.parseFromString(inner, 'text/html');
  247. let text = '';
  248. // Handle user-name elements specifically
  249. const userNameElements = doc.querySelectorAll('.user-name');
  250. if (userNameElements.length > 0) {
  251. userNameElements.forEach(el => {
  252. // Get text from nested structure - try different selectors
  253. const nameText =
  254. el.querySelector('.fw-medium')?.textContent ||
  255. el.querySelector('.d-block')?.textContent ||
  256. el.textContent;
  257. text += nameText.trim() + ' ';
  258. });
  259. } else {
  260. // Handle other elements (status, role, etc)
  261. text = doc.body.textContent || doc.body.innerText;
  262. }
  263. return text.trim();
  264. }
  265. }
  266. }
  267. },
  268. {
  269. extend: 'excel',
  270. text: '<i class="icon-base bx bxs-file-export me-2"></i>Excel',
  271. className: 'dropdown-item',
  272. exportOptions: {
  273. columns: [1, 2, 3, 4, 5],
  274. format: {
  275. body: function (inner, coldex, rowdex) {
  276. if (inner.length <= 0) return inner;
  277. // Parse HTML content
  278. const parser = new DOMParser();
  279. const doc = parser.parseFromString(inner, 'text/html');
  280. let text = '';
  281. // Handle user-name elements specifically
  282. const userNameElements = doc.querySelectorAll('.user-name');
  283. if (userNameElements.length > 0) {
  284. userNameElements.forEach(el => {
  285. // Get text from nested structure - try different selectors
  286. const nameText =
  287. el.querySelector('.fw-medium')?.textContent ||
  288. el.querySelector('.d-block')?.textContent ||
  289. el.textContent;
  290. text += nameText.trim() + ' ';
  291. });
  292. } else {
  293. // Handle other elements (status, role, etc)
  294. text = doc.body.textContent || doc.body.innerText;
  295. }
  296. return text.trim();
  297. }
  298. }
  299. }
  300. },
  301. {
  302. extend: 'pdf',
  303. title: 'Users',
  304. text: '<i class="icon-base bx bxs-file-pdf me-2"></i>Pdf',
  305. className: 'dropdown-item',
  306. exportOptions: {
  307. columns: [1, 2, 3, 4, 5],
  308. format: {
  309. body: function (inner, coldex, rowdex) {
  310. if (inner.length <= 0) return inner;
  311. // Parse HTML content
  312. const parser = new DOMParser();
  313. const doc = parser.parseFromString(inner, 'text/html');
  314. let text = '';
  315. // Handle user-name elements specifically
  316. const userNameElements = doc.querySelectorAll('.user-name');
  317. if (userNameElements.length > 0) {
  318. userNameElements.forEach(el => {
  319. // Get text from nested structure - try different selectors
  320. const nameText =
  321. el.querySelector('.fw-medium')?.textContent ||
  322. el.querySelector('.d-block')?.textContent ||
  323. el.textContent;
  324. text += nameText.trim() + ' ';
  325. });
  326. } else {
  327. // Handle other elements (status, role, etc)
  328. text = doc.body.textContent || doc.body.innerText;
  329. }
  330. return text.trim();
  331. }
  332. }
  333. }
  334. },
  335. {
  336. extend: 'copy',
  337. title: 'Users',
  338. text: '<i class="icon-base bx bx-copy me-2" ></i>Copy',
  339. className: 'dropdown-item',
  340. exportOptions: {
  341. columns: [1, 2, 3, 4, 5],
  342. format: {
  343. body: function (inner, coldex, rowdex) {
  344. if (inner.length <= 0) return inner;
  345. // Parse HTML content
  346. const parser = new DOMParser();
  347. const doc = parser.parseFromString(inner, 'text/html');
  348. let text = '';
  349. // Handle user-name elements specifically
  350. const userNameElements = doc.querySelectorAll('.user-name');
  351. if (userNameElements.length > 0) {
  352. userNameElements.forEach(el => {
  353. // Get text from nested structure - try different selectors
  354. const nameText =
  355. el.querySelector('.fw-medium')?.textContent ||
  356. el.querySelector('.d-block')?.textContent ||
  357. el.textContent;
  358. text += nameText.trim() + ' ';
  359. });
  360. } else {
  361. // Handle other elements (status, role, etc)
  362. text = doc.body.textContent || doc.body.innerText;
  363. }
  364. return text.trim();
  365. }
  366. }
  367. }
  368. }
  369. ]
  370. },
  371. {
  372. text: '<i class="icon-base bx bx-plus icon-sm me-0 me-sm-2"></i><span class="d-none d-sm-inline-block">Add New User</span>',
  373. className: 'add-new btn btn-primary',
  374. attr: {
  375. 'data-bs-toggle': 'offcanvas',
  376. 'data-bs-target': '#offcanvasAddUser'
  377. }
  378. }
  379. ]
  380. }
  381. ]
  382. },
  383. bottomStart: {
  384. rowClass: 'row mx-3 justify-content-between',
  385. features: [
  386. {
  387. info: {
  388. text: 'Showing _START_ to _END_ of _TOTAL_ entries'
  389. }
  390. }
  391. ]
  392. },
  393. bottomEnd: 'paging'
  394. },
  395. displayLength: 7,
  396. language: {
  397. paginate: {
  398. next: '<i class="icon-base bx bx-chevron-right scaleX-n1-rtl icon-18px"></i>',
  399. previous: '<i class="icon-base bx bx-chevron-left scaleX-n1-rtl icon-18px"></i>',
  400. first: '<i class="icon-base bx bx-chevrons-left scaleX-n1-rtl icon-18px"></i>',
  401. last: '<i class="icon-base bx bx-chevrons-right scaleX-n1-rtl icon-18px"></i>'
  402. }
  403. },
  404. // For responsive popup
  405. responsive: {
  406. details: {
  407. display: DataTable.Responsive.display.modal({
  408. header: function (row) {
  409. const data = row.data();
  410. return 'Details of ' + data['name'];
  411. }
  412. }),
  413. type: 'column',
  414. renderer: function (api, rowIdx, columns) {
  415. const data = columns
  416. .map(function (col) {
  417. return col.title !== '' // Do not show row in modal popup if title is blank (for check box)
  418. ? `<tr data-dt-row="${col.rowIndex}" data-dt-column="${col.columnIndex}">
  419. <td>${col.title}:</td>
  420. <td>${col.data}</td>
  421. </tr>`
  422. : '';
  423. })
  424. .join('');
  425. if (data) {
  426. const div = document.createElement('div');
  427. div.classList.add('table-responsive');
  428. const table = document.createElement('table');
  429. div.appendChild(table);
  430. table.classList.add('table');
  431. const tbody = document.createElement('tbody');
  432. tbody.innerHTML = data;
  433. table.appendChild(tbody);
  434. return div;
  435. }
  436. return false;
  437. }
  438. }
  439. },
  440. initComplete: function () {
  441. // Remove btn-secondary from export buttons
  442. document.querySelectorAll('.dt-buttons .btn').forEach(btn => {
  443. btn.classList.remove('btn-secondary');
  444. });
  445. }
  446. });
  447. // Delete Record
  448. document.addEventListener('click', function (e) {
  449. if (e.target.closest('.delete-record')) {
  450. const deleteBtn = e.target.closest('.delete-record');
  451. const user_id = deleteBtn.dataset.id;
  452. const dtrModal = document.querySelector('.dtr-bs-modal.show');
  453. // hide responsive modal in small screen
  454. if (dtrModal) {
  455. const bsModal = bootstrap.Modal.getInstance(dtrModal);
  456. bsModal.hide();
  457. }
  458. // sweetalert for confirmation of delete
  459. Swal.fire({
  460. title: 'Are you sure?',
  461. text: "You won't be able to revert this!",
  462. icon: 'warning',
  463. showCancelButton: true,
  464. confirmButtonText: 'Yes, delete it!',
  465. customClass: {
  466. confirmButton: 'btn btn-primary me-3',
  467. cancelButton: 'btn btn-label-secondary'
  468. },
  469. buttonsStyling: false
  470. }).then(function (result) {
  471. if (result.value) {
  472. // delete the data
  473. fetch(`${baseUrl}user-list/${user_id}`, {
  474. method: 'DELETE',
  475. headers: {
  476. 'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute('content'),
  477. 'Content-Type': 'application/json'
  478. }
  479. })
  480. .then(response => {
  481. if (response.ok) {
  482. dt_user.draw();
  483. // success sweetalert
  484. Swal.fire({
  485. icon: 'success',
  486. title: 'Deleted!',
  487. text: 'The user has been deleted!',
  488. customClass: {
  489. confirmButton: 'btn btn-success'
  490. }
  491. });
  492. } else {
  493. throw new Error('Delete failed');
  494. }
  495. })
  496. .catch(error => {
  497. console.log(error);
  498. });
  499. } else if (result.dismiss === Swal.DismissReason.cancel) {
  500. Swal.fire({
  501. title: 'Cancelled',
  502. text: 'The User is not deleted!',
  503. icon: 'error',
  504. customClass: {
  505. confirmButton: 'btn btn-success'
  506. }
  507. });
  508. }
  509. });
  510. }
  511. });
  512. // edit record
  513. document.addEventListener('click', function (e) {
  514. if (e.target.closest('.edit-record')) {
  515. const editBtn = e.target.closest('.edit-record');
  516. const user_id = editBtn.dataset.id;
  517. const dtrModal = document.querySelector('.dtr-bs-modal.show');
  518. // hide responsive modal in small screen
  519. if (dtrModal) {
  520. const bsModal = bootstrap.Modal.getInstance(dtrModal);
  521. bsModal.hide();
  522. }
  523. // changing the title of offcanvas
  524. document.getElementById('offcanvasAddUserLabel').innerHTML = 'Edit User';
  525. // get data
  526. fetch(`${baseUrl}user-list/${user_id}/edit`)
  527. .then(response => response.json())
  528. .then(data => {
  529. document.getElementById('user_id').value = data.id;
  530. document.getElementById('add-user-fullname').value = data.name;
  531. document.getElementById('add-user-email').value = data.email;
  532. });
  533. }
  534. });
  535. // changing the title
  536. const addNewBtn = document.querySelector('.add-new');
  537. if (addNewBtn) {
  538. addNewBtn.addEventListener('click', function () {
  539. document.getElementById('user_id').value = ''; //resetting input field
  540. document.getElementById('offcanvasAddUserLabel').innerHTML = 'Add User';
  541. });
  542. }
  543. // Filter form control to default size
  544. setTimeout(() => {
  545. const elementsToModify = [
  546. { selector: '.dt-buttons .btn', classToRemove: 'btn-secondary' },
  547. { selector: '.dt-search .form-control', classToRemove: 'form-control-sm' },
  548. { selector: '.dt-length .form-select', classToRemove: 'form-select-sm', classToAdd: 'ms-0' },
  549. { selector: '.dt-length', classToAdd: 'mb-md-6 mb-0' },
  550. {
  551. selector: '.dt-layout-end',
  552. classToRemove: 'justify-content-between',
  553. classToAdd: 'd-flex gap-md-4 justify-content-md-between justify-content-center gap-0 flex-wrap mt-0'
  554. },
  555. { selector: '.dt-layout-start', classToAdd: 'mt-0' },
  556. { selector: '.dt-buttons', classToAdd: 'd-flex gap-4 mb-md-0 mb-6' },
  557. { selector: '.dt-layout-table', classToRemove: 'row mt-2' },
  558. { selector: '.dt-layout-full', classToRemove: 'col-md col-12', classToAdd: 'table-responsive' }
  559. ];
  560. // Delete record
  561. elementsToModify.forEach(({ selector, classToRemove, classToAdd }) => {
  562. document.querySelectorAll(selector).forEach(element => {
  563. if (classToRemove) {
  564. classToRemove.split(' ').forEach(className => element.classList.remove(className));
  565. }
  566. if (classToAdd) {
  567. classToAdd.split(' ').forEach(className => element.classList.add(className));
  568. }
  569. });
  570. });
  571. }, 100);
  572. }
  573. // validating form and updating user's data
  574. const addNewUserForm = document.getElementById('addNewUserForm');
  575. // user form validation
  576. if (addNewUserForm) {
  577. const fv = FormValidation.formValidation(addNewUserForm, {
  578. fields: {
  579. name: {
  580. validators: {
  581. notEmpty: {
  582. message: 'Please enter fullname'
  583. }
  584. }
  585. },
  586. email: {
  587. validators: {
  588. notEmpty: {
  589. message: 'Please enter your email'
  590. },
  591. emailAddress: {
  592. message: 'The value is not a valid email address'
  593. }
  594. }
  595. },
  596. userContact: {
  597. validators: {
  598. notEmpty: {
  599. message: 'Please enter your contact'
  600. }
  601. }
  602. },
  603. company: {
  604. validators: {
  605. notEmpty: {
  606. message: 'Please enter your company'
  607. }
  608. }
  609. }
  610. },
  611. plugins: {
  612. trigger: new FormValidation.plugins.Trigger(),
  613. bootstrap5: new FormValidation.plugins.Bootstrap5({
  614. // Use this for enabling/changing valid/invalid class
  615. eleValidClass: '',
  616. rowSelector: function (field, ele) {
  617. // field is the field name & ele is the field element
  618. return '.mb-6';
  619. }
  620. }),
  621. submitButton: new FormValidation.plugins.SubmitButton(),
  622. autoFocus: new FormValidation.plugins.AutoFocus()
  623. }
  624. }).on('core.form.valid', function () {
  625. // adding or updating user when form successfully validate
  626. const formData = new FormData(addNewUserForm);
  627. const formDataObj = {};
  628. // Convert FormData to URL-encoded string
  629. formData.forEach((value, key) => {
  630. formDataObj[key] = value;
  631. });
  632. const searchParams = new URLSearchParams();
  633. for (const [key, value] of Object.entries(formDataObj)) {
  634. searchParams.append(key, value);
  635. }
  636. fetch(`${baseUrl}user-list`, {
  637. method: 'POST',
  638. headers: {
  639. 'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute('content'),
  640. 'Content-Type': 'application/x-www-form-urlencoded'
  641. },
  642. body: searchParams.toString()
  643. })
  644. .then(response => {
  645. if (!response.ok) {
  646. throw new Error('Network response was not ok');
  647. }
  648. return response.text();
  649. })
  650. .then(status => {
  651. // Refresh DataTable
  652. dt_user_table && new DataTable(dt_user_table).draw();
  653. // Hide offcanvas
  654. const offcanvasInstance = bootstrap.Offcanvas.getInstance(offCanvasForm);
  655. offcanvasInstance && offcanvasInstance.hide();
  656. // sweetalert
  657. Swal.fire({
  658. icon: 'success',
  659. title: `Successfully ${status}!`,
  660. text: `User ${status} Successfully.`,
  661. customClass: {
  662. confirmButton: 'btn btn-success'
  663. }
  664. });
  665. })
  666. .catch(err => {
  667. // Hide offcanvas
  668. const offcanvasInstance = bootstrap.Offcanvas.getInstance(offCanvasForm);
  669. offcanvasInstance && offcanvasInstance.hide();
  670. Swal.fire({
  671. title: 'Duplicate Entry!',
  672. text: 'Your email should be unique.',
  673. icon: 'error',
  674. customClass: {
  675. confirmButton: 'btn btn-success'
  676. }
  677. });
  678. });
  679. });
  680. // clearing form data when offcanvas hidden
  681. offCanvasForm.addEventListener('hidden.bs.offcanvas', function () {
  682. fv.resetForm(true);
  683. });
  684. }
  685. // Phone mask initialization
  686. const phoneMaskList = document.querySelectorAll('.phone-mask');
  687. // Phone Number
  688. if (phoneMaskList) {
  689. phoneMaskList.forEach(function (phoneMask) {
  690. phoneMask.addEventListener('input', event => {
  691. const cleanValue = event.target.value.replace(/\D/g, '');
  692. phoneMask.value = formatGeneral(cleanValue, {
  693. blocks: [3, 3, 4],
  694. delimiters: [' ', ' ']
  695. });
  696. });
  697. registerCursorTracker({
  698. input: phoneMask,
  699. delimiter: ' '
  700. });
  701. });
  702. }
  703. });