1--FOOTER
---Refactored FOOTER to use slogan in setting, and version in config

----------------------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------------------

2---MENU
    --LOGO
        Refactored Menu to use, Logo image logo.png from public/images/app_images
    --USER DROP DOWN
        Refactored user dropdown to use users photos in /public/uploads/users_photos saved by person_id.png
        Separated the dropdown from the other link list 
        added a column in my peoples table 
        
        ALTER TABLE `ospos_people` ADD COLUMN `photo` VARCHAR(255) DEFAULT NULL AFTER `person_id`;
        
        
    --MENU ITEMS LIST
        Refactored menu to be mobile friendly
        Separated the dropdown from the other link list 
    --THEME MODE SWITCH
        --CREATED A CONTROLLER IN home.php controller for saving the theme
            public function save_theme_preference()
----------------------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------------------

3--FONTS
    --DOWNLOAD
        Downloaded roboto and open sans in my public/fonts folder
    --FONT.CSS
        Created a font.css in public/dist
        --FONT FACE DECLARION
        
                @font-face {
                    font-family: 'Open Sans';
                    font-weight: 400; /* Regular */
                    src: url('../fonts/OpenSans-Regular.ttf') format('truetype');
                }
                
            --Tells the browser: "When you see text that should use 'Open Sans' with weight 400, load this .ttf file"
                Each weight (300, 400, 500, 700) gets its own @font-face declaration
        
        --CSS VARIABLES FOR CONSISTENCY
                Creates reusable variables you can use anywhere
                Fallback fonts in case your custom fonts don't load
        
                :root {
                    --font-primary: 'Open Sans', Arial, sans-serif;
                    --font-secondary: 'Roboto', Arial, sans-serif;
                }
        --AUTOMATIC APPLICATION AND PROTECTION
        
        /* Apply to text elements */
        body, p, h1, h2, button, input {
            font-family: var(--font-primary) !important;
        }
        
        /* BUT protect Font Awesome */
        .fas, .far, .fab {
            font-family: 'Font Awesome 5 Free' !important;
        }
        
        --CONVERTED FROM TTF TO WOFF2
        Converted my font format to WOFF2 using https://cloudconvert.com/ttf-converter
        Updated my font css to use the new format and fall back to tff
        
        
        /* Open Sans Font Faces */
        @font-face {
            font-family: 'Open Sans';
            font-style: normal;
            font-weight: 400; /* Regular */
            src: url('../fonts/OpenSans-Regular.woff2') format('woff2'),
                 url('../fonts/OpenSans-Regular.ttf') format('truetype');
            font-display: swap;
        }
        
        @font-face {
            font-family: 'Open Sans';
            font-style: normal;
            font-weight: 500; /* Medium */
            src: url('../fonts/OpenSans-Medium.woff2') format('woff2'),
                 url('../fonts/OpenSans-Medium.ttf') format('truetype');
            font-display: swap;
        }
----------------------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------------------
4. LOGIN
---GET LOGO AND BG AND OTHER DATA FROM DB
images/app_images
------INSERTED FOLLOWING VALUES

INSERT INTO `ospos_app_config` (`key`, `value`) VALUES
('is_darkmode', '0'), /* 0 for Light Mode (Default), 1 for Dark Mode */
('dark_logo', 'logo_dark.png'),
('light_logo', 'logo.png'),
('dark_bg', 'bg_dark.png'),
('light_bg', 'bg.png'),
('app_slogan', 'Your Default App Slogan'), /* Placeholder value */
('app_version', '1.0'), /* Placeholder value */
('app_commit', '1.0'), /* Placeholder value */
('business_code', 'BCODE'), /* Placeholder value */
('business_slogan', 'Your Default Business Slogan'), /* Placeholder value */
('payments_details', 'Your Payments'); /* Placeholder value */
('business_type', 'fashion'), /* Placeholder value */
('business_avatar', 'fashion.png'); /* Placeholder value */
----------------------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------------------

5. COLUMN VISIBILITY BY DEFAULT
----UPDATED TABULAR_HEADER AND UPDATED COLUMN TO BE HIDDEN BY DEFAULT

changes made to the transform_headers function in the tabular_views_helper.php file to implement column hiding.

The only function modified is transform_headers.

⚙️ Changes in transform_headers

I've added the missing $CI =& get_instance(); line and, most importantly, the 'visible' key to control column display.

/*
Basic tabular headers function
*/
function transform_headers($array, $readonly = FALSE, $editable = TRUE)
{
    $CI =& get_instance(); // <-- ADDED: Necessary to access CI functions like $CI->config->item later if needed.
    $result = array();

    if(!$readonly)
    {
        $array = array_merge(array(array('checkbox' => 'select', 'sortable' => FALSE)), $array);
    }

    if($editable)
    {
        $array[] = array('edit' => '');
    }

    foreach($array as $element)
    {
        // Extract key and value for the column
        $field_name = key($element); // <-- MODIFIED/CLEANED UP: Explicitly getting key/value
        $title_value = current($element); // <-- MODIFIED/CLEANED UP: Explicitly getting key/value

        // reset($element); // <-- REMOVED: Replaced by explicit key/current calls
        
        $result[] = array('field' => $field_name,
            'title' => $title_value,
            'switchable' => isset($element['switchable']) ? $element['switchable'] : !preg_match('(^$|&nbsp)', $title_value),
            
            // ** START: COLUMN HIDING LOGIC - NEW LINES ADDED **
            // This logic checks if 'visible' is already set in the array element. 
            // If not, it defaults to TRUE unless the column is in the list of fields to hide.
            'visible' => isset($element['visible']) ? $element['visible'] : ($field_name != 'email' && $field_name != 'last_name' && $field_name != 'people.person_id'  && $field_name != 'people.person_idagency_name'
            && $field_name != 'items.item_id' && $field_name != 'item_number' && $field_name != 'company_name' && $field_name != 'category' && $field_name != 'cost_price'
            && $field_name != 'sale_id' && $field_name != 'change_due' && $field_name != 'amount_tendered' && $field_name != 'payment_type' && $field_name != 'invoice' && $field_name != 'invoice_number'
            && $field_name != 'expense_id' && $field_name != 'supplier_tax_code' && $field_name != 'tax_amount' && $field_name != 'category_name' && $field_name != 'description' && $field_name != 'created_by' 
            && $field_name != 'giftcard_id'),
            // ** END: COLUMN HIDING LOGIC **
            
            'escape' => !preg_match("/(edit|phone_number|email|messages|item_pic)/", $field_name) && !(isset($element['escape']) && !$element['escape']),
            'sortable' => isset($element['sortable']) ? $element['sortable'] : $title_value != '',
            'checkbox' => isset($element['checkbox']) ? $element['checkbox'] : FALSE,
            'class' => isset($element['checkbox']) || preg_match('(^$|&nbsp)', $title_value) ? 'print_hide' : '',
            'sorter' => isset($element['sorter']) ? $element ['sorter'] : '');
    }

    return json_encode($result);
}
--------------------------------------------------------------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------------------------------------------
6. BREADCRUMBS
---Created a helper breadcrumb_helper.php
<?php
function get_breadcrumb_data($controller_name, $method_name)
{
    $CI =& get_instance(); 
    // 1. Get the main page title (e.g., "Customers" from language file)
    // The language line key for a module is often 'module_name' . '_title' (e.g., 'customers_title')
    $page_title_key = $controller_name . '_title';
    $page_title = $CI->lang->line($page_title_key); 

    // Default breadcrumb is just the main page title
    $breadcrumb_text = $page_title;

    // 2. Logic for detail/action pages (e.g., 'view', 'edit')
    if ($method_name && $method_name != 'index') {
        $detail_methods = ['view', 'edit', 'clone', 'receive', 'register', 'manage']; // Add all your action methods
        if (in_array($method_name, $detail_methods)) {
            // Get localized action name (e.g., "New" or "Edit")
            $action_key = (strpos($method_name, 'view') !== false) ? 'common_new' : 'common_edit'; // Adjust logic as needed
            $action_text = $CI->lang->line($action_key);
            
            // Build the full breadcrumb: "Localized Module Title > Localized Action"
            $main_page_url = site_url($controller_name);
            $breadcrumb_text = '<a href="' . $main_page_url . '">' . $page_title . '</a> &nbsp;&rsaquo;&nbsp; ' . $action_text;
        }
    }

    return [
        'page_title' => $page_title,          // Simple title for mobile (e.g., "Customers")
        'breadcrumb_text' => $breadcrumb_text // Full trail for desktop (e.g., "Customers > New")
    ];
}

---UPDATED IT IN AUTOLOAD 
----CALL IT IN CONTROLLER
// Inside People.php (or your controller extending Secure_Controller)

public function index()
{
    // Make sure the helper is loaded (usually in constructor or Secure_Controller)
    // $this->load->helper('breadcrumb');
    
    // Get the breadcrumb data for the current view
    $data = get_breadcrumb_data(strtolower($this->router->fetch_class()), $this->router->fetch_method());
    
    // Pass the data to the view
    $data['controller_name'] = strtolower($this->router->fetch_class());
    $this->load->view('people/manage', $data);
}

step 3: Implement HTML in people/manage.php (PHP/HTML)

You need to define three primary header sections:

    Desktop Breadcrumb Container: Hides on mobile.

    Mobile Title Container: Hides on desktop.

    Desktop Buttons: Hides on mobile (these are your import/new buttons).

    File: application/views/people/manage.php
    
    
    <div id="title_bar" class="btn-toolbar">
    <div class="pull-left desktop-breadcrumb-container print_hide">
        <h3 class="desktop-breadcrumb">
            <?php echo $breadcrumb_text; ?>
        </h3>
    </div>
    
    <?php
    if ($controller_name == 'customers')
    {
    // ... Import Button Code Here ... 
    }
    ?>
    </div>

<div id="mobile_title_bar" class="print_hide">
    <h4 id="mobile_page_title">
        <?php echo $page_title; ?> </h4>
</div>

<div id="mobile_header_toolbar">
    </div>
    
----CSS STYLING    
/* --- GLOBAL/DEFAULT RULES (Desktop by default, Mobile hidden) --- */
#mobile_title_bar {
    display: none !important; /* Hide mobile title on desktop */
}
.desktop-breadcrumb-container {
    float: left;
    margin-right: 20px;
}
.desktop-breadcrumb {
    font-size: 20px;
    margin: 10px 0;
}


/* --- MOBILE STYLES (max-width: 767px) --- */
@media (max-width: 767px) {
    /* Hide the desktop components */
    .desktop-breadcrumb-container {
        display: none !important;
    }
    #title_bar {
        display: none !important; /* The main desktop toolbar */
    }

    /* Show and style the new mobile title bar */
    #mobile_title_bar {
        display: block !important;
        padding: 10px 15px;
        background-color: #f8f8f8;
        border-bottom: 1px solid #ddd;
        text-align: left;
    }
    
    /* Style the title text inside */
    #mobile_page_title {
        font-size: 1.2em;
        font-weight: bold;
        margin: 0;
    }
    
    /* Ensure the untouched mobile header toolbar still functions */
    #mobile_header_toolbar {
        border-top: none !important; /* Remove any lingering top border */
    }
}


/* --- DESKTOP STYLES (min-width: 768px) --- */
@media (min-width: 768px) {
    /* Ensure desktop components are visible */
    #title_bar {
        display: block !important;
    }
    .desktop-breadcrumb-container {
        display: block !important; /* Show desktop breadcrumb */
    }
}

----USING LANGFILE
How the Helper Uses the Language File

Your get_breadcrumb_data function (Step 1 of the previous checklist) already contains the critical lines that perform the localization:
PHP

// Inside get_breadcrumb_data() in your helper:

// 1. Localizing the Module Title
$page_title_key = $controller_name . '_title'; // e.g., 'customers_title'
$page_title = $CI->lang->line($page_title_key); 
// This fetches the value defined in your language file.

// 2. Localizing the Action Name (for the full breadcrumb)
$action_key = (strpos($method_name, 'view') !== false) ? 'common_new' : 'common_edit';
$action_text = $CI->lang->line($action_key);
// This fetches the value defined for 'common_new' or 'common_edit'.



--------------------------------------------------------------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------------------------------------------
6. SWEETALERTS
--------1. Included library links in header
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/sweetalert2@11/dist/sweetalert2.min.css">

<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11/dist/sweetalert2.all.min.js"></script>

--------2. JavaScript Helper Functions (sweetalerts.js) 
Created folder assets/js since it wasnt available
We will create two main JS functions: one for Toast notifications (for success/error flashdata) and one for standard Alerts/Confirmations.

File: Save this code as assets/js/sweetalerts.js

--------3. PHP Helper Function (sweetalerts_helper.php)
This helper is used to set flashdata in your controller and to create a wrapper for confirmation dialogs.

File: Save this code as application/helpers/sweetalerts_helper.php

-------------USAGE--------------
--------A. Load the Helper
In your main controller constructor or autoload configuration, ensure the helper is loaded:

--------B. Display the Alerts
In your view file (e.e.g., partial/footer.php), call the render function:
Call the render_sweet_alerts() Function in my partial/footer.php
        
        <?php echo render_sweet_alerts(); ?>

--------C. In Your Controller
Replace your old flashdata calls:

PHP

// OLD WAY: $this->session->set_flashdata('success', 'Item saved!');
// NEW WAY: 
set_success_alert('Item saved successfully!');

--------4. Converting Existing JavaScript
Your existing JavaScript confirmation logic needs to be updated to use the new showConfirm function instead of the native confirm().

Original JS:

JavaScript

$('#cancel_sale_button').click(function() {
    if(confirm(LANG.CONFIRM_CANCEL_SALE))
    {
        $buttonsForm.attr('action', CONTROLLER_URL + '/cancel').submit();
    }
});
Updated JS:

Replace the old block with this new, cleaner, promise-based logic that uses showConfirm:

JavaScript

$('#cancel_sale_button').click(function(e) {
    // Prevent default form submission while confirmation runs
    e.preventDefault(); 
    
    // Use the new showConfirm helper function
    showConfirm('Confirm Sale Cancellation', LANG.CONFIRM_CANCEL_SALE, 'warning')
        .then((confirmed) => {
            if (confirmed) {
                // If confirmed, proceed with form submission
                $buttonsForm.attr('action', CONTROLLER_URL + '/cancel').submit();
            }
        });
});
By completing these four steps, you will have centralized, uniform, and modern SweetAlerts across your entire application, both desktop and mobile.
        

--------------------------------------------------------------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------------------------------------------
6. BREAKEVEN AND DAILY GOALS
INSERT INTO `ospos_app_config` (`key`, `value`) VALUES ('fixed_monthly_expenses', '150000');
INSERT INTO `ospos_app_config` (`key`, `value`) VALUES ('daily_sales_goal', '15000');        