Skip to content

Frontend checkpoint: November 5th 2025 #33

@naman0r

Description

@naman0r

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

  1. 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;
};
  1. 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),
  });
}
  1. 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.

Metadata

Metadata

Labels

No labels
No labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions