diff --git a/app/Controllers/BoardsController.php b/app/Controllers/BoardsController.php index f21535d..411fa68 100644 --- a/app/Controllers/BoardsController.php +++ b/app/Controllers/BoardsController.php @@ -173,6 +173,35 @@ class BoardsController extends Controller return $this->redirect('/board/' . $board->slug); } + public function updateCardAgeSettings(Request $request, int $id): mixed + { + if (!AuthService::isLoggedIn()) { + return $this->json(['ok' => false, 'error' => 'Unauthorized'], 401); + } + + $row = $this->boards()->find($id); + if ($row === null) { + return $this->json(['ok' => false, 'error' => 'Not found'], 404); + } + + $showCardAge = (string) $request->input('show_card_age', '0') === '1'; + $cardAgeWarningDays = max(0, (int) $request->input('card_age_warning_days', 0)); + + $this->boards()->updateCardAgeSettings( + $id, + $showCardAge, + $cardAgeWarningDays, + date('Y-m-d H:i:s'), + AuthService::getCurrentUsername() + ); + + return $this->json([ + 'ok' => true, + 'show_card_age' => $showCardAge, + 'card_age_warning_days' => $cardAgeWarningDays, + ]); + } + public function destroy(string $slug): mixed { if ($guard = AuthService::requireLogin()) { diff --git a/app/Controllers/CardsController.php b/app/Controllers/CardsController.php index 5816866..8c97b71 100644 --- a/app/Controllers/CardsController.php +++ b/app/Controllers/CardsController.php @@ -47,6 +47,7 @@ class CardsController extends Controller $card->notes = trim((string) $request->input('notes', '')); $card->fullNote = (string) $request->input('full_note', ''); $card->position = $nextPos; + $card->cellEnteredAt = $now; $card->createdAt = $now; $card->createdBy = $username; $card->updatedAt = $now; diff --git a/app/Models/Board.php b/app/Models/Board.php index 16b8125..5c63830 100644 --- a/app/Models/Board.php +++ b/app/Models/Board.php @@ -11,6 +11,8 @@ class Board public string $slug = ''; public bool $importFromPrintstream = false; public string $printstreamJobName = ''; + public bool $showCardAge = false; + public int $cardAgeWarningDays = 0; public ?string $createdAt = null; public string $createdBy = ''; public ?string $updatedAt = null; @@ -24,6 +26,8 @@ class Board $model->slug = (string) ($row['slug'] ?? ''); $model->importFromPrintstream = (bool) ($row['import_from_printstream'] ?? false); $model->printstreamJobName = (string) ($row['printstream_job_name'] ?? ''); + $model->showCardAge = (bool) ($row['show_card_age'] ?? false); + $model->cardAgeWarningDays = (int) ($row['card_age_warning_days'] ?? 0); $model->createdAt = $row['created_at'] ?? null; $model->createdBy = (string) ($row['created_by'] ?? ''); $model->updatedAt = $row['updated_at'] ?? null; diff --git a/app/Models/Card.php b/app/Models/Card.php index e067676..4a99318 100644 --- a/app/Models/Card.php +++ b/app/Models/Card.php @@ -18,6 +18,7 @@ class Card public string $notes = ''; public string $fullNote = ''; public int $position = 0; + public ?string $cellEnteredAt = null; public ?string $createdAt = null; public string $createdBy = ''; public ?string $updatedAt = null; @@ -38,6 +39,7 @@ class Card $model->notes = (string) ($row['notes'] ?? ''); $model->fullNote = (string) ($row['full_note'] ?? ''); $model->position = (int) ($row['position'] ?? 0); + $model->cellEnteredAt = $row['cell_entered_at'] ?? null; $model->createdAt = $row['created_at'] ?? null; $model->createdBy = (string) ($row['created_by'] ?? ''); $model->updatedAt = $row['updated_at'] ?? null; @@ -60,6 +62,7 @@ class Card 'notes' => $this->notes, 'full_note' => $this->fullNote, 'position' => $this->position, + 'cell_entered_at' => $this->cellEnteredAt, ]; } } diff --git a/app/Repositories/BoardRepository.php b/app/Repositories/BoardRepository.php index f565341..2e69d94 100644 --- a/app/Repositories/BoardRepository.php +++ b/app/Repositories/BoardRepository.php @@ -63,14 +63,18 @@ class BoardRepository extends Repository { $this->database->execute( 'INSERT INTO boards - (name, slug, import_from_printstream, printstream_job_name, created_at, created_by, updated_at, updated_by) + (name, slug, import_from_printstream, printstream_job_name, show_card_age, card_age_warning_days, + created_at, created_by, updated_at, updated_by) VALUES - (:name, :slug, :import_from_printstream, :printstream_job_name, :created_at, :created_by, :updated_at, :updated_by)', + (:name, :slug, :import_from_printstream, :printstream_job_name, :show_card_age, :card_age_warning_days, + :created_at, :created_by, :updated_at, :updated_by)', [ 'name' => $board->name, 'slug' => $board->slug, 'import_from_printstream' => $board->importFromPrintstream ? 1 : 0, 'printstream_job_name' => $board->printstreamJobName, + 'show_card_age' => $board->showCardAge ? 1 : 0, + 'card_age_warning_days' => $board->cardAgeWarningDays, 'created_at' => $board->createdAt, 'created_by' => $board->createdBy, 'updated_at' => $board->updatedAt, @@ -102,4 +106,21 @@ class BoardRepository extends Repository ] ); } + + public function updateCardAgeSettings(int $id, bool $showCardAge, int $cardAgeWarningDays, string $updatedAt, string $updatedBy): void + { + $this->database->execute( + 'UPDATE boards + SET show_card_age = :show_card_age, card_age_warning_days = :card_age_warning_days, + updated_at = :updated_at, updated_by = :updated_by + WHERE id = :id', + [ + 'show_card_age' => $showCardAge ? 1 : 0, + 'card_age_warning_days' => $cardAgeWarningDays, + 'updated_at' => $updatedAt, + 'updated_by' => $updatedBy, + 'id' => $id, + ] + ); + } } diff --git a/app/Repositories/CardRepository.php b/app/Repositories/CardRepository.php index 625c68e..c475962 100644 --- a/app/Repositories/CardRepository.php +++ b/app/Repositories/CardRepository.php @@ -44,10 +44,10 @@ class CardRepository extends Repository $this->database->execute( 'INSERT INTO cards (board_id, column_id, swim_lane_id, job_number, job_name, customer_name, delivery_date, - quantity, notes, full_note, position, created_at, created_by, updated_at, updated_by) + quantity, notes, full_note, position, cell_entered_at, created_at, created_by, updated_at, updated_by) VALUES (:board_id, :column_id, :swim_lane_id, :job_number, :job_name, :customer_name, :delivery_date, - :quantity, :notes, :full_note, :position, :created_at, :created_by, :updated_at, :updated_by)', + :quantity, :notes, :full_note, :position, :cell_entered_at, :created_at, :created_by, :updated_at, :updated_by)', [ 'board_id' => $card->boardId, 'column_id' => $card->columnId, @@ -60,6 +60,7 @@ class CardRepository extends Repository 'notes' => $card->notes, 'full_note' => $card->fullNote, 'position' => $card->position, + 'cell_entered_at' => $card->cellEnteredAt, 'created_at' => $card->createdAt, 'created_by' => $card->createdBy, 'updated_at' => $card->updatedAt, @@ -100,9 +101,18 @@ class CardRepository extends Repository { $this->database->execute( 'UPDATE cards SET column_id = :column_id, swim_lane_id = :swim_lane_id, position = :position, - updated_at = :updated_at, updated_by = :updated_by WHERE id = :id', - ['column_id' => $columnId, 'swim_lane_id' => $swimLaneId, 'position' => $position, - 'updated_at' => $updatedAt, 'updated_by' => $updatedBy, 'id' => $id] + updated_at = :updated_at, updated_by = :updated_by, + cell_entered_at = CASE + WHEN column_id != :check_column_id OR swim_lane_id != :check_swim_lane_id THEN :cell_entered_at + ELSE cell_entered_at + END + WHERE id = :id', + [ + 'column_id' => $columnId, 'swim_lane_id' => $swimLaneId, 'position' => $position, + 'updated_at' => $updatedAt, 'updated_by' => $updatedBy, + 'check_column_id' => $columnId, 'check_swim_lane_id' => $swimLaneId, + 'cell_entered_at' => $updatedAt, 'id' => $id, + ] ); } diff --git a/app/Views/boards/show.php b/app/Views/boards/show.php index 4db7a29..766c423 100644 --- a/app/Views/boards/show.php +++ b/app/Views/boards/show.php @@ -84,7 +84,9 @@ var KANBAN = { boardId: = (int) $board->id ?>, boardSlug: "= e($board->slug) ?>", - cards: = $cardsJson ?> + cards: = $cardsJson ?>, + showCardAge: = $board->showCardAge ? 'true' : 'false' ?>, + cardAgeWarningDays: = (int) $board->cardAgeWarningDays ?> }; var KANBAN_COLS = = json_encode(array_map(fn($c) => ['id' => $c->id, 'name' => $c->name, 'position' => $c->position, 'show_card_count' => $c->showCardCount], $columns)) ?>; var KANBAN_LANES = = json_encode(array_map(fn($l) => ['id' => $l->id, 'name' => $l->name, 'position' => $l->position], $lanes)) ?>; diff --git a/app/Views/partials/settings-panel.php b/app/Views/partials/settings-panel.php index d5cea0a..4bd5bc0 100644 --- a/app/Views/partials/settings-panel.php +++ b/app/Views/partials/settings-panel.php @@ -79,5 +79,28 @@ + +