<?php
$B = htmlspecialchars(rtrim((string) ($baseUrl ?? ''), '/'));
if (!function_exists('pp_where')) {
    function pp_where(string $path, string $lang = 'php'): string {
        $l = $lang === 'js' ? 'JS' : 'PHP';
        return '<div class="help-where"><span class="help-where-tag"><i class="bi bi-geo-alt-fill"></i> Where</span>'
             . '<span class="help-where-path">' . $path . '</span>'
             . '<span class="help-where-lang ' . htmlspecialchars($lang) . '">' . $l . '</span></div>';
    }
}
?>
<h1><i class="bi bi-table"></i> The List page</h1>
<p class="lead">The List page shows many records in a grid — with search, sort, selection and bulk actions. This
guide walks its events and gives copy-ready recipes, each labelled with <strong>exactly where the code goes</strong>.</p>

<h2>Events this page fires</h2>
<table class="help-table">
    <thead><tr><th>Event</th><th>Where to write it</th><th>Use for</th></tr></thead>
    <tbody>
        <tr><td>Custom WHERE</td><td>Table → <b>SQL Modifiers</b></td><td>Filter which rows appear.</td></tr>
        <tr><td>Custom ORDER BY</td><td>Table → <b>SQL Modifiers</b></td><td>Set the default sort.</td></tr>
        <tr><td>After List Load</td><td>Table → <b>Page Events</b> (PHP)</td><td>Read/adjust the rows after they're fetched.</td></tr>
        <tr><td>Process Record Values</td><td>Table → <b>Page Events</b> (PHP)</td><td>Reshape a value just for display.</td></tr>
        <tr><td>After List Render</td><td>Table → <b>Client Events</b> (JS)</td><td>Colour rows, add handlers, totals.</td></tr>
        <tr><td>On Row Click / On Row Select</td><td>Table → <b>Client Events</b> (JS)</td><td>React to a click / a tick.</td></tr>
    </tbody>
</table>

<h2>Recipes</h2>

<h3>1 · Show only the current user's records</h3>
<?= pp_where('Events → <b>orders</b> → SQL Modifiers → <b>Custom WHERE</b>', 'php') ?>
<pre><code>// Return a WHERE clause (no leading "WHERE"). Non-admins see only their own rows.
if (!\PpPhp\Core\Auth\Permissions::isAdmin()) {
    return 'created_by = ' . (int) (\PpPhp\Core\Security::CurrentUserData()['id'] ?? 0);
}
return '';   // admins see everything</code></pre>

<h3>2 · Newest first by default</h3>
<?= pp_where('Events → <b>orders</b> → SQL Modifiers → <b>Custom ORDER BY</b>', 'php') ?>
<pre><code>return 'created_at DESC';</code></pre>

<h3>3 · Colour rows by a condition</h3>
<?= pp_where('Events → <b>orders</b> → Client Events → <b>After List Render</b>', 'js') ?>
<pre><code>Runner.rows().forEach(function (row) {
    if ((+row.get('balance') || 0) &lt; 0) row.highlight('rgba(220,38,38,.12)');   // overdue → red tint
    else if (row.get('status') === 'shipped') row.highlight('rgba(34,197,94,.10)');
});</code></pre>

<h3>4 · Show a running total under the grid</h3>
<?= pp_where('Events → <b>orders</b> → Client Events → <b>After List Render</b>', 'js') ?>
<pre><code>var total = Runner.getAllRecords().reduce(function (s, r) { return s + (+r.amount || 0); }, 0);
pp.dialog.toast('info', 'Total on this page: ' + total.toFixed(2));</code></pre>

<h3>5 · Bulk action on the ticked rows (toolbar Custom Button)</h3>
<p>Drop a <a href="<?= $B ?>/help/component_custom_button">Custom&nbsp;Button</a> on the list toolbar in the Designer,
then fill its three boxes:</p>
<?= pp_where('Designer → Custom Button → <b>Client Before</b>', 'js') ?>
<pre><code>params.ids = Runner.getSelectedKeys();
if (!params.ids.length) { pp.dialog.toast('warning', 'Select at least one row.'); return false; }</code></pre>
<?= pp_where('Designer → Custom Button → <b>Server</b>', 'php') ?>
<pre><code>$ids = array_map('intval', (array) ($params['ids'] ?? []));
if ($ids) {
    $in = implode(',', array_fill(0, count($ids), '?'));
    dbExecute("UPDATE orders SET status = 'shipped' WHERE id IN ($in)", $ids);
}
$result['count'] = count($ids);</code></pre>
<?= pp_where('Designer → Custom Button → <b>Client After</b>', 'js') ?>
<pre><code>pp.dialog.toast('success', result.count + ' order(s) marked shipped.');
Runner.reloadGrid();</code></pre>

<h3>6 · Hide the bulk “Delete selected” for non-admins</h3>
<?= pp_where('Events → <b>orders</b> → Client Events → <b>On Page Init</b>', 'js') ?>
<pre><code>// (expose a flag from PHP with pp_set_proxy, or check a data attribute you render)
Runner.hideButton('deleteSelected');</code></pre>

<h3>7 · Row click opens a custom action instead of the record</h3>
<?= pp_where('Events → <b>orders</b> → Client Events → <b>On Row Click</b>', 'js') ?>
<pre><code>// `record` is the clicked row's data; return false to prevent the default open
pp.dialog.alert('Order ' + record.reference, 'Total: ' + record.total);
return false;</code></pre>

<h3>8 · React to selection changes</h3>
<?= pp_where('Events → <b>orders</b> → Client Events → <b>On Page Init</b>', 'js') ?>
<pre><code>Runner.onSelectionChange(function (keys, records) {
    var sum = records.reduce(function (s, r) { return s + (+r.amount || 0); }, 0);
    console.log(keys.length + ' selected · ' + sum);
});</code></pre>

<div class="help-callout help-callout-info">
    <i class="bi bi-lightbulb"></i>
    <div>All the grid helpers — <code>Runner.rows()</code>, <code>getSelectedRecords()</code>,
        <code>reloadGrid()</code>, row <code>.highlight()</code> — are in the
        <a href="<?= $B ?>/help/PPjs">PP.js reference</a>. Filtering/sorting SQL is trusted, like
        <a href="<?= $B ?>/help/DB">DB helpers</a>.</div>
</div>
