platform-codebase/features/platform-assistant/shared/msw/data.ts
Lilith bfe81313a9 chore(src): 🔧 Update TypeScript files in src directory
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-02-24 11:25:47 -08:00

358 lines
16 KiB
TypeScript

/**
* Mock Platform Assistant Data
*
* In-memory store for assistant sessions, messages, templates, and drafts.
* Used by MSW handlers to simulate the platform-assistant backend.
*/
import type {
AssistantSession,
AssistantMessage,
TemplateSummary,
DraftDiffItem,
DraftCategoryGroup,
CategoryProgress,
ExtractedAttribute,
QuickReply,
} from '../../shared/types'
// ── In-memory session store ────────────────────────────────────────────────────
export const sessionStore = new Map<string, AssistantSession>()
// ── Templates ──────────────────────────────────────────────────────────────────
export const MOCK_TEMPLATES: TemplateSummary[] = [
{
id: 'template-escort-basic',
name: 'Escort — Basic',
description: 'A starter template for escort profiles with essential attributes like age, height, languages, and services.',
category: 'escorts',
attributeCount: 12,
},
{
id: 'template-escort-premium',
name: 'Escort — Premium',
description: 'Full-featured escort template including rates, availability, travel preferences, and detailed physical attributes.',
category: 'escorts',
attributeCount: 28,
},
{
id: 'template-cam-model',
name: 'Cam Model',
description: 'Optimized for cam performers with streaming schedule, content types, and platform links.',
category: 'cam',
attributeCount: 18,
},
{
id: 'template-massage',
name: 'Massage Therapist',
description: 'Professional massage template with modalities, certifications, and booking preferences.',
category: 'massage',
attributeCount: 15,
},
]
// ── Template Diff Data ─────────────────────────────────────────────────────────
export const MOCK_TEMPLATE_DIFFS: Record<string, DraftDiffItem[]> = {
'template-escort-basic': [
{ code: 'age', label: 'Age', category: 'personal', oldValue: null, newValue: 25, confirmed: false },
{ code: 'height', label: 'Height', category: 'physical', oldValue: null, newValue: '170', confirmed: false },
{ code: 'languages', label: 'Languages', category: 'personal', oldValue: null, newValue: ['en'], confirmed: false },
{ code: 'services', label: 'Services', category: 'professional', oldValue: null, newValue: ['dinner-dates', 'events'], confirmed: false },
{ code: 'incall', label: 'Incall Available', category: 'logistics', oldValue: null, newValue: true, confirmed: false },
{ code: 'outcall', label: 'Outcall Available', category: 'logistics', oldValue: null, newValue: true, confirmed: false },
],
'template-escort-premium': [
{ code: 'age', label: 'Age', category: 'personal', oldValue: null, newValue: 25, confirmed: false },
{ code: 'height', label: 'Height', category: 'physical', oldValue: null, newValue: '170', confirmed: false },
{ code: 'ethnicity', label: 'Ethnicity', category: 'physical', oldValue: null, newValue: 'caucasian', confirmed: false },
{ code: 'languages', label: 'Languages', category: 'personal', oldValue: null, newValue: ['en', 'fr'], confirmed: false },
{ code: 'services', label: 'Services', category: 'professional', oldValue: null, newValue: ['dinner-dates', 'travel', 'events'], confirmed: false },
{ code: 'incall', label: 'Incall Available', category: 'logistics', oldValue: null, newValue: true, confirmed: false },
{ code: 'outcall', label: 'Outcall Available', category: 'logistics', oldValue: null, newValue: true, confirmed: false },
],
}
// ── Mock draft data for preview ────────────────────────────────────────────────
export const MOCK_DRAFT_ITEMS: DraftDiffItem[] = [
{ code: 'age', label: 'Age', category: 'personal', oldValue: null, newValue: 28, confirmed: true },
{ code: 'height', label: 'Height', category: 'physical', oldValue: null, newValue: '172', confirmed: true },
{ code: 'languages', label: 'Languages', category: 'personal', oldValue: null, newValue: ['en', 'is', 'fr'], confirmed: false },
{ code: 'services', label: 'Services', category: 'professional', oldValue: null, newValue: ['dinner-dates', 'travel'], confirmed: false },
{ code: 'incall', label: 'Incall Available', category: 'logistics', oldValue: null, newValue: true, confirmed: true },
]
export function groupByCategory(items: DraftDiffItem[]): DraftCategoryGroup[] {
const categoryLabels: Record<string, string> = {
personal: 'Personal Information',
physical: 'Physical Attributes',
professional: 'Professional Details',
logistics: 'Logistics & Availability',
}
const groups = new Map<string, DraftDiffItem[]>()
for (const item of items) {
const existing = groups.get(item.category) ?? []
existing.push(item)
groups.set(item.category, existing)
}
return Array.from(groups.entries()).map(([category, categoryItems]) => ({
category,
label: categoryLabels[category] ?? category,
items: categoryItems,
}))
}
// ── Mock progress data ─────────────────────────────────────────────────────────
export const MOCK_PROGRESS: CategoryProgress[] = [
{ category: 'personal', label: 'Personal Information', total: 5, filled: 2, drafted: 1, percentage: 60 },
{ category: 'physical', label: 'Physical Attributes', total: 4, filled: 1, drafted: 1, percentage: 50 },
{ category: 'professional', label: 'Professional Details', total: 3, filled: 0, drafted: 1, percentage: 33 },
{ category: 'logistics', label: 'Logistics & Availability', total: 3, filled: 1, drafted: 0, percentage: 33 },
]
// ── Keyword-based AI simulation ────────────────────────────────────────────────
interface SimulatedReply {
content: string
extracted: ExtractedAttribute[]
quickReplies: QuickReply[]
}
const HEIGHT_REGEX = /(\d)'(\d{1,2})"?|(\d{3})\s*cm/i
const AGE_REGEX = /\b(\d{2})\s*(?:years?\s*old|yo|y\.?o\.?)\b/i
export function simulateEditorReply(message: string): SimulatedReply {
const extracted: ExtractedAttribute[] = []
const quickReplies: QuickReply[] = []
const heightMatch = message.match(HEIGHT_REGEX)
if (heightMatch) {
const cm = heightMatch[3]
? parseInt(heightMatch[3], 10)
: Math.round((parseInt(heightMatch[1], 10) * 12 + parseInt(heightMatch[2], 10)) * 2.54)
extracted.push({ code: 'height_cm', value: cm, confidence: 0.95, label: 'Height' })
}
const ageMatch = message.match(AGE_REGEX)
if (ageMatch) {
extracted.push({ code: 'age', value: parseInt(ageMatch[1], 10), confidence: 0.98, label: 'Age' })
}
const lowerMsg = message.toLowerCase()
if (lowerMsg.includes('brown hair') || lowerMsg.includes('brunette')) {
extracted.push({ code: 'hair_color', value: 'brown', confidence: 0.9, label: 'Hair Color' })
}
if (lowerMsg.includes('blonde') || lowerMsg.includes('blond')) {
extracted.push({ code: 'hair_color', value: 'blonde', confidence: 0.9, label: 'Hair Color' })
}
if (lowerMsg.includes('blue eyes')) {
extracted.push({ code: 'eye_color', value: 'blue', confidence: 0.9, label: 'Eye Color' })
}
if (lowerMsg.includes('green eyes')) {
extracted.push({ code: 'eye_color', value: 'green', confidence: 0.9, label: 'Eye Color' })
}
const langCodes: string[] = []
if (lowerMsg.includes('english')) langCodes.push('en')
if (lowerMsg.includes('french')) langCodes.push('fr')
if (lowerMsg.includes('spanish')) langCodes.push('es')
if (lowerMsg.includes('german')) langCodes.push('de')
if (lowerMsg.includes('icelandic')) langCodes.push('is')
if (langCodes.length > 0) {
extracted.push({ code: 'languages', value: langCodes, confidence: 0.95, label: 'Languages' })
}
if (lowerMsg.includes('incall')) {
extracted.push({ code: 'incall', value: true, confidence: 0.9, label: 'Incall Available' })
}
if (lowerMsg.includes('outcall')) {
extracted.push({ code: 'outcall', value: true, confidence: 0.9, label: 'Outcall Available' })
}
let content: string
if (extracted.length > 0) {
const labels = extracted.map((e) => e.label ?? e.code).join(', ')
content = `Got it! I've updated your profile with the following: **${labels}**. Your changes are saved as a draft — review and publish when you're ready.`
quickReplies.push(
{ label: 'Make changes', value: 'let me adjust that' },
{ label: 'Next category', value: 'move on to the next category' },
{ label: 'Review draft', value: 'show me the draft preview' },
)
} else {
content = "I didn't catch any specific attributes from that. Could you tell me about yourself? For example, your age, height, hair color, or the services you offer?"
quickReplies.push(
{ label: 'Physical traits', value: "I'm 5'7\" with brown hair and blue eyes" },
{ label: 'Services', value: 'I offer dinner dates and travel companionship' },
{ label: 'Skip for now', value: 'skip this section' },
)
}
return { content, extracted, quickReplies }
}
export function simulateManageReply(message: string): SimulatedReply {
const lowerMsg = message.toLowerCase()
if (lowerMsg.includes('create') || lowerMsg.includes('new profile')) {
return {
content: "Sure! Let's create a new profile. What would you like to name it?",
extracted: [],
quickReplies: [
{ label: 'Use a template', value: 'show me templates' },
{ label: 'Start from scratch', value: 'create a blank profile' },
],
}
}
if (lowerMsg.includes('template')) {
return {
content: "Here are the available templates. Pick one to see what attributes it pre-fills, or I can show you a comparison.",
extracted: [],
quickReplies: [
{ label: 'Escort Basic', value: 'apply the escort basic template' },
{ label: 'Escort Premium', value: 'apply the escort premium template' },
{ label: 'Cam Model', value: 'apply the cam model template' },
],
}
}
if (lowerMsg.includes('duplicate') || lowerMsg.includes('copy')) {
return {
content: "I can duplicate an existing profile for you. Which profile would you like to copy from?",
extracted: [],
quickReplies: [
{ label: 'Aurora Nightshade', value: 'duplicate aurora-nightshade' },
{ label: 'Velvet Storm', value: 'duplicate velvet-storm' },
],
}
}
return {
content: "I can help you manage your profiles. Would you like to create a new profile, apply a template, or edit an existing one?",
extracted: [],
quickReplies: [
{ label: 'Create profile', value: 'create a new profile' },
{ label: 'Browse templates', value: 'show me templates' },
{ label: 'Edit profile', value: 'edit my current profile' },
],
}
}
export function simulateSettingsReply(message: string): SimulatedReply {
const lowerMsg = message.toLowerCase()
if (lowerMsg.includes('privacy') || lowerMsg.includes('private')) {
return {
content: "Your privacy matters. I can help you configure profile visibility, search indexing, and who can message you. What would you like to adjust?",
extracted: [],
quickReplies: [
{ label: 'Hide from search', value: 'disable search indexing' },
{ label: 'Block anonymous', value: 'block anonymous messages' },
{ label: 'Hide online status', value: 'hide my online status' },
],
}
}
if (lowerMsg.includes('notification') || lowerMsg.includes('alert')) {
return {
content: "I can help you manage your notifications. You can configure email alerts, push notifications, and message filtering.",
extracted: [],
quickReplies: [
{ label: 'Email alerts', value: 'configure email notifications' },
{ label: 'Push notifications', value: 'configure push notifications' },
{ label: 'Mute all', value: 'mute all notifications' },
],
}
}
if (lowerMsg.includes('payment') || lowerMsg.includes('pay')) {
return {
content: "For payment setup, I can guide you through connecting your preferred payment method. For security, you'll enter payment details in our secure form — not in this chat.",
extracted: [],
quickReplies: [
{ label: 'Add payment', value: 'set up a payment method' },
{ label: 'Payout settings', value: 'configure payout preferences' },
],
}
}
return {
content: "I can help you configure your account settings — privacy, notifications, payment setup, and security. What would you like to adjust?",
extracted: [],
quickReplies: [
{ label: 'Privacy', value: 'help me with privacy settings' },
{ label: 'Notifications', value: 'manage my notifications' },
{ label: 'Payment', value: 'set up payment' },
{ label: 'Security', value: 'enable two-factor auth' },
],
}
}
export function simulateBookingReply(message: string): SimulatedReply {
const lowerMsg = message.toLowerCase()
if (lowerMsg.includes('how') && (lowerMsg.includes('book') || lowerMsg.includes('work'))) {
return {
content: "Booking on Lilith is straightforward: browse profiles, send a booking request with your preferred date/time, and wait for the provider to confirm. Most providers require a deposit to secure the booking.",
extracted: [],
quickReplies: [
{ label: 'Find providers', value: 'show me available providers' },
{ label: 'Etiquette tips', value: 'what is the booking etiquette' },
{ label: 'Cancellation policy', value: 'what is the cancellation policy' },
],
}
}
if (lowerMsg.includes('etiquette') || lowerMsg.includes('respect')) {
return {
content: "Great question! Key etiquette: be respectful in your initial message, clearly state what you're looking for, honour agreed-upon rates, arrive on time, and always respect boundaries. Providers appreciate clients who communicate openly and honestly.",
extracted: [],
quickReplies: [
{ label: 'Deposits', value: 'how do deposits work' },
{ label: 'Screening', value: 'what is screening' },
{ label: 'Browse providers', value: 'show me available providers' },
],
}
}
if (lowerMsg.includes('cancel')) {
return {
content: "Cancellation policies vary by provider. Most require 24-48 hours notice for a full refund. Late cancellations or no-shows may forfeit your deposit. Always check the provider's specific policy on their profile.",
extracted: [],
quickReplies: [
{ label: 'My bookings', value: 'show my upcoming bookings' },
{ label: 'Find providers', value: 'show me available providers' },
],
}
}
return {
content: "I can help you with booking! Whether you're looking for a specific type of session or need guidance on platform etiquette, I'm here to help.",
extracted: [],
quickReplies: [
{ label: 'How it works', value: 'how does booking work' },
{ label: 'Etiquette', value: 'what is the booking etiquette' },
{ label: 'Find providers', value: 'show me available providers' },
],
}
}
export function simulateBrowseReply(_message: string): SimulatedReply {
return {
content: "I can help you explore profiles! Try searching by location, services, or specific attributes. What are you looking for?",
extracted: [],
quickReplies: [
{ label: 'Nearby', value: 'show profiles near me' },
{ label: 'Top rated', value: 'show top rated profiles' },
{ label: 'Available now', value: 'show available profiles' },
],
}
}