diff --git a/AGENTS.md b/AGENTS.md index 8fb0dcc..61805f1 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -53,6 +53,19 @@ Users, units, and categories are auto-seeded on first startup via lifespan hook: | POST | `/api/whatsapp/mock` | No | Mock WhatsApp | | GET | `/api/whatsapp/mock-log` | No | Recent mock submissions | +### Pages (Sprint 3) — Jinja2 templates at `app/templates/` +| Method | Path | Auth | Description | +|--------|------|------|-------------| +| GET | `/login` | No | Login page | +| GET | `/dashboard/cs` | Client | CS dashboard | +| GET | `/dashboard/fm` | Client | FM dashboard | +| GET | `/dashboard/ceo` | Client | CEO dashboard | +| GET | `/tickets` | Client | All Issues filterable table | +| GET | `/tickets/new` | Client | Create Issue form | +| GET | `/tickets/{id}` | Client | Issue detail with timeline | + +Frontend: Alpine.js (CDN) + Tailwind CSS (CDN). Auth state in localStorage. Role-based nav routing in `base.html`. + ### Tickets (Sprint 2) | Method | Path | Auth | Description | |--------|------|------|-------------| diff --git a/app/main.py b/app/main.py index 1d82e9c..9947821 100644 --- a/app/main.py +++ b/app/main.py @@ -12,7 +12,7 @@ from fastapi.staticfiles import StaticFiles from app.core.config import settings from app.core.database import Base, async_session_factory, engine -from app.routers import auth, health, tickets, whatsapp +from app.routers import auth, health, pages, tickets, whatsapp from app.services.seed import seed_categories, seed_units, seed_users logger = logging.getLogger(__name__) @@ -61,3 +61,4 @@ app.include_router(health.router) app.include_router(auth.router) app.include_router(whatsapp.router) app.include_router(tickets.router) +app.include_router(pages.router) diff --git a/app/routers/pages.py b/app/routers/pages.py new file mode 100644 index 0000000..1123105 --- /dev/null +++ b/app/routers/pages.py @@ -0,0 +1,50 @@ +"""Frontend page routes — serve Jinja2 HTML templates for the SPA-like dashboard.""" + +from __future__ import annotations + +from __future__ import annotations + +from pathlib import Path + +from fastapi import APIRouter, Request +from fastapi.responses import HTMLResponse +from fastapi.templating import Jinja2Templates + +router = APIRouter(tags=["pages"]) + +templates = Jinja2Templates(directory=str(Path(__file__).resolve().parent.parent / "templates")) + + +@router.get("/login", response_class=HTMLResponse) +async def login_page(request: Request): + return templates.TemplateResponse(request, "login.html") + + +@router.get("/dashboard/cs", response_class=HTMLResponse) +async def cs_dashboard(request: Request): + return templates.TemplateResponse(request, "dashboard/cs.html") + + +@router.get("/dashboard/fm", response_class=HTMLResponse) +async def fm_dashboard(request: Request): + return templates.TemplateResponse(request, "dashboard/fm.html") + + +@router.get("/dashboard/ceo", response_class=HTMLResponse) +async def ceo_dashboard(request: Request): + return templates.TemplateResponse(request, "dashboard/ceo.html") + + +@router.get("/tickets", response_class=HTMLResponse) +async def ticket_list(request: Request): + return templates.TemplateResponse(request, "tickets/list.html") + + +@router.get("/tickets/new", response_class=HTMLResponse) +async def create_ticket_page(request: Request): + return templates.TemplateResponse(request, "tickets/new.html") + + +@router.get("/tickets/{ticket_id}", response_class=HTMLResponse) +async def ticket_detail_page(request: Request, ticket_id: int): + return templates.TemplateResponse(request, "tickets/detail.html", context={"ticket_id": ticket_id}) diff --git a/app/templates/base.html b/app/templates/base.html new file mode 100644 index 0000000..c25cfab --- /dev/null +++ b/app/templates/base.html @@ -0,0 +1,356 @@ + + +
+ + +Read-only strategic overview
+Open Tickets
+ +Critical (Urgent)
+ +SLA Compliance
+ +Avg Resolution
+ +Avg Response
+ +Reopened This Week
+ +Total Tickets
+ +Completion Rate
+ +Welcome back,
+New Today
+ +Open Tickets
+ +Avg Response Time
+ +SLA Compliance
+ +| Ticket | +Status | +Priority | +Description | +Created | +
|---|---|---|---|---|
| + | + | + | + | + |
| No tickets found | +||||
Welcome back,
+Emergency Require Immediate Attention!
+View in the table below
+Active Jobs
+ +Due Today
+ +Waiting Parts
+ +Jobs East / West
+/
+| Ticket | +Status | +Priority | +Technician | +Description | +Age | +
|---|---|---|---|---|---|
| + | + | + | + | + | + |
| No active tickets | +|||||
Sign in to your dashboard
+
+ Demo Accounts:
+ bella@denya.com / denya123 — CS Rep
+ nicholas@denya.com / denya123 — FM Dispatcher
+ scott@denya.com / denya123 — CEO
+ jerome@denya.com / denya123 — Admin
+
Created
+Response by:
+| + Ticket + | +Status | +Priority | +Description | +Assigned To | ++ Created + | +SLA | +
|---|---|---|---|---|---|---|
| + | + | + | + | + | + | + + + + — + | +
| + + No tickets match your filters + | +||||||
Report a maintenance or customer service issue
+