render.php 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. <?php
  2. require_once __DIR__ . '/db.php';
  3. function h(?string $s): string {
  4. return htmlspecialchars($s ?? '', ENT_QUOTES, 'UTF-8');
  5. }
  6. // Render the job table for a given audience.
  7. // $audience: 'ICG' or 'vendor'
  8. // $vendor_id: required when $audience === 'vendor'
  9. function render_jobs_table(string $audience, ?int $vendor_id = null): string {
  10. $pdo = db();
  11. // Filter matches the original: open jobs OR anything touched in the last 4 days.
  12. $where = "(j.status != 'Received') OR (j.updated_at > datetime('now', '-4 days'))";
  13. $params = [];
  14. if ($audience === 'vendor') {
  15. $where = "j.vendor_id = ? AND ($where)";
  16. $params[] = $vendor_id;
  17. }
  18. $sql = "
  19. SELECT j.*, v.slug AS vendor_slug, v.name AS vendor_name,
  20. CASE WHEN j.due_date IS NULL THEN ''
  21. ELSE CAST(CAST(strftime('%m', j.due_date) AS INTEGER) AS TEXT) || '-' ||
  22. CAST(CAST(strftime('%d', j.due_date) AS INTEGER) AS TEXT)
  23. END AS due_short
  24. FROM jobs j
  25. JOIN vendors v ON v.id = j.vendor_id
  26. WHERE $where
  27. ORDER BY (j.status = '') DESC,
  28. (j.status = 'Finished') DESC,
  29. (j.status = 'Shipped') DESC,
  30. (j.ack = 'new') DESC,
  31. j.due_date IS NULL,
  32. j.due_date ASC,
  33. j.job
  34. ";
  35. $stmt = $pdo->prepare($sql);
  36. $stmt->execute($params);
  37. $rows = $stmt->fetchAll();
  38. ob_start();
  39. ?>
  40. <table class="jobs">
  41. <thead>
  42. <tr>
  43. <th>Job</th>
  44. <th>Material</th>
  45. <th>Description</th>
  46. <th class="right">Qty</th>
  47. <th class="center">Due</th>
  48. <?php if ($audience === 'ICG'): ?><th>Vendor</th><?php endif; ?>
  49. <th class="center">Ack</th>
  50. <th class="center">Status</th>
  51. <th class="center">Action</th>
  52. </tr>
  53. </thead>
  54. <tbody>
  55. <?php if (!$rows): ?>
  56. <tr><td colspan="<?= $audience === 'ICG' ? 9 : 8 ?>" class="empty">No active jobs.</td></tr>
  57. <?php endif; ?>
  58. <?php foreach ($rows as $r):
  59. $editable = ($audience === 'ICG');
  60. $jobClass = strlen($r['job']) > 9 ? 'smaller' : '';
  61. $statusClass = $r['status'] !== '' ? 'status-' . strtolower($r['status']) : '';
  62. $ackClass = $r['ack'] === 'new' ? 'ack-new' : '';
  63. ?>
  64. <tr data-job-id="<?= (int) $r['id'] ?>" class="<?= h($statusClass) ?>">
  65. <td class="<?= h($jobClass) ?>"><?= render_field($r, 'job', $editable) ?></td>
  66. <td><?= render_field($r, 'material', $editable) ?></td>
  67. <td class="center"><?= render_field($r, 'description', $editable) ?></td>
  68. <td class="right"><?= render_field($r, 'qty', $editable) ?></td>
  69. <td class="center"><?= render_due($r, $editable) ?></td>
  70. <?php if ($audience === 'ICG'): ?><td><?= h($r['vendor_name']) ?></td><?php endif; ?>
  71. <td class="center <?= h($ackClass) ?>"><?= $r['ack'] === 'new' ? 'NEW' : '' ?></td>
  72. <td class="center"><?= h($r['status']) ?></td>
  73. <td class="center actions"><?= render_actions($r, $audience) ?></td>
  74. </tr>
  75. <?php endforeach; ?>
  76. </tbody>
  77. </table>
  78. <?php
  79. return ob_get_clean();
  80. }
  81. function render_field(array $r, string $col, bool $editable): string {
  82. $val = (string) ($r[$col] ?? '');
  83. if (!$editable) {
  84. return h($val);
  85. }
  86. return '<span class="editable" data-column="' . h($col) . '" tabindex="0">'
  87. . ($val === '' ? '&mdash;' : h($val))
  88. . '</span>';
  89. }
  90. function render_due(array $r, bool $editable): string {
  91. $display = $r['due_short'] !== '' ? h($r['due_short']) : '&mdash;';
  92. if (!$editable) return $display;
  93. return '<span class="editable" data-column="due_date" data-raw="' . h($r['due_date']) . '" tabindex="0">'
  94. . $display . '</span>';
  95. }
  96. function render_actions(array $r, string $audience): string {
  97. $btns = [];
  98. if ($audience === 'vendor') {
  99. if ($r['ack'] === 'new') {
  100. $btns[] = '<button class="btn btn-ack" data-action="acknowledge">Acknowledge</button>';
  101. }
  102. if ($r['status'] === '') {
  103. $btns[] = '<button class="btn btn-finish" data-action="mark_finished">Mark Finished</button>';
  104. } elseif ($r['status'] === 'Finished') {
  105. $btns[] = '<button class="btn btn-ship" data-action="mark_shipped">Mark Shipped</button>';
  106. }
  107. } else { // ICG
  108. if ($r['status'] === 'Shipped') {
  109. $btns[] = '<button class="btn btn-receive" data-action="mark_received">Mark Received</button>';
  110. }
  111. if ($r['status'] === 'Received') {
  112. $btns[] = '<span class="received">Received</span>';
  113. }
  114. }
  115. return implode(' ', $btns);
  116. }
  117. function render_messages(int $vendor_id, ?int $since_id = null): string {
  118. $pdo = db();
  119. if ($since_id !== null) {
  120. $stmt = $pdo->prepare('SELECT * FROM messages WHERE vendor_id = ? AND id > ? ORDER BY id ASC');
  121. $stmt->execute([$vendor_id, $since_id]);
  122. } else {
  123. $stmt = $pdo->prepare('SELECT * FROM messages WHERE vendor_id = ? ORDER BY id ASC');
  124. $stmt->execute([$vendor_id]);
  125. }
  126. $rows = $stmt->fetchAll();
  127. ob_start();
  128. foreach ($rows as $m) {
  129. $klass = $m['author'] === 'ICG' ? 'msg msg-icg' : 'msg msg-vendor';
  130. echo '<div class="' . $klass . '" data-msg-id="' . (int)$m['id'] . '">';
  131. echo '<span class="msg-author">' . h($m['author']) . '</span>';
  132. echo '<span class="msg-time">' . h($m['posted_at']) . '</span>';
  133. echo '<div class="msg-body">' . nl2br(h($m['body'])) . '</div>';
  134. echo '</div>';
  135. }
  136. return ob_get_clean();
  137. }
  138. function max_message_id(int $vendor_id): int {
  139. $stmt = db()->prepare('SELECT COALESCE(MAX(id), 0) FROM messages WHERE vendor_id = ?');
  140. $stmt->execute([$vendor_id]);
  141. return (int) $stmt->fetchColumn();
  142. }