254 lines
7.1 KiB
TypeScript
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),
|
|
},
|
|
}
|
|
}
|