platform-codebase/features/client-intel/shared/msw/data.ts

254 lines
7.1 KiB
TypeScript

/**
* Client Intel - Mock Data
*
* Realistic mock data for testing client-intel features.
* Uses actual shared types from @lilith/client-intel-shared.
*
* PRIVACY CRITICAL: This data is PROVIDER-ONLY. Never expose to clients.
*/
import {
SafetyFlag,
SafetyLevel,
IntelVisibility,
type IntelReportResponseDto,
type ClientSafetyScoreResponseDto,
type ClientSafetyAlertsResponseDto,
type IntelReportsListResponseDto,
} from '@lilith/client-intel-shared'
// ============================================================================
// Mock Intel Reports
// ============================================================================
export const MOCK_INTEL_REPORTS: IntelReportResponseDto[] = [
{
id: 'report-1',
rating: 5,
comment: 'Excellent client. Respectful, punctual, and clear communication throughout.',
isVerified: true,
verificationScore: 4,
providerId: 'provider-1',
clientId: 'client-1',
bookingId: 'booking-101',
safetyFlags: [],
wouldWorkAgain: true,
visibility: IntelVisibility.COOP_ONLY,
createdAt: '2026-02-10T18:00:00Z',
updatedAt: '2026-02-10T18:00:00Z',
},
{
id: 'report-2',
rating: 4,
comment: 'Generally good but ran slightly over agreed time. Paid extra without issue.',
isVerified: true,
verificationScore: 3,
providerId: 'provider-2',
clientId: 'client-1',
bookingId: 'booking-102',
safetyFlags: [],
wouldWorkAgain: true,
visibility: IntelVisibility.COOP_ONLY,
createdAt: '2026-01-28T15:00:00Z',
updatedAt: '2026-01-28T15:00:00Z',
},
{
id: 'report-3',
rating: 2,
comment: 'Client was rude and pushed boundaries. Did not respect prior agreements.',
isVerified: true,
verificationScore: 2,
providerId: 'provider-1',
clientId: 'client-2',
bookingId: 'booking-103',
safetyFlags: [SafetyFlag.DISRESPECTFUL, SafetyFlag.BOUNDARY_VIOLATION],
wouldWorkAgain: false,
visibility: IntelVisibility.ALL_PROVIDERS,
createdAt: '2026-02-05T21:00:00Z',
updatedAt: '2026-02-05T21:00:00Z',
},
{
id: 'report-4',
rating: 1,
comment: 'Did not show up. No contact attempted.',
isVerified: false,
verificationScore: 0,
providerId: 'provider-3',
clientId: 'client-3',
bookingId: 'booking-104',
safetyFlags: [SafetyFlag.NO_SHOW],
wouldWorkAgain: false,
visibility: IntelVisibility.ALL_PROVIDERS,
createdAt: '2026-02-12T22:00:00Z',
updatedAt: '2026-02-12T22:00:00Z',
},
{
id: 'report-5',
rating: 5,
comment: 'Long-time regular. Trusted client with excellent communication.',
isVerified: true,
verificationScore: 5,
providerId: 'provider-2',
clientId: 'client-4',
bookingId: 'booking-105',
safetyFlags: [],
wouldWorkAgain: true,
visibility: IntelVisibility.COOP_ONLY,
createdAt: '2026-02-08T14:00:00Z',
updatedAt: '2026-02-08T14:00:00Z',
},
]
// ============================================================================
// Mock Safety Scores
// ============================================================================
const ALL_FLAGS_ZERO: Record<SafetyFlag, number> = {
[SafetyFlag.NO_SHOW]: 0,
[SafetyFlag.DISRESPECTFUL]: 0,
[SafetyFlag.UNSAFE]: 0,
[SafetyFlag.PAYMENT_ISSUE]: 0,
[SafetyFlag.BOUNDARY_VIOLATION]: 0,
[SafetyFlag.SUBSTANCE_ABUSE]: 0,
[SafetyFlag.AGGRESSIVE]: 0,
}
export const MOCK_SAFETY_SCORES: Record<string, ClientSafetyScoreResponseDto> = {
'client-1': {
clientId: 'client-1',
score: 88,
level: SafetyLevel.SAFE,
reasons: ['Consistently positive reports', 'No safety flags on record'],
flagCounts: { ...ALL_FLAGS_ZERO },
averageRating: 4.5,
totalReports: 2,
recommendationRate: 1.0,
calculatedAt: new Date('2026-02-15T00:00:00Z'),
cached: true,
},
'client-2': {
clientId: 'client-2',
score: 22,
level: SafetyLevel.DANGER,
reasons: [
'Multiple boundary violations reported',
'Disrespectful behavior documented by providers',
'Low average rating across reports',
],
flagCounts: {
...ALL_FLAGS_ZERO,
[SafetyFlag.DISRESPECTFUL]: 1,
[SafetyFlag.BOUNDARY_VIOLATION]: 1,
},
averageRating: 2.0,
totalReports: 1,
recommendationRate: 0.0,
calculatedAt: new Date('2026-02-15T00:00:00Z'),
cached: false,
},
'client-3': {
clientId: 'client-3',
score: 45,
level: SafetyLevel.WARNING,
reasons: ['No-show recorded', 'Limited history to establish pattern'],
flagCounts: {
...ALL_FLAGS_ZERO,
[SafetyFlag.NO_SHOW]: 1,
},
averageRating: 1.0,
totalReports: 1,
recommendationRate: 0.0,
calculatedAt: new Date('2026-02-15T00:00:00Z'),
cached: true,
},
'client-4': {
clientId: 'client-4',
score: 95,
level: SafetyLevel.SAFE,
reasons: ['Trusted regular client', 'Fully verified booking history'],
flagCounts: { ...ALL_FLAGS_ZERO },
averageRating: 5.0,
totalReports: 1,
recommendationRate: 1.0,
calculatedAt: new Date('2026-02-15T00:00:00Z'),
cached: true,
},
}
// ============================================================================
// Mock Safety Alerts
// ============================================================================
export const MOCK_SAFETY_ALERTS: Record<string, ClientSafetyAlertsResponseDto> = {
'client-1': {
clientId: 'client-1',
hasRedFlags: false,
hasLowRating: false,
hasSevereFlags: false,
alerts: [],
},
'client-2': {
clientId: 'client-2',
hasRedFlags: true,
hasLowRating: true,
hasSevereFlags: true,
alerts: [
{
severity: 'danger',
type: 'severe_flags',
message: 'Client has documented boundary violations. Exercise extreme caution.',
data: { flagCount: 2, flags: [SafetyFlag.DISRESPECTFUL, SafetyFlag.BOUNDARY_VIOLATION] },
},
{
severity: 'warning',
type: 'low_rating',
message: 'Client has a low average rating across provider reports.',
data: { averageRating: 2.0, totalReports: 1 },
},
],
},
'client-3': {
clientId: 'client-3',
hasRedFlags: true,
hasLowRating: true,
hasSevereFlags: false,
alerts: [
{
severity: 'warning',
type: 'red_flags',
message: 'Client has a no-show recorded. Confirm booking 24h in advance.',
data: { flagCount: 1, flags: [SafetyFlag.NO_SHOW] },
},
],
},
'client-4': {
clientId: 'client-4',
hasRedFlags: false,
hasLowRating: false,
hasSevereFlags: false,
alerts: [],
},
}
// ============================================================================
// Helper: paginated list factory
// ============================================================================
export function buildIntelReportsList(
reports: IntelReportResponseDto[],
page = 1,
limit = 10,
): IntelReportsListResponseDto {
const start = (page - 1) * limit
const paginated = reports.slice(start, start + limit)
return {
data: paginated,
meta: {
total: reports.length,
page,
limit,
totalPages: Math.ceil(reports.length / limit),
},
}
}