# Tenders CRUD for Ease of Management

## Overview

Add dialog-based Create, Edit, and Delete operations to the Tenders list and detail pages, matching the existing Vendor module CRUD pattern. Includes new tRPC mutations, shared dialog components, and action buttons on both list and detail views.

## Backend

### New Router Procedures (`tender.router.ts`)

- **`tender.update`** — `adminProcedure`. Input: `{ id, title?, description?, eligibility?, submissionDeadline?, tenderType?, projectId?, autoApproveBids? }`. Calls `TenderService.update()`. Logs audit via `AuditService.log` with `action: "UPDATE"`, publishes `CHANNELS.DASHBOARD_STATS`. Throws `NOT_FOUND` if tender doesn't exist.
- **`tender.delete`** — `adminProcedure`. Input: `{ id }`. Calls `TenderService.delete()` (hard delete from DB). Logs audit with `action: "DELETE"`, publishes stats. Throws `NOT_FOUND` if not found.

No changes to `TenderService` — `update()` and `delete()` already exist.

## Frontend

### Shared Dialog Components (`src/components/tender/`)

Three components following the exact Vendor module patterns:

- **`CreateTenderDialog.tsx`** — Opens from list page. Form fields: title, description, eligibility, submissionDeadline (date picker), projectId (select), tenderType (select: PROJECT/CATEGORY), fiscalYearId (select). Uses `trpc.tender.create.useMutation`. Resets form and invalidates `tender.list` on success.

- **`EditTenderDialog.tsx`** — Opens from list page or detail page. Receives full tender object, pre-fills form. Same editable fields as create. Uses `trpc.tender.update.useMutation`. Invalidates both `tender.list` and `tender.getById` on success.

- **`DeleteTenderDialog.tsx`** — Confirmation dialog. Receives `tenderId` and `tenderName`. Warning text: "Are you sure you want to delete this tender? This action cannot be undone." Destructive button. Uses `trpc.tender.delete.useMutation`. Invalidates both queries on success.

### List Page (`tenders/page.tsx`)

- Add action column to the table (Edit / Delete buttons as icon buttons)
- Add state for dialog open/close and selected tender
- Render `CreateTenderDialog` (triggered by "Create Ad-hoc Tender" button replacing the Link)
- Render `EditTenderDialog` and `DeleteTenderDialog` for row actions

### Detail Page (`tenders/[tenderId]/page.tsx`)

- Add Edit and Delete buttons in the page header action bar
- Wire up `EditTenderDialog` and `DeleteTenderDialog` with the current tender's data
- On successful edit, update the displayed tender data
- On successful delete, redirect to `/tenders`

## Files Changed

| File | Change |
|------|--------|
| `src/server/routers/tender.router.ts` | Add `update` and `delete` mutations |
| `src/components/tender/CreateTenderDialog.tsx` | New — create dialog |
| `src/components/tender/EditTenderDialog.tsx` | New — edit dialog |
| `src/components/tender/DeleteTenderDialog.tsx` | New — delete confirmation dialog |
| `src/components/tender/index.ts` | Export new components |
| `src/app/(dashboard)/tenders/page.tsx` | Add action column + dialogs |
| `src/app/(dashboard)/tenders/[tenderId]/page.tsx` | Add edit/delete buttons + dialogs |

## Not Changed

- `TenderService` — already has `update()` and `delete()` methods
- Prisma schema — no migration needed
- Existing `/tenders/new` page — kept as-is
