/** * App User View - Account (js) */ 'use strict'; document.addEventListener('DOMContentLoaded', function (e) { // Variable declaration for table const dt_project_table = document.querySelector('.datatable-project'), dt_invoice_table = document.querySelector('.datatable-invoice'); // Project datatable // -------------------------------------------------------------------- if (dt_project_table) { let tableTitle = document.createElement('h5'); tableTitle.classList.add('card-title', 'mb-0', 'text-md-start', 'text-center', 'pt-md-0', 'pt-6'); tableTitle.innerHTML = 'Project List'; var dt_project = new DataTable(dt_project_table, { ajax: assetsPath + 'json/user-profile.json', // JSON file to add data columns: [ { data: 'id' }, { data: 'id', orderable: false, render: DataTable.render.select() }, { data: 'project_name' }, { data: 'project_leader' }, { data: 'id' }, { data: 'status' }, { data: 'id' } ], columnDefs: [ { // For Responsive className: 'control', searchable: false, orderable: false, responsivePriority: 2, targets: 0, render: function (data, type, full, meta) { return ''; } }, { // For Checkboxes targets: 1, orderable: false, searchable: false, responsivePriority: 3, checkboxes: true, render: function () { return ''; }, checkboxes: { selectAllRender: '' } }, { targets: 2, responsivePriority: 4, render: function (data, type, full, meta) { var userImg = full['project_img'], name = full['project_name'], date = full['date']; var output; if (userImg) { // For Avatar image output = 'Avatar'; } else { // For Avatar badge var stateNum = Math.floor(Math.random() * 6); var states = ['success', 'danger', 'warning', 'info', 'primary', 'secondary']; var state = states[stateNum], initials = name.match(/\b\w/g) || []; initials = ((initials.shift() || '') + (initials.pop() || '')).toUpperCase(); output = '' + initials + ''; } // Creates full output for row var rowOutput = '
' + '
' + '
' + output + '
' + '
' + '
' + '' + name + '' + '' + date + '' + '
' + '
'; return rowOutput; } }, { // Task targets: 3, render: function (data, type, full, meta) { var task = full['project_leader']; return '' + task + ''; } }, { targets: 4, orderable: false, searchable: false, render: function (data, type, full, meta) { const team = full['team']; let teamItem = ''; let teamCount = 0; // Iterate through team members and generate the list items for (let i = 0; i < team.length; i++) { teamItem += `
  • Avatar
  • `; teamCount++; if (teamCount > 2) break; } // Check if there are more than 2 team members, and add the remaining avatars if (teamCount > 2) { const remainingAvatars = team.length - 3; if (remainingAvatars > 0) { teamItem += `
  • +${remainingAvatars}
  • `; } } // Combine the team items into the final output const teamOutput = `
    `; return teamOutput; } }, { targets: -2, render: function (data, type, full, meta) { const statusNumber = full['status']; return `
    ${statusNumber}
    `; } }, { // Actions targets: -1, searchable: false, title: 'Action', orderable: false, render: function (data, type, full, meta) { return ( '
    ' + '' + '' + '
    ' ); } } ], select: { style: 'multi', selector: 'td:nth-child(2)' }, order: [[2, 'desc']], layout: { topStart: { rowClass: 'row mx-md-3 my-0 justify-content-between', features: [tableTitle] }, topEnd: { search: { placeholder: 'Search Project', text: '_INPUT_' } }, bottomStart: { rowClass: 'row mx-3 justify-content-between', features: ['info'] }, bottomEnd: 'paging' }, displayLength: 7, language: { lengthMenu: '_MENU_', paginate: { next: '', previous: '', first: '', last: '' } }, // For responsive popup responsive: { details: { display: DataTable.Responsive.display.modal({ header: function (row) { const data = row.data(); return 'Details of ' + data['project_name']; } }), type: 'column', renderer: function (api, rowIdx, columns) { const data = columns .map(function (col) { return col.title !== '' // Do not show row in modal popup if title is blank (for check box) ? ` ${col.title}: ${col.data} ` : ''; }) .join(''); if (data) { const div = document.createElement('div'); div.classList.add('table-responsive'); const table = document.createElement('table'); div.appendChild(table); table.classList.add('table'); const tbody = document.createElement('tbody'); tbody.innerHTML = data; table.appendChild(tbody); return div; } return false; } } } }); //? The 'delete-record' class is necessary for the functionality of the following code. document.addEventListener('click', function (e) { if (e.target.classList.contains('delete-record')) { dt_project.row(e.target.closest('tr')).remove().draw(); const modalEl = document.querySelector('.dtr-bs-modal'); if (modalEl && modalEl.classList.contains('show')) { const modal = bootstrap.Modal.getInstance(modalEl); modal?.hide(); } } }); } // Invoice datatable // -------------------------------------------------------------------- if (dt_invoice_table) { let tableTitle = document.createElement('h5'); tableTitle.classList.add('card-title', 'mb-0', 'text-md-start', 'text-center', 'pt-md-0', 'pt-6'); tableTitle.innerHTML = 'Invoice List'; const dt_invoice = new DataTable(dt_invoice_table, { ajax: assetsPath + 'json/invoice-list.json', // JSON file to add data columns: [ // columns according to JSON { data: 'id' }, { data: 'invoice_id' }, { data: 'invoice_status' }, { data: 'total' }, { data: 'issued_date' }, { data: 'action' } ], columnDefs: [ { // For Responsive className: 'control', orderable: false, searchable: false, responsivePriority: 2, targets: 0, render: function (data, type, full, meta) { return ''; } }, { // Invoice ID targets: 1, render: (data, type, full, meta) => { const invoiceId = full['invoice_id']; // Creates full output for row const rowOutput = `#${invoiceId}`; return rowOutput; } }, { // Invoice status targets: 2, render: (data, type, full, meta) => { const invoiceStatus = full['invoice_status']; const dueDate = full['due_date']; const balance = full['balance']; const roleBadgeObj = { Sent: ``, Draft: ``, 'Past Due': ``, 'Partial Payment': ``, Paid: ``, Downloaded: `` }; return ` ${roleBadgeObj[invoiceStatus]} `; } }, { // Total Invoice Amount targets: 3, render: function (data, type, full, meta) { const total = full['total']; return '$' + total; } }, { // Actions targets: -1, title: 'Actions', orderable: false, render: (data, type, full, meta) => { return `
    `; } } ], order: [[1, 'desc']], layout: { topStart: { rowClass: 'row border-bottom mx-0 px-3', features: [tableTitle] }, topEnd: { features: [ { pageLength: { menu: [10, 25, 50, 100], text: '_MENU_' } }, { buttons: [ { extend: 'collection', className: 'btn btn-label-secondary dropdown-toggle float-sm-end mb-3 mb-md-0 mt-md-0 mt-5', text: 'Export', buttons: [ { extend: 'print', text: 'Print', exportOptions: { columns: [1, 2, 3, 4] } }, { extend: 'csv', text: 'Csv', exportOptions: { columns: [1, 2, 3, 4] } }, { extend: 'excel', text: 'Excel', exportOptions: { columns: [1, 2, 3, 4] } }, { extend: 'pdf', text: 'Pdf', exportOptions: { columns: [1, 2, 3, 4] } }, { extend: 'copy', text: 'Copy', exportOptions: { columns: [1, 2, 3, 4] } } ] } ] } ] }, bottomStart: { rowClass: 'row mx-3 justify-content-between', features: ['info'] }, bottomEnd: 'paging' }, language: { paginate: { next: '', previous: '', first: '', last: '' } }, // For responsive popup responsive: { details: { display: DataTable.Responsive.display.modal({ header: function (row) { const data = row.data(); return 'Details of ' + data['invoice_id']; } }), type: 'column', renderer: function (api, rowIdx, columns) { const data = columns .map(function (col) { return col.title !== '' // Do not show row in modal popup if title is blank (for check box) ? ` ${col.title}: ${col.data} ` : ''; }) .join(''); if (data) { const div = document.createElement('div'); div.classList.add('table-responsive'); const table = document.createElement('table'); div.appendChild(table); table.classList.add('table'); const tbody = document.createElement('tbody'); tbody.innerHTML = data; table.appendChild(tbody); return div; } return false; } } } }); //? The 'delete-record' class is necessary for the functionality of the following code. function deleteRecord(event) { let row = document.querySelector('.dtr-expanded'); if (event) { row = event.target.parentElement.closest('tr'); } if (row) { dt_invoice.row(row).remove().draw(); } } function bindDeleteEvent() { const dt_invoice_table = document.querySelector('.datatable-invoice'); const modal = document.querySelector('.dtr-bs-modal'); if (dt_invoice_table && dt_invoice_table.classList.contains('collapsed')) { if (modal) { modal.addEventListener('click', function (event) { if (event.target.parentElement.classList.contains('delete-record')) { deleteRecord(); const closeButton = modal.querySelector('.btn-close'); if (closeButton) closeButton.click(); // Simulates a click on the close button } }); } } else { const tableBody = dt_invoice_table?.querySelector('tbody'); if (tableBody) { tableBody.addEventListener('click', function (event) { if (event.target.parentElement.classList.contains('delete-record')) { deleteRecord(event); } }); } } } // Initial event binding bindDeleteEvent(); // Re-bind events when modal is shown or hidden document.addEventListener('show.bs.modal', function (event) { if (event.target.classList.contains('dtr-bs-modal')) { bindDeleteEvent(); } }); document.addEventListener('hide.bs.modal', function (event) { if (event.target.classList.contains('dtr-bs-modal')) { bindDeleteEvent(); } }); // On each datatable draw, initialize tooltip dt_invoice.on('draw.dt', function () { var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]')); var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) { return new bootstrap.Tooltip(tooltipTriggerEl, { boundary: document.body }); }); }); } // Filter form control to default size // ? setTimeout used for project-list and invoice-list table initialization setTimeout(() => { const elementsToModify = [ { selector: '.dt-search .form-control', classToRemove: 'form-control-sm' }, { selector: '.dt-length .form-select', classToRemove: 'form-select-sm', classToAdd: 'ms-0' }, { selector: '.dt-length', classToAdd: 'mb-md-6 mb-0' }, { selector: '.dt-buttons', classToAdd: 'justify-content-center' }, { selector: '.dt-layout-table', classToRemove: 'row mt-2' }, { selector: '.dt-layout-end', classToAdd: 'gap-md-2 gap-0 mt-0' }, { selector: '.dt-layout-full', classToRemove: 'col-md col-12', classToAdd: 'table-responsive' } ]; // Delete record elementsToModify.forEach(({ selector, classToRemove, classToAdd }) => { document.querySelectorAll(selector).forEach(element => { if (classToRemove) { classToRemove.split(' ').forEach(className => element.classList.remove(className)); } if (classToAdd) { classToAdd.split(' ').forEach(className => element.classList.add(className)); } }); }); }, 100); });