Source: datatableUtils/datatableUtils.js

import { NavigationMixin } from 'lightning/navigation';
import { ShowToastEvent } from 'lightning/platformShowToastEvent';
import { deleteRecord, updateRecord } from 'lightning/uiRecordApi';

/**
 * Dispatches a toast event on the given component.
 * @param {LightningElement} component - The component instance
 * @param {string} title - Toast title
 * @param {string} message - Toast message
 * @param {string} variant - Toast variant (success, error, warning, info)
 */
export function showToast(component, title, message, variant) {
  component.dispatchEvent(new ShowToastEvent({ title, message, variant }));
}

/**
 * Navigates to a record page using the NavigationMixin.
 * @param {LightningElement} component - The component instance (must extend NavigationMixin)
 * @param {string} recordId - The record Id to navigate to
 * @param {string} actionName - The navigation action ('view' or 'edit')
 */
export function navigateToRecord(component, recordId, actionName) {
  component[NavigationMixin.Navigate]({
    type: 'standard__recordPage',
    attributes: { recordId, actionName }
  });
}

/**
 * Handles row action events from lightning-datatable.
 * @param {LightningElement} component - The component instance
 * @param {Event} event - The rowaction event
 * @param {Function} refreshFn - Function to refresh data after delete
 */
export function handleRowAction(component, event, refreshFn) {
  const actionName = event.detail.action.name;
  const row = event.detail.row;
  switch (actionName) {
    case 'view':
      navigateToRecord(component, row.Id, 'view');
      break;
    case 'edit':
      navigateToRecord(component, row.Id, 'edit');
      break;
    case 'delete':
      deleteCurrentRecord(component, row.Id, refreshFn);
      break;
    default:
  }
}

/**
 * Appends row action columns to the columns array.
 * @param {Array} columns - The columns array to modify
 * @param {boolean} showView - Whether to show the View action
 * @param {boolean} showEdit - Whether to show the Edit action
 * @param {boolean} showDelete - Whether to show the Delete action
 */
export function addRowActions(columns, showView, showEdit, showDelete) {
  const actions = [];
  if (showView) actions.push({ label: 'View', name: 'view' });
  if (showEdit) actions.push({ label: 'Edit', name: 'edit' });
  if (showDelete) actions.push({ label: 'Delete', name: 'delete' });
  if (actions.length) {
    columns.push({ type: 'action', typeAttributes: { rowActions: actions, menuAlignment: 'right' } });
  }
}

/**
 * Handles row selection events from lightning-datatable.
 * @param {LightningElement} component - The component instance
 * @param {Event} event - The rowselection event
 */
export function getSelectedRecords(component, event) {
  component.selectedRecords = event.detail.selectedRows;
  component.hasSelectedRecords = component.selectedRecords.length > 0;
}

/**
 * Builds the properties object passed to the datatable extension component.
 * @param {LightningElement} component - The component instance
 * @returns {Object} The datatable properties
 */
export function buildDatatableProperties(component) {
  return {
    keyField: component.keyField,
    data: component.records,
    columns: component.columns,
    columnWidthsMode: component.columnWidthsMode,
    defaultSortDirection: component.defaultSortDirection,
    draftValues: component.draftValues,
    hideCheckboxColumn: component.hideCheckboxColumn,
    hideTableHeader: component.hideTableHeader,
    maxColumnWidth: component.maxColumnWidth,
    maxRowSelection: component.maxRowSelection,
    minColumnWidth: component.minColumnWidth,
    rowNumberOffset: component.computedRowNumberOffset,
    resizeColumnDisabled: component.resizeColumnDisabled,
    showRowNumberColumn: component.showRowNumberColumn,
    suppressBottomBar: component.suppressBottomBar
  };
}

/**
 * Deletes a single record and refreshes data.
 * @param {LightningElement} component - The component instance
 * @param {string} recordId - The record Id to delete
 * @param {Function} refreshFn - Function to refresh data after deletion
 */
export function deleteCurrentRecord(component, recordId, refreshFn) {
  component.isLoading = true;
  deleteRecord(recordId)
    .then(() => {
      showToast(component, 'Success', 'Record deleted', 'success');
      return refreshFn().then(() => {
        component.isLoading = false;
      });
    })
    .catch((error) => {
      showToast(component, 'Error deleting record', error.body.message, 'error');
    });
}

/**
 * Handles inline edit save by updating all draft records.
 * @param {LightningElement} component - The component instance
 * @param {Array} draftValues - The draft values from the save event
 * @param {Function} refreshFn - Function to refresh data after save
 */
export function handleSave(component, draftValues, refreshFn) {
  const recordInputs = draftValues.slice().map((draft) => ({ fields: { ...draft } }));
  const promises = recordInputs.map((recordInput) => updateRecord(recordInput));
  Promise.all(promises)
    .then(() => {
      showToast(component, 'Success', 'Records updated', 'success');
      return refreshFn().then(() => {
        component.draftValues = [];
      });
    })
    .catch((error) => {
      showToast(component, 'Error updating records', error.body.message, 'error');
    });
}

/**
 * Deletes multiple selected records and refreshes data.
 * @param {LightningElement} component - The component instance
 * @param {Array} selectedRecords - The records to delete
 * @param {Function} refreshFn - Function to refresh data after deletion
 */
export function deleteSelectedRecords(component, selectedRecords, refreshFn) {
  component.isLoading = true;
  const promises = selectedRecords.map((record) => deleteRecord(record.Id));
  Promise.all(promises)
    .then(() => {
      showToast(component, 'Success', 'Records deleted', 'success');
      return refreshFn().then(() => {
        component.isLoading = false;
      });
    })
    .catch((error) => {
      showToast(component, 'Error deleting records', error.body.message, 'error');
    });
}