json(['ok' => false, 'error' => 'Unauthorized'], 401); } $boardId = (int) $request->input('board_id', 0); $columnId = (int) $request->input('column_id', 0); $swimLaneId = (int) $request->input('swim_lane_id', 0); if ($boardId === 0 || $columnId === 0 || $swimLaneId === 0) { return $this->json(['ok' => false, 'error' => 'board_id, column_id, and swim_lane_id are required']); } $now = date('Y-m-d H:i:s'); $username = AuthService::getCurrentUsername(); $nextPos = $this->cards()->maxPosition($columnId, $swimLaneId) + 1; $card = new Card(); $card->boardId = $boardId; $card->columnId = $columnId; $card->swimLaneId = $swimLaneId; $card->jobNumber = trim((string) $request->input('job_number', '')); $card->jobName = trim((string) $request->input('job_name', '')); $card->customerName = trim((string) $request->input('customer_name', '')); $card->deliveryDate = trim((string) $request->input('delivery_date', '')) ?: null; $card->quantity = trim((string) $request->input('quantity', '')); $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; $card->updatedBy = $username; try { $this->cards()->insert($card); } catch (\Throwable $e) { return $this->json(['ok' => false, 'error' => $e->getMessage()]); } return $this->json(['ok' => true] + $card->toJsonArray()); } public function update(Request $request, int $id): mixed { if (!AuthService::isLoggedIn()) { return $this->json(['ok' => false, 'error' => 'Unauthorized'], 401); } $card = $this->cards()->findById($id); if ($card === null) { return $this->json(['ok' => false, 'error' => 'Not found'], 404); } $card->jobNumber = trim((string) $request->input('job_number', '')); $card->jobName = trim((string) $request->input('job_name', '')); $card->customerName = trim((string) $request->input('customer_name', '')); $card->deliveryDate = trim((string) $request->input('delivery_date', '')) ?: null; $card->quantity = trim((string) $request->input('quantity', '')); $card->notes = trim((string) $request->input('notes', '')); $card->fullNote = (string) $request->input('full_note', ''); $card->updatedAt = date('Y-m-d H:i:s'); $card->updatedBy = AuthService::getCurrentUsername(); try { $this->cards()->update($card); } catch (\Throwable $e) { return $this->json(['ok' => false, 'error' => $e->getMessage()]); } return $this->json(['ok' => true] + $card->toJsonArray()); } public function move(Request $request, int $id): mixed { if (!AuthService::isLoggedIn()) { return $this->json(['ok' => false, 'error' => 'Unauthorized'], 401); } $columnId = (int) $request->input('column_id', 0); $swimLaneId = (int) $request->input('swim_lane_id', 0); $position = (int) $request->input('position', 0); $now = date('Y-m-d H:i:s'); $username = AuthService::getCurrentUsername(); $this->cards()->move($id, $columnId, $swimLaneId, $position, $now, $username); $siblings = trim((string) $request->input('sibling_ids', '')); if ($siblings !== '') { foreach (explode(',', $siblings) as $idx => $sibId) { $sibId = (int) trim($sibId); if ($sibId > 0) { $this->cards()->updatePosition($sibId, $idx, $now, $username); } } } return $this->json(['ok' => true]); } public function destroy(int $id): mixed { if (!AuthService::isLoggedIn()) { return $this->json(['ok' => false, 'error' => 'Unauthorized'], 401); } $this->cards()->delete($id); return $this->json(['ok' => true]); } }