/* ========================================================================== mockData.ts -------------------------------------------------------------------------- Fake postings for the v1 test page (test.html). One case per banner rule, plus the cases where the banner is deliberately suppressed. Dates are built relative to a single `NOW` captured at load, and that same `NOW` is handed to the components as the `now` prop, so every run renders identical relative timestamps, so screenshots stay comparable. See mockReferralStats.ts for the smaller, named fixture set the v2 state grid (state-grid.html) uses. ========================================================================== */ (function (SB: any) { "use strict"; const NOW = Date.now(); const MINUTE = 60e3; const HOUR = 60 * MINUTE; const DAY = 24 * HOUR; function minutesAgo(n: number): Date { return new Date(NOW - n * MINUTE); } function hoursAgo(n: number): Date { return new Date(NOW - n * HOUR); } function daysAgo(n: number): Date { return new Date(NOW - n * DAY); } const BASE_POSTING: ReferralStats = { state: "open", isDirect: false, postedAt: null, viewCount: 0, responseCount: 0, lastResponseAt: null, ownerHasResponded: false, lastOwnerMessageAt: null, }; // v1-only fixtures (this file never drives a v2 request); the profile is // never read, just present to satisfy the type. const BASE_VIEWER: Viewer = { isOwner: false, hasApplied: false, profile: { id: "none", name: "", practiceAreas: [], pastCaseTypes: [] }, }; function posting(overrides: Partial): ReferralStats { return Object.assign({}, BASE_POSTING, overrides); } function viewer(overrides?: Partial): Viewer { return Object.assign({}, BASE_VIEWER, overrides); } interface Case { id: string; label: string; note: string; expect: BannerKey | null; posting: ReferralStats; viewer: Viewer; } const cases: Case[] = [ { id: "no-responses", label: "No responses", note: "2 hours old, nobody has responded yet.", expect: "new", posting: posting({ postedAt: hoursAgo(2), viewCount: 34, responseCount: 0, }), viewer: viewer(), }, { id: "low-activity", label: "Low activity", note: "30 hours old, 2 responses, owner has not replied.", expect: "competitive", posting: posting({ postedAt: hoursAgo(30), viewCount: 86, responseCount: 2, lastResponseAt: hoursAgo(5), }), viewer: viewer(), }, { id: "trending", label: "Trending", note: "20 hours old, 7 responses, owner has not replied.", expect: "trending", posting: posting({ postedAt: hoursAgo(20), viewCount: 412, responseCount: 7, lastResponseAt: minutesAgo(25), }), viewer: viewer(), }, { id: "old-posting", label: "Old posting", note: "5 days old with no responses at all: rule 5, branch A.", expect: "underperforming", posting: posting({ postedAt: daysAgo(5), viewCount: 58, responseCount: 0, }), viewer: viewer(), }, { id: "momentum-slowing", label: "Momentum slowing", note: "4 days old, 3 responses but none in the last 48h: rule 5, branch B.", expect: "underperforming", posting: posting({ postedAt: daysAgo(4), viewCount: 143, responseCount: 3, lastResponseAt: daysAgo(3), }), viewer: viewer(), }, { id: "owner-reviewing", label: "Owner reviewing", note: "Owner replied 30 minutes ago. Rule 1 outranks trending, " + "even with 5 responses.", expect: "reviewing", posting: posting({ postedAt: hoursAgo(26), viewCount: 230, responseCount: 5, lastResponseAt: hoursAgo(4), ownerHasResponded: true, lastOwnerMessageAt: minutesAgo(30), }), viewer: viewer(), }, { id: "dormant", label: "Dormant", note: "9 days old, past the 7 day cutoff, so no banner. Stats remain.", expect: null, posting: posting({ postedAt: daysAgo(9), viewCount: 77, responseCount: 4, lastResponseAt: daysAgo(8), }), viewer: viewer(), }, { id: "single-response", label: "Exactly one response", note: "Shows the preserved source quirk: SHOW_RESPONSES_WHEN = 1 hides the " + "response stat until there are 2.", expect: "competitive", posting: posting({ postedAt: hoursAgo(12), viewCount: 41, responseCount: 1, lastResponseAt: hoursAgo(2), }), viewer: viewer(), }, { id: "viewer-is-owner", label: "Viewer is the owner", note: "Trending data, but the banner is for responders only.", expect: null, posting: posting({ postedAt: hoursAgo(20), viewCount: 412, responseCount: 7, lastResponseAt: minutesAgo(25), }), viewer: viewer({ isOwner: true }), }, { id: "viewer-has-applied", label: "Viewer already responded", note: "Trending data, but this viewer has already applied.", expect: null, posting: posting({ postedAt: hoursAgo(20), viewCount: 412, responseCount: 7, lastResponseAt: minutesAgo(25), }), viewer: viewer({ hasApplied: true }), }, { id: "direct-posting", label: "Direct posting", note: "Direct postings show neither the stats row nor the banner.", expect: null, posting: posting({ postedAt: hoursAgo(6), viewCount: 12, responseCount: 1, isDirect: true, }), viewer: viewer(), }, ]; SB.mockData = { now: NOW, cases: cases, posting: posting, viewer: viewer, }; })((window as any).SB = (window as any).SB || {});