Bez popisu
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

app-ecommerce-reviews.js 27KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767
  1. /**
  2. * App eCommerce review
  3. */
  4. 'use strict';
  5. // apex-chart
  6. document.addEventListener('DOMContentLoaded', function (e) {
  7. let cardColor, shadeColor, labelColor, headingColor, borderColor, bodyBg;
  8. if (isDarkStyle) {
  9. shadeColor = 'dark';
  10. } else {
  11. shadeColor = '';
  12. }
  13. cardColor = config.colors.cardColor;
  14. labelColor = config.colors.textMuted;
  15. headingColor = config.colors.headingColor;
  16. borderColor = config.colors.borderColor;
  17. bodyBg = config.colors.bodyBg;
  18. // Visitor Bar Chart
  19. // --------------------------------------------------------------------
  20. const visitorBarChartEl = document.querySelector('#reviewsChart'),
  21. visitorBarChartConfig = {
  22. chart: {
  23. height: 160,
  24. width: 190,
  25. type: 'bar',
  26. toolbar: {
  27. show: false
  28. }
  29. },
  30. plotOptions: {
  31. bar: {
  32. barHeight: '75%',
  33. columnWidth: '40%',
  34. startingShape: 'rounded',
  35. endingShape: 'rounded',
  36. borderRadius: 5,
  37. distributed: true
  38. }
  39. },
  40. grid: {
  41. show: false,
  42. padding: {
  43. top: -25,
  44. bottom: -12
  45. }
  46. },
  47. colors: [
  48. config.colors_label.success,
  49. config.colors_label.success,
  50. config.colors_label.success,
  51. config.colors_label.success,
  52. config.colors.success,
  53. config.colors_label.success,
  54. config.colors_label.success
  55. ],
  56. dataLabels: {
  57. enabled: false
  58. },
  59. series: [
  60. {
  61. data: [20, 40, 60, 80, 100, 80, 60]
  62. }
  63. ],
  64. legend: {
  65. show: false
  66. },
  67. xaxis: {
  68. categories: ['M', 'T', 'W', 'T', 'F', 'S', 'S'],
  69. axisBorder: {
  70. show: false
  71. },
  72. axisTicks: {
  73. show: false
  74. },
  75. labels: {
  76. style: {
  77. colors: labelColor,
  78. fontSize: '13px'
  79. }
  80. }
  81. },
  82. yaxis: {
  83. labels: {
  84. show: false
  85. }
  86. },
  87. responsive: [
  88. {
  89. breakpoint: 0,
  90. options: {
  91. chart: {
  92. width: '100%'
  93. },
  94. plotOptions: {
  95. bar: {
  96. columnWidth: '40%'
  97. }
  98. }
  99. }
  100. },
  101. {
  102. breakpoint: 1440,
  103. options: {
  104. chart: {
  105. height: 150,
  106. width: 190,
  107. toolbar: {
  108. show: false
  109. }
  110. },
  111. plotOptions: {
  112. bar: {
  113. borderRadius: 6,
  114. columnWidth: '40%'
  115. }
  116. }
  117. }
  118. },
  119. {
  120. breakpoint: 1400,
  121. options: {
  122. plotOptions: {
  123. bar: {
  124. borderRadius: 6,
  125. columnWidth: '40%'
  126. }
  127. }
  128. }
  129. },
  130. {
  131. breakpoint: 1200,
  132. options: {
  133. chart: {
  134. height: 130,
  135. width: 190,
  136. toolbar: {
  137. show: false
  138. }
  139. },
  140. plotOptions: {
  141. bar: {
  142. borderRadius: 6,
  143. columnWidth: '40%'
  144. }
  145. }
  146. }
  147. },
  148. {
  149. breakpoint: 992,
  150. chart: {
  151. height: 150,
  152. width: 190,
  153. toolbar: {
  154. show: false
  155. }
  156. },
  157. options: {
  158. plotOptions: {
  159. bar: {
  160. borderRadius: 5,
  161. columnWidth: '40%'
  162. }
  163. }
  164. }
  165. },
  166. {
  167. breakpoint: 883,
  168. options: {
  169. plotOptions: {
  170. bar: {
  171. borderRadius: 5,
  172. columnWidth: '40%'
  173. }
  174. }
  175. }
  176. },
  177. {
  178. breakpoint: 768,
  179. options: {
  180. chart: {
  181. height: 150,
  182. width: 190,
  183. toolbar: {
  184. show: false
  185. }
  186. },
  187. plotOptions: {
  188. bar: {
  189. borderRadius: 4,
  190. columnWidth: '40%'
  191. }
  192. }
  193. }
  194. },
  195. {
  196. breakpoint: 576,
  197. options: {
  198. chart: {
  199. width: '100%',
  200. height: '200',
  201. type: 'bar'
  202. },
  203. plotOptions: {
  204. bar: {
  205. borderRadius: 6,
  206. columnWidth: '30% '
  207. }
  208. }
  209. }
  210. },
  211. {
  212. breakpoint: 420,
  213. options: {
  214. plotOptions: {
  215. chart: {
  216. width: '100%',
  217. height: '200',
  218. type: 'bar'
  219. },
  220. bar: {
  221. borderRadius: 3,
  222. columnWidth: '30%'
  223. }
  224. }
  225. }
  226. }
  227. ]
  228. };
  229. if (typeof visitorBarChartEl !== undefined && visitorBarChartEl !== null) {
  230. const visitorBarChart = new ApexCharts(visitorBarChartEl, visitorBarChartConfig);
  231. visitorBarChart.render();
  232. }
  233. // Variable declaration for table
  234. var dt_customer_review = document.querySelector('.datatables-review'),
  235. customerView = baseUrl + 'app/ecommerce/customer/details/overview',
  236. statusObj = {
  237. Pending: { title: 'Pending', class: 'bg-label-warning' },
  238. Published: { title: 'Published', class: 'bg-label-success' }
  239. };
  240. // reviewer datatable
  241. if (dt_customer_review) {
  242. const reviewFilter = document.createElement('div');
  243. reviewFilter.classList.add('review_filter');
  244. var dt_review = new DataTable(dt_customer_review, {
  245. ajax: assetsPath + 'json/app-ecommerce-reviews.json', // JSON file to add data
  246. columns: [
  247. // columns according to JSON
  248. { data: 'id' },
  249. { data: 'id', orderable: false, render: DataTable.render.select() },
  250. { data: 'product' },
  251. { data: 'reviewer' },
  252. { data: 'review' },
  253. { data: 'date' },
  254. { data: 'status' },
  255. { data: 'id' }
  256. ],
  257. columnDefs: [
  258. {
  259. // For Responsive
  260. className: 'control',
  261. searchable: false,
  262. orderable: false,
  263. responsivePriority: 2,
  264. targets: 0,
  265. render: function (data, type, full, meta) {
  266. return '';
  267. }
  268. },
  269. {
  270. // For Checkboxes
  271. targets: 1,
  272. orderable: false,
  273. searchable: false,
  274. responsivePriority: 3,
  275. checkboxes: true,
  276. render: function () {
  277. return '<input type="checkbox" class="dt-checkboxes form-check-input">';
  278. },
  279. checkboxes: {
  280. selectAllRender: '<input type="checkbox" class="form-check-input">'
  281. }
  282. },
  283. {
  284. targets: 2,
  285. render: function (data, type, full, meta) {
  286. const product = full['product'];
  287. const companyName = full['company_name'];
  288. const id = full['id'];
  289. const image = full['product_image'];
  290. let output;
  291. if (image) {
  292. // For Product image
  293. output = `
  294. <img src="${assetsPath}img/ecommerce-images/${image}" alt="Product-${id}" class="rounded">
  295. `;
  296. } else {
  297. // For Avatar badge
  298. const stateNum = Math.floor(Math.random() * 6);
  299. const states = ['success', 'danger', 'warning', 'info', 'dark', 'primary', 'secondary'];
  300. const state = states[stateNum];
  301. const initials = (product.match(/\b\w/g) || []).slice(0, 2).join('').toUpperCase();
  302. output = `<span class="avatar-initial rounded bg-label-${state}">${initials}</span>`;
  303. }
  304. // Creates full output for product and company name
  305. const rowOutput = `
  306. <div class="d-flex justify-content-start align-items-center customer-name">
  307. <div class="avatar-wrapper">
  308. <div class="avatar me-4 rounded-2 bg-label-secondary">${output}</div>
  309. </div>
  310. <div class="d-flex flex-column">
  311. <span class="fw-medium text-nowrap text-heading">${product}</span>
  312. <small>${companyName}</small>
  313. </div>
  314. </div>`;
  315. return rowOutput;
  316. }
  317. },
  318. {
  319. // Reviewer
  320. targets: 3,
  321. responsivePriority: 1,
  322. render: function (data, type, full, meta) {
  323. const reviewerName = full['reviewer'];
  324. const email = full['email'];
  325. const avatar = full['avatar'];
  326. let output;
  327. if (avatar) {
  328. // For Avatar image
  329. output = `<img src="${assetsPath}img/avatars/${avatar}" alt="Avatar" class="rounded-circle">`;
  330. } else {
  331. // For Avatar badge
  332. const stateNum = Math.floor(Math.random() * 6);
  333. const states = ['success', 'danger', 'warning', 'info', 'dark', 'primary', 'secondary'];
  334. const state = states[stateNum];
  335. const initials = (reviewerName.match(/\b\w/g) || []).slice(0, 2).join('').toUpperCase();
  336. output = `<span class="avatar-initial rounded-circle bg-label-${state}">${initials}</span>`;
  337. }
  338. // Creates full output for row
  339. const rowOutput = `
  340. <div class="d-flex justify-content-start align-items-center customer-name">
  341. <div class="avatar-wrapper">
  342. <div class="avatar avatar-sm me-4">${output}</div>
  343. </div>
  344. <div class="d-flex flex-column">
  345. <a href="${customerView}"><span class="fw-medium">${reviewerName}</span></a>
  346. <small class="text-nowrap">${email}</small>
  347. </div>
  348. </div>`;
  349. return rowOutput;
  350. }
  351. },
  352. {
  353. targets: 4,
  354. responsivePriority: 2,
  355. sortable: false,
  356. render: function (data, type, full, meta) {
  357. const num = full['review'];
  358. const heading = full['head'];
  359. const comment = full['para'];
  360. function capitalizeFirstLetter(str) {
  361. if (typeof str !== 'string' || str.length === 0) {
  362. return str; // Return the input as it is if it's not a string or empty
  363. }
  364. return str.charAt(0).toUpperCase() + str.slice(1);
  365. }
  366. const firstCap = capitalizeFirstLetter(heading);
  367. // Create the rating element container
  368. const readOnlyRatings = document.createElement('div');
  369. readOnlyRatings.className = 'read-only-ratings raty mb-1';
  370. readOnlyRatings.setAttribute('data-number', '5');
  371. let r = parseInt(window.Helpers.getCssVar('gray-200', true).slice(1, 3), 16);
  372. let g = parseInt(window.Helpers.getCssVar('gray-200', true).slice(3, 5), 16);
  373. let b = parseInt(window.Helpers.getCssVar('gray-200', true).slice(5, 7), 16);
  374. // Initialize the Raty plugin
  375. if (readOnlyRatings) {
  376. const ratings = new Raty(readOnlyRatings, {
  377. score: num,
  378. readOnly: true, // Make the rating read-only
  379. starOn:
  380. "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='16' %3E%3Cpath fill='%23FFD700' d='M21.947 9.179a1 1 0 0 0-.868-.676l-5.701-.453l-2.467-5.461a.998.998 0 0 0-1.822-.001L8.622 8.05l-5.701.453a1 1 0 0 0-.619 1.713l4.213 4.107l-1.49 6.452a1 1 0 0 0 1.53 1.057L12 18.202l5.445 3.63a1.001 1.001 0 0 0 1.517-1.106l-1.829-6.4l4.536-4.082c.297-.268.406-.686.278-1.065'/%3E%3C/svg%3E",
  381. starOff:
  382. "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='16' %3E%3Cpath fill='rgb(" +
  383. r +
  384. ',' +
  385. g +
  386. ',' +
  387. b +
  388. ")' d='M21.947 9.179a1 1 0 0 0-.868-.676l-5.701-.453l-2.467-5.461a.998.998 0 0 0-1.822-.001L8.622 8.05l-5.701.453a1 1 0 0 0-.619 1.713l4.213 4.107l-1.49 6.452a1 1 0 0 0 1.53 1.057L12 18.202l5.445 3.63a1.001 1.001 0 0 0 1.517-1.106l-1.829-6.4l4.536-4.082c.297-.268.406-.686.278-1.065'/%3E%3C/svg%3E"
  389. });
  390. ratings.init();
  391. // Generate the HTML for the review
  392. const review = `
  393. <div>
  394. ${readOnlyRatings.outerHTML}
  395. <p class="h6 mb-1 text-truncate">${firstCap}</p>
  396. <small class="text-break">${comment}</small>
  397. </div>
  398. `;
  399. return review;
  400. }
  401. }
  402. },
  403. {
  404. // date
  405. targets: 5,
  406. render: function (data, type, full, meta) {
  407. var date = new Date(full.date); // convert the date string to a Date object
  408. var formattedDate = date.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' });
  409. return '<span class="text-nowrap">' + formattedDate + '</span>';
  410. }
  411. },
  412. {
  413. // User Status
  414. targets: 6,
  415. render: function (data, type, full, meta) {
  416. let status = full['status'];
  417. return (
  418. '<span class="badge ' +
  419. statusObj[status].class +
  420. '" text-capitalize>' +
  421. statusObj[status].title +
  422. '</span>'
  423. );
  424. }
  425. },
  426. {
  427. targets: -1,
  428. title: 'Actions',
  429. searchable: false,
  430. orderable: false,
  431. render: function (data, type, full, meta) {
  432. return `
  433. <div class="text-xxl-center">
  434. <div class="dropdown">
  435. <a href="javascript:void(0);" class="btn btn-icon dropdown-toggle hide-arrow p-0" data-bs-toggle="dropdown">
  436. <i class="icon-base bx bx-dots-vertical-rounded icon-md"></i>
  437. </a>
  438. <div class="dropdown-menu dropdown-menu-end">
  439. <a href="javascript:void(0);" class="dropdown-item">Download</a>
  440. <a href="javascript:void(0);" class="dropdown-item">Edit</a>
  441. <a href="javascript:void(0);" class="dropdown-item">Duplicate</a>
  442. <div class="dropdown-divider"></div>
  443. <a href="javascript:void(0);" class="dropdown-item delete-record text-danger">Delete</a>
  444. </div>
  445. </div>
  446. </div>
  447. `;
  448. }
  449. }
  450. ],
  451. select: {
  452. style: 'multi',
  453. selector: 'td:nth-child(2)'
  454. },
  455. order: [[2, 'asc']],
  456. layout: {
  457. topStart: {
  458. rowClass: 'row m-3 my-0 justify-content-between',
  459. features: [
  460. {
  461. search: {
  462. placeholder: 'Search Review',
  463. text: '_INPUT_'
  464. }
  465. }
  466. ]
  467. },
  468. topEnd: {
  469. features: [
  470. {
  471. pageLength: {
  472. menu: [10, 25, 50, 100],
  473. text: '_MENU_'
  474. }
  475. },
  476. reviewFilter,
  477. {
  478. buttons: [
  479. {
  480. extend: 'collection',
  481. className: 'btn btn-label-primary dropdown-toggle',
  482. text: '<span class="d-flex align-items-center gap-2"><i class="icon-base bx bx-export me-sm-1"></i> <span class="d-none d-sm-inline-block">Export</span></span>',
  483. buttons: [
  484. {
  485. extend: 'print',
  486. text: `<span class="d-flex align-items-center"><i class="icon-base bx bx-printer me-1"></i>Print</span>`,
  487. className: 'dropdown-item',
  488. exportOptions: {
  489. columns: [3, 4, 5, 6, 7],
  490. format: {
  491. body: function (inner, coldex, rowdex) {
  492. if (inner.length <= 0) return inner;
  493. const el = new DOMParser().parseFromString(inner, 'text/html').body.childNodes;
  494. let result = '';
  495. el.forEach(item => {
  496. if (item.classList && item.classList.contains('user-name')) {
  497. result += item.lastChild.firstChild.textContent;
  498. } else {
  499. result += item.textContent || item.innerText || '';
  500. }
  501. });
  502. return result;
  503. }
  504. }
  505. },
  506. customize: function (win) {
  507. win.document.body.style.color = headingColor;
  508. win.document.body.style.borderColor = borderColor;
  509. win.document.body.style.backgroundColor = bodyBg;
  510. const table = win.document.body.querySelector('table');
  511. table.classList.add('compact');
  512. table.style.color = 'inherit';
  513. table.style.borderColor = 'inherit';
  514. table.style.backgroundColor = 'inherit';
  515. }
  516. },
  517. {
  518. extend: 'csv',
  519. text: `<span class="d-flex align-items-center"><i class="icon-base bx bx-file me-1"></i>Csv</span>`,
  520. className: 'dropdown-item',
  521. exportOptions: {
  522. columns: [3, 4, 5, 6, 7],
  523. format: {
  524. body: function (inner, coldex, rowdex) {
  525. if (inner.length <= 0) return inner;
  526. const el = new DOMParser().parseFromString(inner, 'text/html').body.childNodes;
  527. let result = '';
  528. el.forEach(item => {
  529. if (item.classList && item.classList.contains('user-name')) {
  530. result += item.lastChild.firstChild.textContent;
  531. } else {
  532. result += item.textContent || item.innerText || '';
  533. }
  534. });
  535. return result;
  536. }
  537. }
  538. }
  539. },
  540. {
  541. extend: 'excel',
  542. text: `<span class="d-flex align-items-center"><i class="icon-base bx bxs-file-export me-1"></i>Excel</span>`,
  543. className: 'dropdown-item',
  544. exportOptions: {
  545. columns: [3, 4, 5, 6, 7],
  546. format: {
  547. body: function (inner, coldex, rowdex) {
  548. if (inner.length <= 0) return inner;
  549. const el = new DOMParser().parseFromString(inner, 'text/html').body.childNodes;
  550. let result = '';
  551. el.forEach(item => {
  552. if (item.classList && item.classList.contains('user-name')) {
  553. result += item.lastChild.firstChild.textContent;
  554. } else {
  555. result += item.textContent || item.innerText || '';
  556. }
  557. });
  558. return result;
  559. }
  560. }
  561. }
  562. },
  563. {
  564. extend: 'pdf',
  565. text: `<span class="d-flex align-items-center"><i class="icon-base bx bxs-file-pdf me-1"></i>Pdf</span>`,
  566. className: 'dropdown-item',
  567. exportOptions: {
  568. columns: [3, 4, 5, 6, 7],
  569. format: {
  570. body: function (inner, coldex, rowdex) {
  571. if (inner.length <= 0) return inner;
  572. const el = new DOMParser().parseFromString(inner, 'text/html').body.childNodes;
  573. let result = '';
  574. el.forEach(item => {
  575. if (item.classList && item.classList.contains('user-name')) {
  576. result += item.lastChild.firstChild.textContent;
  577. } else {
  578. result += item.textContent || item.innerText || '';
  579. }
  580. });
  581. return result;
  582. }
  583. }
  584. }
  585. },
  586. {
  587. extend: 'copy',
  588. text: `<i class="icon-base bx bx-copy me-1"></i>Copy`,
  589. className: 'dropdown-item',
  590. exportOptions: {
  591. columns: [3, 4, 5, 6, 7],
  592. format: {
  593. body: function (inner, coldex, rowdex) {
  594. if (inner.length <= 0) return inner;
  595. const el = new DOMParser().parseFromString(inner, 'text/html').body.childNodes;
  596. let result = '';
  597. el.forEach(item => {
  598. if (item.classList && item.classList.contains('user-name')) {
  599. result += item.lastChild.firstChild.textContent;
  600. } else {
  601. result += item.textContent || item.innerText || '';
  602. }
  603. });
  604. return result;
  605. }
  606. }
  607. }
  608. }
  609. ]
  610. }
  611. ]
  612. }
  613. ]
  614. },
  615. bottomStart: {
  616. rowClass: 'row mx-3 justify-content-between',
  617. features: ['info']
  618. },
  619. bottomEnd: 'paging'
  620. },
  621. language: {
  622. paginate: {
  623. next: '<i class="icon-base bx bx-chevron-right scaleX-n1-rtl icon-18px"></i>',
  624. previous: '<i class="icon-base bx bx-chevron-left scaleX-n1-rtl icon-18px"></i>',
  625. first: '<i class="icon-base bx bx-chevrons-left scaleX-n1-rtl icon-18px"></i>',
  626. last: '<i class="icon-base bx bx-chevrons-right scaleX-n1-rtl icon-18px"></i>'
  627. }
  628. },
  629. // For responsive popup
  630. responsive: {
  631. details: {
  632. display: DataTable.Responsive.display.modal({
  633. header: function (row) {
  634. const data = row.data();
  635. return 'Details of ' + data['reviewer'];
  636. }
  637. }),
  638. type: 'column',
  639. renderer: function (api, rowIdx, columns) {
  640. const data = columns
  641. .map(function (col) {
  642. return col.title !== '' // Do not show row in modal popup if title is blank (for check box)
  643. ? `<tr data-dt-row="${col.rowIndex}" data-dt-column="${col.columnIndex}">
  644. <td>${col.title}:</td>
  645. <td>${col.data}</td>
  646. </tr>`
  647. : '';
  648. })
  649. .join('');
  650. if (data) {
  651. const div = document.createElement('div');
  652. div.classList.add('table-responsive');
  653. const table = document.createElement('table');
  654. div.appendChild(table);
  655. table.classList.add('table');
  656. const tbody = document.createElement('tbody');
  657. tbody.innerHTML = data;
  658. table.appendChild(tbody);
  659. return div;
  660. }
  661. return false;
  662. }
  663. }
  664. },
  665. initComplete: function () {
  666. this.api()
  667. .columns(6)
  668. .every(function () {
  669. const column = this;
  670. if (reviewFilter) {
  671. const select = document.createElement('select');
  672. select.className = 'form-select';
  673. select.innerHTML = '<option value=""> All </option>';
  674. reviewFilter.appendChild(select);
  675. select.addEventListener('change', function () {
  676. const val = select.value ? '^' + select.value + '$' : '';
  677. column.search(val, true, false).draw();
  678. });
  679. column
  680. .data()
  681. .unique()
  682. .sort()
  683. .each(function (d) {
  684. const option = document.createElement('option');
  685. option.value = d;
  686. option.className = 'text-capitalize';
  687. option.textContent = d;
  688. select.appendChild(option);
  689. });
  690. }
  691. });
  692. }
  693. });
  694. }
  695. //? The 'delete-record' class is necessary for the functionality of the following code.
  696. document.addEventListener('click', function (e) {
  697. if (e.target.classList.contains('delete-record')) {
  698. dt_review.row(e.target.closest('tr')).remove().draw();
  699. const modalEl = document.querySelector('.dtr-bs-modal');
  700. if (modalEl && modalEl.classList.contains('show')) {
  701. const modal = bootstrap.Modal.getInstance(modalEl);
  702. modal?.hide();
  703. }
  704. }
  705. });
  706. // Filter form control to default size
  707. // ? setTimeout used for reviews table initialization
  708. setTimeout(() => {
  709. const elementsToModify = [
  710. { selector: '.dt-buttons .btn', classToRemove: 'btn-secondary', classToAdd: 'btn-label-secondary' },
  711. { selector: '.dt-buttons.btn-group', classToAdd: 'justify-content-center' },
  712. { selector: '.dt-search .form-control', classToRemove: 'form-control-sm', classToAdd: 'ms-0' },
  713. { selector: '.dt-search', classToAdd: 'mb-md-6 mb-0' },
  714. { selector: '.dt-length .form-select', classToRemove: 'form-select-sm', classToAdd: 'me-md-4 me-0' },
  715. { selector: '.dt-layout-table', classToRemove: 'row mt-2' },
  716. { selector: '.dt-layout-start', classToAdd: 'px-3' },
  717. { selector: '.review_filter', classToAdd: 'me-md-4' },
  718. { selector: '.review_filter .form-select', classToAdd: 'w-px-150' },
  719. { selector: '.dt-buttons', classToAdd: 'mb-0' },
  720. {
  721. selector: '.dt-layout-end',
  722. classToAdd: 'd-flex flex-md-row flex-column gap-md-0 gap-5 px-3 mb-md-0 mb-5 mt-0'
  723. },
  724. {
  725. selector: '.dt-layout-end .dt-length',
  726. classToAdd: 'mb-md-6 mb-0'
  727. },
  728. { selector: '.dt-layout-full', classToRemove: 'col-md col-12', classToAdd: 'table-responsive' }
  729. ];
  730. // Delete record
  731. elementsToModify.forEach(({ selector, classToRemove, classToAdd }) => {
  732. document.querySelectorAll(selector).forEach(element => {
  733. if (classToRemove) {
  734. classToRemove.split(' ').forEach(className => element.classList.remove(className));
  735. }
  736. if (classToAdd) {
  737. classToAdd.split(' ').forEach(className => element.classList.add(className));
  738. }
  739. });
  740. });
  741. }, 100);
  742. });