hey guys, sorry for the delayed responses, past two weeks have been very busy and i've also been sick the past couple of days.
Summary
- Call the new mock pricing API from the dashboard and render a recommendations table.
- Add CSV export, types, and basic error handling. Move user signup network call into a service.
- implement the calendar page with mock data, ability to change month, etc, and click on a specific date.
Why Now
- Demonstrates MVP 0 end-to-end value: users can log in and immediately see pricing recommendations for the next 30 days.
Acceptance Criteria
- On
/dashboard, after user is authenticated, the page fetches POST /api/pricing/quote for a default room type and date range (today → +30 days).
- A table renders: Date, Recommended Price, Min, Max, Notes.
- “Export CSV” button downloads the current table data as a CSV.
- Errors show a non-intrusive inline alert; loading state is shown while fetching.
- User signup call is moved to a service function and handles 201/409 gracefully.
Files to Touch
frontend/src/services/pricingService.ts (new)
frontend/src/types/pricing.ts (new)
frontend/src/app/(routes)/dashboard/page.tsx (fetch + render table + export)
frontend/src/services/userService.tsx (implement signup)
- Optional:
frontend/src/utils/apiClient.tsx (use base URL from env, add simple error wrappers)
Types and Service Layer
- Types
// src/types/pricing.ts
export type PricingItem = {
date: string;
room_type_code: string;
price_rec: number;
price_min: number;
price_max: number;
drivers: string[];
};
export type PricingResponse = {
items: PricingItem[];
modelVersion: string;
};
- Pricing Service
// src/services/pricingService.ts
import { request } from "../utils/apiClient";
import type { PricingResponse } from "../types/pricing";
type QuoteParams = {
hotel_id: number;
room_type_code: string;
from: string; // YYYY-MM-DD
to: string; // YYYY-MM-DD
};
export async function quote(params: QuoteParams): Promise<PricingResponse> {
return request("/api/pricing/quote", {
method: "POST",
body: JSON.stringify(params),
});
}
- User Service
// src/services/userService.tsx
type SignupPayload = {
clerk_user_id: string;
first_name: string;
last_name: string;
email: string;
};
export async function signup(payload: SignupPayload): Promise<Response> {
return fetch("http://localhost:8000/api/users/signup", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload),
});
}
Dashboard Integration
- In
dashboard/page.tsx:
- Compute
from = today, to = today + 30 days.
- Call
quote({ hotel_id: 1, room_type_code: "DLX-QUEEN", from, to }) on server side (preferred) or in a server action.
- Render a table with columns: Date | Rec | Min | Max | Notes (drivers joined by
, ).
- Add an “Export CSV” button that converts current rows to CSV and triggers a client-side download.
Example fetch usage (server component):
import { quote } from "../../../services/pricingService";
const today = new Date();
const to = new Date();
to.setDate(today.getDate() + 30);
const fmt = (d: Date) => d.toISOString().slice(0, 10);
const data = await quote({
hotel_id: 1,
room_type_code: "DLX-QUEEN",
from: fmt(today),
to: fmt(to),
});
CSV export helper (client):
export function downloadCsv(filename: string, rows: any[]) {
const header = Object.keys(rows[0] ?? {}).join(",");
const body = rows.map(r => Object.values(r).join(",")).join("\n");
const csv = `${header}\n${body}`;
const blob = new Blob([csv], { type: "text/csv;charset=utf-8;" });
const url = URL.createObjectURL(blob);
const link = document.createElement("a");
link.href = url;
link.setAttribute("download", filename);
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
URL.revokeObjectURL(url);
}
Error Handling & States
- Loading: show a skeleton or spinner while the request is in-flight.
- Error: inline message (e.g., “Couldn’t load recommendations. Please try again.”) and log to console in dev.
- Empty state: show a brief message if
items.length === 0.
Environment & Config
- Use
NEXT_PUBLIC_API_BASE_URL (default to http://localhost:8000) in apiClient.tsx. Example:
const BASE_URL = process.env.NEXT_PUBLIC_API_BASE_URL ?? "http://localhost:8000";
Local Run and Test
- Start the backend first (ensure pricing endpoint is live).
- Start the frontend:
npm run dev.
- Visit
/dashboard while signed in via Clerk.
- Confirm the table renders 30 rows; “Export CSV” downloads a file containing the same rows.
Out of Scope (for this ticket)
- Calendar visualization, filters, or pagination.
- Styling polish beyond basic readability.
- Persisting user-selected room types.
Resources
Definition of Done
- Dashboard shows recommendations for the next 30 days.
- CSV export works and contains displayed rows.
- Network errors handled gracefully; no unhandled promise rejections in console.
- Code compiles with
npm run build.
hey guys, sorry for the delayed responses, past two weeks have been very busy and i've also been sick the past couple of days.
Summary
Why Now
Acceptance Criteria
/dashboard, after user is authenticated, the page fetchesPOST /api/pricing/quotefor a default room type and date range (today → +30 days).Files to Touch
frontend/src/services/pricingService.ts(new)frontend/src/types/pricing.ts(new)frontend/src/app/(routes)/dashboard/page.tsx(fetch + render table + export)frontend/src/services/userService.tsx(implementsignup)frontend/src/utils/apiClient.tsx(use base URL from env, add simple error wrappers)Types and Service Layer
Dashboard Integration
dashboard/page.tsx:from = today,to = today + 30 days.quote({ hotel_id: 1, room_type_code: "DLX-QUEEN", from, to })on server side (preferred) or in a server action.,).Example fetch usage (server component):
CSV export helper (client):
Error Handling & States
items.length === 0.Environment & Config
NEXT_PUBLIC_API_BASE_URL(default tohttp://localhost:8000) inapiClient.tsx. Example:Local Run and Test
npm run dev./dashboardwhile signed in via Clerk.Out of Scope (for this ticket)
Resources
Definition of Done
npm run build.