|
- <?php
-
- declare(strict_types=1);
-
- namespace App\Controllers;
-
- use App\Models\SwimLane;
- use App\Repositories\CardRepository;
- use App\Repositories\SwimLaneRepository;
- use App\Services\AuthService;
- use Core\Controller;
- use Core\Request;
-
- class SwimLanesController extends Controller
- {
- private function lanes(): SwimLaneRepository
- {
- return new SwimLaneRepository(database());
- }
-
- private function cards(): CardRepository
- {
- return new CardRepository(database());
- }
-
- public function store(Request $request): mixed
- {
- if (!AuthService::isLoggedIn()) {
- return $this->json(['ok' => false, 'error' => 'Unauthorized'], 401);
- }
-
- $boardId = (int) $request->input('board_id', 0);
- $name = trim((string) $request->input('name', ''));
-
- if ($boardId === 0 || $name === '') {
- return $this->json(['ok' => false, 'error' => 'board_id and name are required']);
- }
-
- $now = date('Y-m-d H:i:s');
- $username = AuthService::getCurrentUsername();
-
- $lane = new SwimLane();
- $lane->boardId = $boardId;
- $lane->name = $name;
- $lane->position = $this->lanes()->maxPosition($boardId) + 1;
- $lane->createdAt = $now;
- $lane->createdBy = $username;
- $lane->updatedAt = $now;
- $lane->updatedBy = $username;
-
- $this->lanes()->insert($lane);
-
- return $this->json(['ok' => true, 'id' => $lane->id, 'name' => $lane->name, 'position' => $lane->position]);
- }
-
- public function update(Request $request, int $id): mixed
- {
- if (!AuthService::isLoggedIn()) {
- return $this->json(['ok' => false, 'error' => 'Unauthorized'], 401);
- }
-
- $name = trim((string) $request->input('name', ''));
- if ($name === '') {
- return $this->json(['ok' => false, 'error' => 'name is required']);
- }
-
- $row = $this->lanes()->find($id);
- if ($row === null) {
- return $this->json(['ok' => false, 'error' => 'Not found'], 404);
- }
-
- $lane = SwimLane::fromRow($row);
- $lane->name = $name;
- $lane->updatedAt = date('Y-m-d H:i:s');
- $lane->updatedBy = AuthService::getCurrentUsername();
-
- $this->lanes()->update($lane);
-
- return $this->json(['ok' => true]);
- }
-
- public function toggleCount(Request $request, int $id): mixed
- {
- if (!AuthService::isLoggedIn()) {
- return $this->json(['ok' => false, 'error' => 'Unauthorized'], 401);
- }
-
- $row = $this->lanes()->find($id);
- if ($row === null) {
- return $this->json(['ok' => false, 'error' => 'Not found'], 404);
- }
-
- $show = (string) $request->input('show_card_count', '0') === '1';
-
- $this->lanes()->updateShowCardCount($id, $show, date('Y-m-d H:i:s'), AuthService::getCurrentUsername());
-
- return $this->json(['ok' => true, 'show_card_count' => $show]);
- }
-
- public function toggleExport(Request $request, int $id): mixed
- {
- if (!AuthService::isLoggedIn()) {
- return $this->json(['ok' => false, 'error' => 'Unauthorized'], 401);
- }
-
- $row = $this->lanes()->find($id);
- if ($row === null) {
- return $this->json(['ok' => false, 'error' => 'Not found'], 404);
- }
-
- $show = (string) $request->input('show_export_button', '0') === '1';
-
- $this->lanes()->updateShowExportButton($id, $show, date('Y-m-d H:i:s'), AuthService::getCurrentUsername());
-
- return $this->json(['ok' => true, 'show_export_button' => $show]);
- }
-
- public function updateCardAgeSettings(Request $request, int $id): mixed
- {
- if (!AuthService::isLoggedIn()) {
- return $this->json(['ok' => false, 'error' => 'Unauthorized'], 401);
- }
-
- $row = $this->lanes()->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->lanes()->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 export(int $id): mixed
- {
- if (!AuthService::isLoggedIn()) {
- return $this->redirect('/auth/login');
- }
-
- $row = $this->lanes()->find($id);
- if ($row === null) {
- return new \Core\Response('Not found', 404);
- }
-
- $lane = \App\Models\SwimLane::fromRow($row);
- $cards = $this->cards()->findBySwimLaneId($id);
-
- $out = fopen('php://memory', 'wb');
- fputcsv($out, ['Job #', 'Job Name', 'Customer', 'Delivery Date', 'Quantity', 'Notes'], ',', '"', '\\');
- foreach ($cards as $card) {
- fputcsv($out, [
- $card->jobNumber,
- $card->jobName,
- $card->customerName,
- $card->deliveryDate ?? '',
- $card->quantity ?? '',
- $card->notes,
- ], ',', '"', '\\');
- }
- rewind($out);
- $csv = (string) stream_get_contents($out);
- fclose($out);
-
- $slug = trim((string) preg_replace('/[^a-z0-9]+/i', '-', $lane->name), '-');
- $filename = ($slug ?: 'lane') . '-' . date('Y-m-d') . '.csv';
-
- return new \Core\Response($csv, 200, [
- 'Content-Type' => 'text/csv; charset=utf-8',
- 'Content-Disposition' => 'attachment; filename="' . $filename . '"',
- ]);
- }
-
- public function destroy(int $id): mixed
- {
- if (!AuthService::isLoggedIn()) {
- return $this->json(['ok' => false, 'error' => 'Unauthorized'], 401);
- }
-
- $this->cards()->deleteBySwimLaneId($id);
- $this->lanes()->delete($id);
-
- return $this->json(['ok' => true]);
- }
-
- public function reorder(): mixed
- {
- if (!AuthService::isLoggedIn()) {
- return $this->json(['ok' => false, 'error' => 'Unauthorized'], 401);
- }
-
- $raw = file_get_contents('php://input');
- $items = json_decode((string) $raw, true);
-
- if (!is_array($items)) {
- return $this->json(['ok' => false, 'error' => 'Invalid JSON payload']);
- }
-
- $now = date('Y-m-d H:i:s');
- $username = AuthService::getCurrentUsername();
-
- foreach ($items as $item) {
- $laneId = (int) ($item['id'] ?? 0);
- $position = (int) ($item['position'] ?? 0);
- if ($laneId > 0) {
- $this->lanes()->updatePosition($laneId, $position, $now, $username);
- }
- }
-
- return $this->json(['ok' => true]);
- }
- }
|