Subversion Repositories SmartDukaan

Rev

Rev 35971 | Rev 36242 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

<link href="https://cdn.datatables.net/fixedcolumns/3.3.0/css/fixedColumns.bootstrap.css" rel="stylesheet"/>
<style>
        .timeline-table {
                width: 100%;
                border-collapse: collapse;
                font-size: 12px;
        }

        .timeline-table thead th {
                background: #2c3e50;
                color: #fff;
                padding: 6px 5px;
                text-align: center;
                font-weight: 600;
                font-size: 11px;
                border: 1px solid #34495e;
                white-space: nowrap;
        }

        .timeline-table tbody td {
                padding: 5px 4px;
                text-align: center;
                border: 1px solid #e0e0e0;
                vertical-align: middle;
                white-space: nowrap;
        }

        .timeline-table tbody tr:nth-child(even) {
                background-color: #f8f9fa;
        }

        .timeline-table tbody tr:hover {
                background-color: #eaf2ff;
        }

        .status-badge {
                display: inline-block;
                padding: 2px 6px;
                border-radius: 10px;
                font-size: 10px;
                font-weight: 600;
                text-transform: uppercase;
        }

        .status-open {
                background: #d4edda;
                color: #155724;
        }

        .status-pending {
                background: #fff3cd;
                color: #856404;
        }

        .status-completed {
                background: #cce5ff;
                color: #004085;
        }

        .status-hold {
                background: #f8d7da;
                color: #721c24;
        }

        .status-rejected {
                background: #e2e3e5;
                color: #383d41;
        }

        .tl-cell {
                display: inline-flex;
                align-items: center;
                gap: 5px;
        }

        .tl-dot {
                height: 8px;
                width: 8px;
                border-radius: 50%;
                display: inline-block;
                flex-shrink: 0;
        }

        .tl-dot.completed {
                background-color: #28a745;
        }

        .tl-dot.delay {
                background-color: #dc3545;
        }

        .tl-dot.wip {
                background-color: #ffc107;
        }

        .tl-dot.not-started {
                background-color: #adb5bd;
        }

        .tl-date {
                font-size: 10px;
                color: #555;
        }

        .legend {
                display: inline-flex;
                gap: 14px;
                flex-wrap: wrap;
                margin: 0;
        }

        .legend-item {
                display: flex;
                align-items: center;
                gap: 5px;
                font-size: 11px;
                color: #555;
        }

        .dataTables_wrapper .top-controls {
                display: flex;
                align-items: center;
                justify-content: space-between;
                flex-wrap: nowrap;
                padding: 8px 0;
        }

        .dataTables_wrapper .top-controls .dataTables_length {
                flex-shrink: 0;
        }

        .dataTables_wrapper .top-controls .timeline-legend-row {
                flex: 1;
                display: flex;
                justify-content: center;
        }

        .dataTables_wrapper .top-controls .dataTables_filter {
                flex-shrink: 0;
}

        .section-header {
                font-size: 11px;
                color: #95a5a6;
                text-transform: uppercase;
                letter-spacing: 0.5px;
                padding: 2px 0;
        }

        .timeline-table tbody tr {
                cursor: pointer;
        }

        .timeline-table tbody tr.row-selected,
        .DTFC_LeftBodyWrapper table tbody tr.row-selected {
                background-color: #d6eaf8 !important;
        }

        .ob-stepper {
                display: flex;
                align-items: center;
                justify-content: center;
                margin: 0 0 20px;
                padding: 0;
        }

        .ob-step {
                display: flex;
                align-items: center;
        }

        .ob-step-circle {
                width: 28px;
                height: 28px;
                border-radius: 50%;
                display: flex;
                align-items: center;
                justify-content: center;
                font-size: 11px;
                font-weight: 700;
                color: #fff;
                flex-shrink: 0;
        }

        .ob-step-circle.completed {
                background: #28a745;
        }

        .ob-step-circle.inProgress {
                background: #007bff;
        }

        .ob-step-circle.notStarted {
                background: #adb5bd;
        }

        .ob-step-line {
                width: 50px;
                height: 3px;
        }

        .ob-step-line.completed {
                background: #28a745;
        }

        .ob-step-line.inProgress {
                background: #007bff;
        }

        .ob-step-line.notStarted {
                background: #dee2e6;
        }

        .ob-step-label {
                font-size: 10px;
                text-align: center;
                margin-top: 4px;
                color: #555;
        }

        .ob-step-wrap {
                display: flex;
                flex-direction: column;
                align-items: center;
        }

        .ob-kv .row {
                padding: 4px 0;
                border-bottom: 1px solid #f0f0f0;
        }

        .ob-kv .text-muted {
                font-size: 12px;
        }

        .ob-kv .col-sm-8 {
                font-size: 12px;
        }

        .ob-badge-ok {
                display: inline-block;
                padding: 2px 8px;
                border-radius: 3px;
                background: #d4edda;
                color: #155724;
                font-size: 11px;
        }

        .ob-badge-fail {
                display: inline-block;
                padding: 2px 8px;
                border-radius: 3px;
                background: #f8d7da;
                color: #721c24;
                font-size: 11px;
        }

        .ob-badge-pending {
                display: inline-block;
                padding: 2px 8px;
                border-radius: 3px;
                background: #fff3cd;
                color: #856404;
                font-size: 11px;
        }

        .ob-badge-na {
                display: inline-block;
                padding: 2px 8px;
                border-radius: 3px;
                background: #e2e3e5;
                color: #6c757d;
                font-size: 11px;
        }

        a.ob-step-circle {
                text-decoration: none;
                color: #fff;
                cursor: pointer;
                transition: transform 0.15s, box-shadow 0.15s;
        }

        a.ob-step-circle:hover {
                transform: scale(1.2);
                box-shadow: 0 0 0 3px rgba(0, 123, 255, 0.3);
                color: #fff;
        }

        .ob-action-bar {
                padding: 8px 10px;
                margin-bottom: 12px;
                background: #f8f9fa;
                border: 1px solid #e9ecef;
                border-radius: 4px;
                display: flex;
                flex-wrap: wrap;
                gap: 8px;
                align-items: center;
        }

        .ob-action-bar .btn-warning {
                font-size: 11px;
                font-weight: 600;
        }

        .ob-action-bar .ob-badge-ok {
                font-size: 11px;
        }

        .loi-header {
                border-bottom: 2px solid #9b59b6;
        }

        .onb-header {
                border-bottom: 2px solid #2980b9;
        }

        .store-header {
                border-bottom: 2px solid #27ae60;
        }
</style>

<section class="wrapper">
        <div class="row">
                <div class="col-lg-12">
                        <h3 class="page-header" style="color:#2c3e50;">
                                <i class="icon_document_alt"></i> Partner Onboarding Timeline
                        </h3>
                        <ol class="breadcrumb">
                                <li><i class="fa fa-home"></i><a href="${rc.contextPath}/dashboard">Home</a></li>
                                <li><i class="icon_document_alt"></i>Onboarding Timeline</li>
                        </ol>
                </div>
        </div>

        <div class="col-lg-12" style="overflow-x:auto;">
                <table class="timeline-table" id="storeTimeline">
                        <thead>
                        <tr>
                                <th rowspan="2">ID</th>
                                <th rowspan="2">Partner</th>
                                <th rowspan="2">Code</th>
                                <th rowspan="2">Status</th>
                                <th colspan="4" style="background:#8e44ad;"><span class="section-header">LOI Process</span></th>
                                <th colspan="4" style="background:#2471a3;"><span class="section-header">Onboarding</span></th>
                                <th colspan="8" style="background:#1e8449;"><span class="section-header">Store Setup</span></th>
                                <th colspan="3" style="background:#d35400;"><span class="section-header">Launch</span></th>
                        </tr>
                        <tr>
                                <!-- LOI Process -->
                                <th style="background:#9b59b6;">LOI Form</th>
                                <th style="background:#9b59b6;">BM Approval</th>
                                <th style="background:#9b59b6;">Doc Approval</th>
                                <th style="background:#9b59b6;">Payment Approval</th>
                                <!-- Onboarding -->
                                <th style="background:#2980b9;">Onboarding</th>
                                <th style="background:#2980b9;">Verification</th>
                                <th style="background:#2980b9;">Store Code</th>
                                <th style="background:#2980b9;">Welcome Call</th>
                                <!-- Store Setup -->
                                <th style="background:#27ae60;">Recce</th>
                                <th style="background:#27ae60;">WOD</th>
                                <th style="background:#27ae60;">Fin Code</th>
                                <th style="background:#27ae60;">WOD-Fin Map</th>
                                <th style="background:#27ae60;">Branding</th>
                                <th style="background:#27ae60;">Full Stock</th>
                                <th style="background:#27ae60;">PO Creation</th>
                                <th style="background:#27ae60;">PO Approval</th>
                                <!-- Launch -->
                                <th style="background:#e67e22;">Billing</th>
                                <th style="background:#e67e22;">Inauguration</th>
                                <th style="background:#e67e22;">Training</th>
                        </tr>
                        </thead>
                        <tbody>
                                #foreach($st in $storeTimelines)
                                <tr>
                                        <td><strong>$st.getOnboardingId()</strong></td>
                                        <td style="text-align:left;max-width:120px;overflow:hidden;text-overflow:ellipsis;"
                                                title="$st.getOutletName() ($st.getCity())">$st.getOutletName() ($st.getCity())
                                        </td>
                                        #if($st.getCode())
                                                <td>$st.getCode()</td>
                                        #else
                                                <td style="color:#ccc;">-</td>
                                        #end
                                        <td>
                                                #set($statusLower = $st.getStatus().toLowerCase())
                                                #if($statusLower == "open")
                                                        <span class="status-badge status-open">$st.getStatus()</span>
                                                #elseif($statusLower == "pending")
                                                        <span class="status-badge status-pending">$st.getStatus()</span>
                                                #elseif($statusLower == "completed")
                                                        <span class="status-badge status-completed">$st.getStatus()</span>
                                                #elseif($statusLower == "hold")
                                                        <span class="status-badge status-hold">$st.getStatus()</span>
                                                #else
                                                        <span class="status-badge status-rejected">$st.getStatus()</span>
                                                #end
                                        </td>
                                        #if($st.getObtm() && $st.getObtm().size() > 0)
                                                #foreach($obtm in $st.getObtm())
                                                        #if($obtm.getStatus().toString() == "COMPLETED")
                                                                <td><span class="tl-cell"><span
                                                                                class="tl-dot completed"></span>#if($obtm.getCompletedTimestamp())<span
                                                                                class="tl-date">$obtm.getCompletedTimestamp().format($dateFormatter)</span>#end</span>
                                                                </td>
                                                        #elseif($obtm.getStatus().toString() == "DELAY")
                                                                <td style="background:#fff0f0;"><span class="tl-cell"><span
                                                                                class="tl-dot delay"></span>#if($obtm.getCompletedTimestamp())<span
                                                                                class="tl-date">$obtm.getCompletedTimestamp().format($dateFormatter)</span>#end</span>
                                                                </td>
                                                        #elseif($obtm.getStatus().toString() == "WIP")
                                                                <td style="background:#fffde7;"><span class="tl-cell"><span
                                                                                class="tl-dot wip"></span>#if($obtm.getCompletedTimestamp())<span
                                                                                class="tl-date">$obtm.getCompletedTimestamp().format($dateFormatter)</span>#end</span>
                                                                </td>
                                                        #elseif($obtm.getStatus().toString() == "NOT_STARTED")
                                                                <td><span class="tl-cell"><span
                                                                                class="tl-dot not-started"></span>#if($obtm.getCompletedTimestamp())<span
                                                                                class="tl-date">$obtm.getCompletedTimestamp().format($dateFormatter)</span>#end</span>
                                                                </td>
                                                        #else
                                                                <td style="color:#ccc;">-</td>
                                                        #end
                                                #end
                                        #else
                                                #foreach($i in [1..19])
                                                        <td style="color:#ccc;">-</td>
                                                #end
                                        #end
                                </tr>
                                #end
                        </tbody>
                </table>
        </div>

        <div id="timeline-detail-container" style="display:none; margin-top:15px;">
                <div class="panel panel-default">
                        <div class="panel-heading">
                                <button type="button" class="close" id="closeDetailPanel">&times;</button>
                                <h4 class="panel-title">
                                        <span id="detail-partner-name"></span>
                                        <small id="detail-partner-code" class="text-muted" style="margin-left:10px;"></small>
                                </h4>
                        </div>
                        <div class="panel-body" id="timeline-detail-body">
                                <div class="text-center"><i class="fa fa-spinner fa-spin"></i> Loading...</div>
                        </div>
                </div>
        </div>
</section>

<script type="text/javascript">
        $(document).ready(function () {
                var dtable = $('#storeTimeline').DataTable({
                        scrollX: true,
                        scrollY: '75vh',
                        scrollCollapse: true,
                        orderCellsTop: true,
                        order: [[0, "desc"]],
                        paging: false,
                        fixedColumns: {
                                leftColumns: 4
                        },
                        dom: '<"top-controls"f>rt<"bottom"i>',
                        language: {
                                search: "Search Partners:"
                        }
                });

                // Insert legend between length and filter controls
                var legendHtml = '<div class="timeline-legend-row">' +
                                '<div class="legend">' +
                                '<div class="legend-item"><span class="tl-dot completed"></span> Completed</div>' +
                                '<div class="legend-item"><span class="tl-dot wip"></span> In Progress</div>' +
                                '<div class="legend-item"><span class="tl-dot delay"></span> Delayed</div>' +
                                '<div class="legend-item"><span class="tl-dot not-started"></span> Not Started</div>' +
                                '</div></div>';
                $('#storeTimeline_wrapper .dataTables_length').after(legendHtml);

                // Row click -> load detail panel
                $('#storeTimeline tbody').on('click', 'tr', function () {
                        var $row = $(this);
                        var onboardingId = $.trim($row.find('td:first').text());
                        if (!onboardingId || isNaN(onboardingId)) return;

                        // Highlight selected row (both main table and fixed-column clone)
                        $('#storeTimeline tbody tr, .DTFC_LeftBodyWrapper table tbody tr').removeClass('row-selected');
                        var rowIndex = dtable.row($row).index();
                        $('#storeTimeline tbody tr').eq(rowIndex).addClass('row-selected');
                        $('.DTFC_LeftBodyWrapper table tbody tr').eq(rowIndex).addClass('row-selected');

                        var partnerName = $.trim($row.find('td:eq(1)').text());
                        var partnerCode = $.trim($row.find('td:eq(2)').text());

                        $('#detail-partner-name').text(partnerName);
                        $('#detail-partner-code').text(partnerCode !== '-' ? partnerCode : '');
                        $('#timeline-detail-body').html('<div class="text-center"><i class="fa fa-spinner fa-spin"></i> Loading...</div>');
                        $('#storeTimeline_wrapper').hide();
                        $('#timeline-detail-container').show();

                        $.ajax({
                                url: '${rc.contextPath}/partnerTimelineDetail',
                                data: {onboardingId: onboardingId},
                                success: function (html) {
                                        $('#timeline-detail-body').html(html);
                                },
                                error: function () {
                                        $('#timeline-detail-body').html('<div class="alert alert-danger">Failed to load details.</div>');
                                }
                        });

                        $('html, body').animate({scrollTop: $('#timeline-detail-container').offset().top - 60}, 300);
                });

                // Close detail panel
                $(document).on('click', '#closeDetailPanel', function () {
                        $('#timeline-detail-container').hide();
                        $('#storeTimeline_wrapper').show();
                        dtable.columns.adjust();
                        $('#storeTimeline tbody tr, .DTFC_LeftBodyWrapper table tbody tr').removeClass('row-selected');
                });
        });
</script>