are there any bugs in the following code? const HEADER = document.querySelector('header')
const FORM = document.querySelector('#form')
const TABLE = document.querySelector('#table')
const ACTIONS_WRAP = document.querySelector('.actions-wrap')
const API_URL = '/data.json'

let LAST_SAVED_DATA = [];
let UI_DATA = [];
let IS_UNSAVED_CHANGES = false;
const SELECTED_ROW = { id: null, data: null, html: null }

async function fetchData(url) {
    try {
        const res = await fetch(url);
        const json = await res.json();
        return json
    } catch (e) {
        console.log(e)
        return []
    }
}

function getUIDataItemIndex(id) {
    return UI_DATA.findIndex(el => el.id === id)
}

function swapArrayIndex(arr, index1, index2) {
    const temp = arr[index1]
    arr[index1] = arr[index2]
    arr[index2] = temp
}

function swapRowIndex(row1, row2) {
    const index1 = row1.children[1].textContent
    const index2 = row2.children[1].textContent

    row1.children[1].textContent = index2
    row2.children[1].textContent = index1
}

function saveData() {
    LAST_SAVED_DATA = JSON.parse(JSON.stringify(UI_DATA))
}

function resetSelectionData() {
    SELECTED_ROW.data = null
    SELECTED_ROW.html = null
}

function refreshUIData() {
    UI_DATA = JSON.parse(JSON.stringify(LAST_SAVED_DATA))
}

function sortUIData(property, dir) {
    UI_DATA.sort((a, b) => {
        if (dir === 'asc') {
            return a[property].localeCompare(b[property], undefined, { numeric: true });
        } else {
            return b[property].localeCompare(a[property], undefined, { numeric: true });
        }
    });
}

function populateForm(data) {
    FORM.chemical_name.value = data.chemical_name;
    FORM.vendor.value = data.vendor;
    FORM.density.value = data.density;
    FORM.viscosity.value = data.viscosity;
    FORM.packaging.value = data.packaging;
    FORM.pack_size.value = data.pack_size;
    FORM.unit.value = data.unit;
    FORM.quantity.value = data.quantity;
}

function toggleForm() {
    HEADER.classList.toggle('show-form')

    removeAllModes()
    if (HEADER.classList.contains('show-form')) {
        formMode()
    } else {
        if (SELECTED_ROW.data) {
            selectedMode()
        } else {
            idealMode()
        }
    }
}

function createCell(text) {
    const cell = document.createElement('td');
    cell.textContent = text;
    return cell
}

function createRow(obj, index) {
    const row = document.createElement('tr');

    const selectBox = createCell(`\u2714`);
    selectBox.classList.add('select-box');
    row.appendChild(selectBox);

    row.dataset.id = obj['id']
    const rowIndexCell = createCell(index);
    row.appendChild(rowIndexCell)

    for (const key in obj) {
        if (key === 'id') {
            continue
        }

        const cell = createCell(obj[key])
        cell.dataset.property = key
        row.appendChild(cell);
    }

    return row
}

function createTableBody(arrayOfObjs) {
    const fragment = document.createDocumentFragment();

    const tbody = document.createElement('tbody');
    fragment.appendChild(tbody)

    arrayOfObjs.forEach((obj, index) => {
        const row = createRow(obj, index + 1)
        tbody.appendChild(row);
    });
    return fragment
}

function selectRow(clickedArea) {
    const cell = clickedArea

    if (!cell.classList.contains('select-box')) {
        return
    }

    const clickedRow = cell.parentElement

    removeAllModes()

    if (clickedRow.classList.contains('active')) {
        clickedRow.classList.remove('active')

        resetSelectionData()
        idealMode()
    } else {
        const allRows = TABLE.lastElementChild.children
        for (let i = 0; i < allRows.length; i++) {
            allRows[i].classList.remove('active')
        }
        clickedRow.classList.add('active')
        SELECTED_ROW.data = UI_DATA[getUIDataItemIndex(clickedRow.dataset.id)]
        SELECTED_ROW.html = clickedRow
        selectedMode()
    }
}

function deleteRow() {
    if (SELECTED_ROW.data === null || SELECTED_ROW.html === null) {
        return
    }

    // ui
    let currentRow = SELECTED_ROW.html;
    let currentRowIndex = parseInt(currentRow.children[1].textContent);
    while (currentRow) {
        currentRow.children[1].textContent = currentRowIndex - 1
        currentRowIndex++
        currentRow = currentRow.nextElementSibling
    }

    SELECTED_ROW.html.remove();

    // data
    const deletedItemDataIndex = getUIDataItemIndex(SELECTED_ROW.data)
    UI_DATA.splice(deletedItemDataIndex, 1)

    resetSelectionData()
}

function moveRowUp() {
    if (SELECTED_ROW.data === null || SELECTED_ROW.html === null) {
        return
    }

    const currentRow = SELECTED_ROW.html
    const previousRow = currentRow.previousElementSibling;

    if (previousRow) {
        const previousRowDataId = getUIDataItemIndex(previousRow.dataset.id)
        currentRow.parentNode.insertBefore(currentRow, previousRow);
        swapRowIndex(previousRow, currentRow)
        swapArrayIndex(UI_DATA, previousRowDataId, previousRowDataId + 1)
    }
}

function moveRowDown() {
    if (SELECTED_ROW.data === null || SELECTED_ROW.html === null) {
        return
    }

    const currentRow = SELECTED_ROW.html
    const nextRow = currentRow.nextElementSibling;

    if (nextRow) {
        const nextItemDataIndex = getUIDataItemIndex(nextRow.dataset.id)
        currentRow.parentNode.insertBefore(nextRow, currentRow);
        swapRowIndex(nextRow, currentRow)
        swapArrayIndex(UI_DATA, nextItemDataIndex, nextItemDataIndex - 1)
    }
}

function refreshTableUI(data) {
    const html = createTableBody(data)
    TABLE.lastElementChild.remove()
    TABLE.append(html)
}

function removeAllModes() {
    HEADER.classList.remove('show-toggle-form', 'show-edit', 'show-delete', 'show-moveup', 'show-movedown', 'show-refresh', 'show-save')
}

function idealMode() {
    HEADER.classList.add('show-toggle-form', 'show-refresh', 'show-save')
}

function selectedMode() {
    HEADER.classList.add('show-edit', 'show-delete', 'show-moveup', 'show-movedown', 'show-refresh', 'show-save')
}

function formMode() {
    HEADER.classList.add('show-toggle-form')
}

// init
fetchData(API_URL)
    .then(res => {
        LAST_SAVED_DATA = JSON.parse(JSON.stringify(res));
        UI_DATA = JSON.parse(JSON.stringify(LAST_SAVED_DATA));

        const html = createTableBody(UI_DATA)
        TABLE.append(html)

        // changes observer
        const observer = new MutationObserver(function () {
            IS_UNSAVED_CHANGES = true
        });
        const observerConfig = { attributes: true, childList: true, subtree: true }
        observer.observe(TABLE, observerConfig);

        TABLE.addEventListener('click', function (e) {

            const clickedArea = e.target;

            selectRow(clickedArea)

            // sorting
            if (clickedArea.dataset.sortProperty !== undefined) {
                const direction = clickedArea.dataset.sortDirection
                sortUIData(clickedArea.dataset.sortProperty, direction)
                clickedArea.dataset.sortDirection = direction === "asc" ? "dsc" : "asc"

                refreshTableUI(UI_DATA)
                resetSelectionData()
            }
        });

        ACTIONS_WRAP.addEventListener('click', function (e) {

            const action = e.target.dataset.action;

            switch (action) {
                case 'edit':
                    FORM.dataset.mode = 'edit'
                    toggleForm()
                    populateForm(SELECTED_ROW.data)
                    break

                case 'toggle-form':
                    toggleForm()
                    break

                case 'moveup':
                    moveRowUp()
                    break

                case 'movedown':
                    moveRowDown()
                    break

                case 'delete':
                    deleteRow()
                    break

                case 'refresh':
                    if (IS_UNSAVED_CHANGES) {
                        const userConfimation = window.confirm('Contains Unsaved Changes, Refresh?')

                        if (!userConfimation) {
                            return
                        }
                    } else {
                        observer.disconnect()
                        refreshUIData()
                        refreshTableUI(LAST_SAVED_DATA)
                        removeAllModes()
                        idealMode()
                        IS_UNSAVED_CHANGES = false
                        observer.observe(TABLE, observerConfig)
                    }
                    break

                case 'save':
                    saveData()
                    IS_UNSAVED_CHANGES = false
                    break

                default:
                    return
            }
        })

        FORM.addEventListener('submit', function (e) {
            e.preventDefault()
            const formData = new FormData(e.target)
            const data = Object.fromEntries(formData.entries())

            if (FORM.dataset.mode === 'edit') {
                FORM.dataset.mode = 'add'
                UI_DATA[getUIDataItemIndex(SELECTED_ROW.data)] = data
            } else {
                UI_DATA.push(data)
            }

            FORM.reset()
            toggleForm()

            refreshTableUI(UI_DATA)
            resetSelectionData()
            removeAllModes()
            idealMode()
        });

        FORM.addEventListener('reset', function(e){
            FORM.reset()
            toggleForm();
            removeAllModes();
            idealMode();
        })
    }).catch(function (e) {
        console.log(e)
    })