semblance/src/hooks/usePersonaDetails.ts

793 lines
36 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { useState, useEffect } from 'react';
import { Persona } from '@/types/persona';
import { GENERATED_PERSONAS_KEY } from '@/hooks/usePersonaStorage';
import { useParams, useLocation, useNavigate } from 'react-router-dom';
import { toast } from 'sonner';
import { personasApi } from '@/lib/api';
import { useNavigation } from '@/contexts/NavigationContext';
// Sample user data for fallback/demo purposes
const sampleUsers: Persona[] = [
{
id: '0',
name: 'Oliver Reynolds',
age: '42',
gender: 'Male',
occupation: 'Senior Investment Manager',
education: 'Master\'s degree (Business and Finance)',
location: 'Kensington, London, UK',
techSavviness: 85,
brandLoyalty: 90,
priceConsciousness: 30,
environmentalConcern: 60,
personality: 'Discerning, sophisticated, detail-oriented, values heritage and craftsmanship',
interests: 'Classic automobiles, high-end timepieces, luxury real estate, fine dining, art exhibitions',
hasPurchasingPower: true,
hasChildren: true,
ethnicity: 'White British',
socialGrade: 'A',
householdIncome: '£275,000 per annum',
householdComposition: 'Married with two children (ages 8 and 12)',
livingSituation: 'Owns a 5-bedroom townhouse in Kensington',
mediaConsumption: 'Financial Times, The Economist, premium streaming services',
deviceUsage: 'Latest iPhone, iPad Pro, MacBook Air, and high-end smart home devices',
shoppingHabits: 'Prefers personal shopping assistants and concierge services',
brandPreferences: 'Heritage luxury brands with impeccable reputation',
communicationPreferences: 'Email for formal communications, encrypted messaging for sensitive matters',
goals: [
'Build a legacy of discerning taste and refined investments',
'Access truly personalized experiences that acknowledge his status',
'Forge meaningful connections with brands that share his values',
'Discover unique, limited-edition items that few others will possess',
'Cultivate a network of trusted advisors across various luxury segments',
'Balance professional achievement with meaningful family experiences'
],
frustrations: [
'Mass-market approaches disguised as premium experiences',
'Fragmented communication across different channels',
'Delays in response or service that waste valuable time',
'Sales representatives who lack deep product knowledge'
],
motivations: [
'Recognition of his refined tastes and achievement',
'Access to exclusive, members-only opportunities',
'Building a collection of meaningful, high-quality possessions',
'Experiences that seamlessly blend heritage with innovation'
],
oceanTraits: {
openness: 85,
conscientiousness: 90,
extraversion: 60,
agreeableness: 65,
neuroticism: 25
},
thinkFeelDo: {
thinks: [
'How does this reflect my personal standards and values?',
'Is this truly the pinnacle of craftsmanship and quality?',
'Will this purchase stand the test of time as a lasting investment?',
'How can this be further personalized to my exact preferences?'
],
feels: [
'Proud to associate with heritage brands that reflect my achievements',
'Gratified by bespoke experiences that acknowledge my unique tastes',
'Frustrated by standardized approaches that fail to recognize individual preferences',
'Reassured by transparent, detailed information about craftsmanship and materials'
],
does: [
'Conducts thorough research before making significant purchasing decisions',
'Seeks personalized consultations with dedicated specialists',
'Expects seamless integration between digital and in-person experiences',
'Values and maintains long-term relationships with trusted luxury brands',
'Regularly attends exclusive events and private showings'
]
},
scenarioType: "Life & Luxury Scenarios",
scenarios: [
'Oliver is considering commissioning a bespoke luxury vehicle with custom interior features. He expects a dedicated consultant to guide him through the entire process, from initial design to delivery.',
'While traveling abroad, Oliver seeks remote access to his preferred brands and expects the same level of personalized service through digital channels.',
'Oliver is attending an exclusive product launch event where he anticipates VIP treatment and early access to limited-edition items.',
'When researching a significant purchase, Oliver consults both trusted peer networks and expects detailed information about materials, craftsmanship, and heritage.',
'Oliver is planning a milestone family celebration and wants to book a private dining experience at an exclusive venue that reflects his sophisticated taste.'
]
},
{
id: '1',
name: 'Fiona Caldwell',
age: '38',
gender: 'Female',
ethnicity: 'White British',
occupation: 'Founder and Creative Director of a luxury lifestyle brand',
education: "First-Class Honours degree from a prestigious university (e.g., Oxbridge)",
location: 'Chelsea, London, UK',
techSavviness: 90,
personality: 'Pioneering creative entrepreneur who blends artistic flair with an unwavering commitment to quality. Thrives in exclusive circles where bespoke, high-touch service is expected at every stage of her luxury journey.',
interests: "Bespoke fashion, high-end design, contemporary art, exclusive dining experiences, curated travel, networking at industry panels and luxury brand collaborations",
socialGrade: "A/B",
householdIncome: "£195,000 per annum",
householdComposition: "Single professional, well-established network, occasional family engagements",
livingSituation: "Stylish, modern flat in an exclusive London district with access to boutique services",
coreValues: "Exceptional quality, distinctiveness, high-touch service, innovation, timeless elegance",
lifestyleChoices: "Enjoys cultural experiences (gallery openings, theatre premieres, curated travel)",
socialActivities: "Networks with high-achieving professionals, attends exclusive events, active in luxury collaborations",
mediaConsumption: "Premium publications (Spectator, Tatler, Vogue); follows luxury & design influencers",
brandLoyalty: 85,
priceConsciousness: 35,
environmentalConcern: 70,
hasPurchasingPower: true,
hasChildren: false,
deviceUsage: "High-performance smartphone, tablet, ultrabook; active on luxury-focused social media",
shoppingHabits: "Entirely bespoke, prefers personalised digital interfaces & in-person exclusivity",
brandPreferences: "Heritage brands with modern innovation (e.g., Rolls-Royce), tailored craftsmanship",
paymentMethods: "Premium digital payment systems, secure banking apps, selective use of credit for HNWIs",
categoryKnowledge: "Luxury automotive, bespoke interior design, limited-edition collections",
purchaseBehaviour: "Blends emotional connection & rational design evaluation; purchases reflect personal brand",
decisionInfluences: "Brand heritage, exclusivity, bespoke customisation, peer recommendations",
painPoints: "Dislikes cookie-cutter luxury retail, seeks recognition of individuality & creative sensibility",
journeyContext: "Engages via immersive digital platforms (virtual showrooms) and in-person appointments",
keyTouchpoints: "Exclusive previews, 1:1 consultancy, personalised digital interactions",
communicationPreferences: "Favors clear, direct, and personalised communication via premium digital and face-to-face",
oceanTraits: {
openness: 95,
conscientiousness: 85,
extraversion: 60,
agreeableness: 60,
neuroticism: 20
},
selfDeterminationNeeds: {
autonomy: "Seeks independence in decision-making; values unique bespoke offerings",
competence: "Wants acknowledgment for refined taste and flawless service",
relatedness: "Values relationships with brands who understand aspirations"
},
goals: [
"Establish herself as a tastemaker in the luxury creative community",
"Experience highly personalized services that acknowledge her uniqueness",
"Discover innovative yet timeless designs that complement her lifestyle",
"Build meaningful connections with brands that share her creative vision",
"Balance digital innovation with high-touch personal experiences",
"Access exclusive opportunities before they reach the mainstream market"
],
motivations: [
"Distinguishing herself in luxury landscape",
"Aligning with brands that echo her creative vision",
"Finding perfect balance of heritage and innovation",
"Building a network of like-minded creative professionals"
],
frustrations: [
"Generic luxury experiences that don't recognize her unique tastes",
"Disconnected online and offline brand experiences",
"Mass-market approaches disguised as premium services",
"Brands that prioritize heritage without embracing innovation"
],
fears: [
"Being treated as anonymous in a mass-market approach",
"Loss of personal touch in digital luxury experiences",
"Missing emerging trends in the luxury space"
],
thinkFeelDo: {
thinks: [
"How does this complement my personal brand and creative vision?",
"Is this innovative yet timeless enough for my lifestyle?",
"Will this experience or product truly stand out from the mainstream?",
"How can this be tailored to reflect my unique aesthetic sensibilities?"
],
feels: [
"Excited by innovative designs that push creative boundaries",
"Valued when brands recognize her accomplishments and creative influence",
"Frustrated by cookie-cutter luxury experiences that lack personality",
"Inspired by perfect execution of bespoke experiences that reflect attention to detail"
],
does: [
"Engages with immersive digital platforms and virtual showrooms",
"Attends exclusive industry events and creative collaborations",
"Seeks one-to-one consultancy sessions for significant purchases",
"Shares refined experiences within her select network of peers",
"Collaborates with luxury brands that align with her creative vision"
]
},
scenarioType: "Lifestyle & Professional Scenarios",
scenarios: [
"Fiona is considering collaborating with a luxury automotive brand on a limited-edition design concept, expecting a personalized presentation that respects her creative expertise.",
"While attending London Fashion Week, Fiona expects seamless integration between digital showcase tools and exclusive in-person appointments with designers.",
"Fiona is hosting a product launch event for her brand and wants to incorporate innovative digital experiences alongside traditional luxury elements.",
"When sourcing materials for a new collection, Fiona expects detailed information about craftsmanship, sustainability credentials, and exclusivity.",
"Fiona is planning a creative retreat and seeks a bespoke travel experience that combines luxury accommodations with artistic inspiration."
],
narrative: "Fiona Caldwell is a pioneering creative entrepreneur who blends artistic flair with an unwavering commitment to quality. At 38, her taste reflects both innovation and timeless elegance. She thrives in exclusive circles where bespoke, high-touch service is expected at every stage of her luxury journey. With an exceptionally high degree of openness, Fiona embraces new ideas and digital innovations that enhance her experience. Her strong conscientiousness ensures that each interaction is meticulously tailored to her exacting standards, while her moderate extraversion and agreeableness allow her to enjoy both intimate consultations and high-profile social gatherings. Fiona's minimal neuroticism underpins a confident, decisive approach to luxury purchases, making her an ideal candidate for RollsRoyce's \"House of Luxury\" proposition."
},
{
id: '9',
name: 'Arash Montazeri',
age: '46',
gender: 'Male',
ethnicity: 'Iranian-British',
occupation: 'Senior Executive at a leading technology firm',
education: 'Bachelor\'s degree in Engineering from a prestigious UK university',
location: 'Ascot, Berkshire, UK',
techSavviness: 95,
personality: 'A modern luxury consumer who seamlessly integrates Iranian heritage with contemporary British sophistication.',
interests: 'Classic cars, bespoke tailoring, fine wines, Persian art, modern design',
socialGrade: 'A',
householdIncome: '£240,000 per annum',
householdComposition: 'Married with two grown-up children',
livingSituation: 'Elegant country estate near Ascot blending contemporary British comfort with refined Persian design accents',
coreValues: 'Strong emphasis on heritage and innovation; values bespoke service that respects both traditional luxury and Iranian cultural legacy',
lifestyleChoices: 'Golfing at exclusive country clubs, fine dining at gourmet restaurants, luxury travel with culturally immersive experiences',
socialActivities: 'Member of elite clubs, attends high-profile charity events and cultural gatherings celebrating diversity and craftsmanship',
mediaConsumption: 'Financial Times, The Economist, selective cultural journals reflecting Iranian heritage and global outlook',
brandLoyalty: 92,
priceConsciousness: 25,
environmentalConcern: 65,
hasPurchasingPower: true,
hasChildren: true,
deviceUsage: 'Latest high-end smartphones, tablets, and connected home devices; utilises personalised digital interfaces',
shoppingHabits: 'Relationship-driven, high-touch purchasing process with bespoke consultations and integrated online-to-offline experiences',
brandPreferences: 'Heritage-driven premium brands that merge traditional craftsmanship with modern innovation',
paymentMethods: 'Secure digital banking solutions, premium credit facilities, bespoke financing options for high-value purchases',
categoryKnowledge: 'Well-versed in luxury automotive design and engineering; appreciates intricate customisation options',
purchaseBehaviour: 'Balances rational analysis with emotional attachment—viewing purchases as investments in personal legacy',
decisionInfluences: 'Brand heritage, bespoke craftsmanship, endorsements from trusted peers; values transparency and personalised narrative',
painPoints: 'Fragmented, impersonal customer journeys and inconsistent integration between digital and in-person service channels',
journeyContext: 'Engages through invitation-only showrooms complemented by immersive, customised digital experiences',
keyTouchpoints: 'One-to-one consultations, private previews of bespoke options, dedicated post-purchase concierge support',
communicationPreferences: 'Direct, transparent engagement through a dedicated relationship manager; comfortable with structured meetings and digital interactions',
oceanTraits: {
openness: 85,
conscientiousness: 95,
extraversion: 60,
agreeableness: 60,
neuroticism: 20
},
selfDeterminationNeeds: {
autonomy: 'Seeks independence in decision-making and prizes bespoke offerings that reflect his multifaceted identity',
competence: 'Desires recognition of his refined tastes and expects flawless service that mirrors his achievements',
relatedness: 'Values personalised, respectful relationships with brands that understand his unique blend of Iranian heritage and British sophistication'
},
goals: [
'Curate a collection of bespoke luxury items that reflect both heritage and innovation',
'Establish lasting relationships with brands that honor his dual cultural identity',
'Access truly personalized experiences that acknowledge his unique perspective',
'Create a legacy of refined taste to pass down to his children',
'Support innovation that respects traditional craftsmanship',
'Build connections with like-minded individuals in elite cultural circles'
],
motivations: [
'Recognition of his unique cultural perspective',
'Appreciation for his attention to detail and high standards',
'Access to exclusive, curated experiences',
'Opportunities to express his personal legacy through bespoke acquisitions'
],
frustrations: [
'Mass-market approaches disguised as premium experiences',
'Disjointed communication between digital and in-person channels',
'Service that fails to recognize his cultural background',
'Standardized luxury that lacks true personalization'
],
fears: [
'Erosion of truly bespoke luxury experiences through excessive digitization',
'Losing connection to cultural heritage in modern luxury contexts',
'Receiving impersonal service despite premium pricing'
],
thinkFeelDo: {
thinks: [
'How does this purchase reflect my personal heritage and contemporary values?',
'Is this truly the pinnacle of craftsmanship that honors both tradition and innovation?',
'Will this experience create a meaningful legacy I can share with my family?',
'Does this brand genuinely understand my unique cultural perspective?'
],
feels: [
'Pride in experiences that honor his dual cultural identity',
'Satisfaction when brands recognize his refined tastes and cultural background',
'Frustration with standardized luxury that fails to acknowledge individuality',
'Connection to heritage through thoughtfully crafted luxury experiences'
],
does: [
'Thoroughly researches the heritage and craftsmanship behind luxury brands',
'Engages deeply with dedicated consultants who understand his preferences',
'Seeks seamless integration between digital convenience and personal service',
'Builds long-term relationships with brands that respect his cultural background',
'Introduces his children to refined experiences that blend heritage and innovation'
]
},
scenarioType: 'Luxury & Cultural Experiences',
scenarios: [
'Arash is commissioning a bespoke vehicle with custom interior features that subtly incorporate elements of Persian design, expecting a dedicated consultant who appreciates both traditional craftsmanship and his cultural background.',
'While hosting international colleagues at his home, Arash wants to showcase luxury items that reflect his dual heritage and sophisticated taste, expecting his chosen brands to provide support for creating a memorable experience.',
'Arash is planning a milestone anniversary celebration that blends British elegance with Persian cultural elements, seeking partners who can provide truly personalized service for this significant occasion.',
'When introducing his grown children to the art of fine collecting, Arash expects luxury brands to recognize this important moment of legacy-building and provide an exceptional educational experience.',
'Arash is attending an exclusive cultural event where he anticipates connecting with like-minded individuals who appreciate the intersection of heritage and innovation in luxury experiences.'
],
narrative: 'Arash Montazeri exemplifies the modern luxury consumer who seamlessly integrates his Iranian heritage with contemporary British sophistication. As a successful senior executive, Arash demands a bespoke, integrated luxury experience that honours both tradition and innovation. His elevated conscientiousness ensures every detail of his journey is handled with precision, while his high openness allows him to embrace creative customisations that reflect his cultural legacy. Arash\'s balanced social orientation and calm, confident demeanour make him particularly sensitive to any disconnect between digital and physical service channels. His thoughtful approach to luxury purchases—considering both emotional resonance and practical excellence—positions him as an ideal candidate for RollsRoyce\'s "House of Luxury" experience.'
},
{
id: '2',
name: 'Michael Chen',
age: '37',
gender: 'Male',
occupation: 'Software Engineer',
education: 'Bachelor\'s Degree',
location: 'San Francisco, USA',
techSavviness: 95,
brandLoyalty: 25,
priceConsciousness: 90,
environmentalConcern: 50,
personality: 'Analytical, detail-oriented, values efficiency',
interests: 'Programming, gadgets, hiking, craft beer',
hasPurchasingPower: true,
hasChildren: true,
goals: [
'Lead a successful project team',
'Contribute to open-source projects',
'Achieve financial independence'
],
frustrations: [
'Dealing with legacy code',
'Unclear project requirements',
'Meetings that could have been emails'
],
motivations: [
'Solving complex problems',
'Learning new technologies',
'Making a positive impact through code'
],
oceanTraits: {
openness: 70,
conscientiousness: 85,
extraversion: 30,
agreeableness: 55,
neuroticism: 20
},
thinkFeelDo: {
thinks: [
'How can I optimize this algorithm?',
'Is this the most efficient solution?',
'Will this scale effectively?'
],
feels: [
'Frustrated by bugs',
'Satisfied when code works flawlessly',
'Excited about new frameworks'
],
does: [
'Writes clean, well-documented code',
'Participates in code reviews',
'Automates repetitive tasks'
]
},
scenarios: [
'Michael is debugging a critical system failure and needs to quickly identify the root cause.',
'While on vacation, Michael wants to stay updated on important project updates.',
'Michael needs to estimate the effort required for a new feature implementation.'
]
},
{
id: '3',
name: 'Sarah Martinez',
age: '48',
gender: 'Female',
occupation: 'Healthcare Administrator',
education: 'Master\'s Degree',
location: 'Chicago, USA',
techSavviness: 60,
brandLoyalty: 80,
priceConsciousness: 70,
environmentalConcern: 90,
personality: 'Practical, thorough, concerned with security',
interests: 'Gardening, reading, volunteering, classical music',
hasPurchasingPower: true,
hasChildren: true,
goals: [
'Improve patient outcomes',
'Streamline administrative processes',
'Ensure regulatory compliance'
],
frustrations: [
'Dealing with insurance companies',
'Keeping up with changing regulations',
'Balancing cost and quality of care'
],
motivations: [
'Making a difference in people\'s lives',
'Providing high-quality care',
'Creating a positive work environment'
],
oceanTraits: {
openness: 40,
conscientiousness: 90,
extraversion: 60,
agreeableness: 80,
neuroticism: 30
},
thinkFeelDo: {
thinks: [
'How can we improve patient satisfaction?',
'Are we meeting all regulatory requirements?',
'Can we reduce costs without sacrificing quality?'
],
feels: [
'Concerned about patient well-being',
'Stressed by administrative burdens',
'Proud of the team\'s accomplishments'
],
does: [
'Implements best practices',
'Conducts regular audits',
'Collaborates with other healthcare professionals'
]
},
scenarios: [
'Sarah is preparing for a hospital accreditation survey and needs to ensure all standards are met.',
'While at a conference, Sarah wants to learn about new healthcare technologies and best practices.',
'Sarah needs to resolve a conflict between staff members while maintaining a positive work environment.'
]
},
{
id: '4',
name: 'David Kim',
age: '22',
gender: 'Male',
occupation: 'Student',
education: 'High School',
location: 'Austin, USA',
techSavviness: 90,
brandLoyalty: 40,
priceConsciousness: 95,
environmentalConcern: 75,
personality: 'Curious, experimental, price-conscious',
interests: 'Gaming, streaming, social media, DIY projects',
hasPurchasingPower: false,
hasChildren: false,
goals: [
'Get good grades',
'Gain new experiences',
'Save money for future investments'
],
frustrations: [
'Paying for tuition and expenses',
'Dealing with student loan debt',
'Finding affordable housing'
],
motivations: [
'Achieving academic success',
'Exploring new interests',
'Building a strong financial foundation'
],
oceanTraits: {
openness: 80,
conscientiousness: 60,
extraversion: 70,
agreeableness: 50,
neuroticism: 40
},
thinkFeelDo: {
thinks: [
'How can I improve my grades?',
'What are the best deals on textbooks?',
'Can I balance school and work?'
],
feels: [
'Stressed about exams',
'Excited about learning new things',
'Anxious about the future'
],
does: [
'Studies regularly',
'Participates in extracurricular activities',
'Seeks out internships and job opportunities'
]
},
scenarios: [
'David is preparing for final exams and needs to find effective study strategies.',
'While browsing online, David wants to find the best deals on textbooks and school supplies.',
'David needs to manage his time effectively to balance school, work, and social activities.'
]
},
{
id: '5',
name: 'Lisa Patel',
age: '41',
gender: 'Female',
occupation: 'Product Manager',
education: 'Bachelor\'s Degree',
location: 'Seattle, USA',
techSavviness: 80,
brandLoyalty: 65,
priceConsciousness: 55,
environmentalConcern: 85,
personality: 'Strategic thinker, detail-oriented, collaborative',
interests: 'Hiking, cooking, travel, photography',
hasPurchasingPower: true,
hasChildren: true,
goals: [
'Launch successful products',
'Build strong relationships with stakeholders',
'Advance her career to a leadership position'
],
frustrations: [
'Dealing with conflicting priorities',
'Managing stakeholder expectations',
'Keeping up with rapidly changing technology'
],
motivations: [
'Creating innovative products',
'Solving customer problems',
'Driving business growth'
],
oceanTraits: {
openness: 75,
conscientiousness: 80,
extraversion: 65,
agreeableness: 70,
neuroticism: 35
},
thinkFeelDo: {
thinks: [
'How can we improve product performance?',
'What are the key customer needs?',
'Can we streamline the development process?'
],
feels: [
'Excited about new product ideas',
'Stressed by tight deadlines',
'Proud of the team\'s accomplishments'
],
does: [
'Conducts market research',
'Collaborates with engineering and design teams',
'Monitors product performance metrics'
]
},
scenarios: [
'Lisa is preparing a product roadmap and needs to prioritize features based on customer feedback.',
'While attending a conference, Lisa wants to learn about new product management methodologies.',
'Lisa needs to resolve a conflict between team members while maintaining a positive work environment.'
]
}
];
export function usePersonaDetails() {
const { id } = useParams<{ id: string }>();
const location = useLocation();
const navigate = useNavigate();
const { navigationState, clearNavigationState } = useNavigation();
const [currentPersona, setCurrentPersona] = useState<Persona | undefined>(undefined);
const [reviewPersona, setReviewPersona] = useState<Persona | undefined>(undefined);
const [isFromReview, setIsFromReview] = useState(false);
const [isEditing, setIsEditing] = useState(false);
const [isReviewMode, setIsReviewMode] = useState(false);
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
if (!id) {
setIsLoading(false);
return;
}
// Track if component is mounted
let isMounted = true;
const searchParams = new URLSearchParams(location.search);
const fromReview = searchParams.get('fromReview') === 'true';
setIsFromReview(fromReview);
setIsLoading(true);
const fetchPersonaData = async () => {
try {
// For local IDs, strip the prefix to convert to MongoDB ObjectId
const apiId = id.startsWith('local-') ? id.substring(6) : id;
// Use personasApi to get persona from database
const response = await personasApi.getById(apiId);
// API responses come with data property that contains the actual persona
if (response && response.data) {
const data = response.data;
if (isMounted) {
console.log('Found persona in database:', data);
// If we get a valid response, use it
setCurrentPersona({
...data,
// Ensure id is set correctly (API returns _id, but frontend uses id)
id: data.id || data._id,
isDbPersona: true // Mark as database persona
});
setIsLoading(false);
return;
}
}
// If we get here, we couldn't find the persona
console.error('Could not find persona with id:', id);
if (isMounted) {
setCurrentPersona(undefined);
setIsLoading(false);
toast.error("Persona not found");
}
} catch (error) {
console.error("Error fetching persona:", error);
if (isMounted) {
setCurrentPersona(undefined);
setIsLoading(false);
toast.error("Failed to load persona details");
}
}
};
fetchPersonaData();
// Cleanup function to prevent memory leaks and state updates after unmounting
return () => {
isMounted = false;
};
}, [id, location.search]);
const handleGoBack = () => {
// Check if we came from a focus group session (participant avatar click)
if (navigationState.previousRoute && navigationState.previousRoute.startsWith('/focus-groups/') && navigationState.focusGroupId) {
// Navigate back to the focus group session
navigate(`/focus-groups/${navigationState.focusGroupId}`);
// Clear navigation state after using it
clearNavigationState();
}
// Check if we came from focus group editing
else if (navigationState.previousRoute === '/focus-groups' && navigationState.focusGroupTab) {
// Navigate back to focus group editing with the specified tab
if (navigationState.isNewFocusGroup) {
// For new focus groups, go to focus-groups page in create mode with the specified tab
navigate(`/focus-groups?mode=create&tab=${navigationState.focusGroupTab}`);
} else if (navigationState.focusGroupId) {
// For existing focus groups, go to the specific focus group editing with the tab
navigate(`/focus-groups?mode=edit&id=${navigationState.focusGroupId}&tab=${navigationState.focusGroupTab}`);
} else {
// Fallback to focus groups page in create mode with participants tab
navigate('/focus-groups?mode=create&tab=participants');
}
// Clear navigation state after using it
clearNavigationState();
}
// Check if we came from synthetic users with a specific folder context
else if (navigationState.previousRoute === '/synthetic-users' && navigationState.folderId) {
// Navigate back to synthetic users with the folder filter applied
// We'll use URL state to restore the folder selection
navigate(`/synthetic-users?folder=${navigationState.folderId}`);
// Clear navigation state after using it
clearNavigationState();
}
else if (isFromReview) {
// Legacy behavior for review mode
navigate('/synthetic-users?mode=create&tab=ai&step=review');
} else {
// Default behavior - go to synthetic users page (coming from synthetic users list)
navigate('/synthetic-users');
}
};
const handleSaveEdit = async (updatedPersona: Persona) => {
try {
setIsEditing(false);
// Determine if this persona already exists in the database
const isExistingDbPersona = updatedPersona.isDbPersona ||
(id && id.length === 24 && /^[0-9a-f]{24}$/i.test(id));
// Create a sanitized copy to prevent _id modification errors
const personaToSend = { ...updatedPersona };
// MongoDB doesn't allow changing the _id field or sending certain client-side properties
if (personaToSend._id) {
delete personaToSend._id;
}
// Remove any client-side only properties that shouldn't be sent to the server
delete personaToSend.isDbPersona;
if (isExistingDbPersona && id && id.length === 24 && /^[0-9a-f]{24}$/i.test(id)) {
// Update existing database persona
const updateResult = await personasApi.update(id, personaToSend);
console.log('Updated persona in database:', updateResult);
// Update the local state with the edited persona
const updatedDbPersona = {
...updatedPersona,
isDbPersona: true
};
setCurrentPersona(updatedDbPersona);
toast.success("Persona updated in database successfully");
} else {
// Create new persona in database
const createResponse = await personasApi.create(personaToSend);
console.log('Created new persona in database:', createResponse.data);
// Update the persona with database ID
const dbPersona = {
...updatedPersona,
id: createResponse.data._id || createResponse.data.id,
_id: createResponse.data._id || createResponse.data.id,
isDbPersona: true
};
setCurrentPersona(dbPersona);
toast.success("Persona saved to database successfully");
}
} catch (error) {
console.error("Error saving persona:", error);
if (error.response && error.response.status === 401) {
toast.error("Authentication error - Please log in to save personas");
} else if (error.response && error.response.status === 404) {
toast.error("API endpoint not found - Database service may be unavailable");
} else {
toast.error("Failed to save persona to database: " + (error.message || "Unknown error"));
}
return false; // Return false to indicate failure
}
// If we got here, the save was successful
return true;
};
const enterReviewMode = (modifiedPersona: Persona) => {
setReviewPersona(modifiedPersona);
setIsReviewMode(true);
};
const exitReviewMode = () => {
setReviewPersona(undefined);
setIsReviewMode(false);
};
const saveReviewedPersona = async () => {
if (!reviewPersona || !currentPersona) return false;
try {
// Use the persona's MongoDB _id or fallback to id
const personaId = currentPersona._id || currentPersona.id;
// Use the update API since we already have the modified data
const updateResponse = await personasApi.update(personaId, reviewPersona);
if (updateResponse) {
toast.success("Persona saved successfully!");
setCurrentPersona(reviewPersona);
exitReviewMode();
// Give time for state update to complete before reloading
setTimeout(() => {
window.location.reload();
}, 100);
return true;
} else {
toast.error("Failed to save persona changes");
return false;
}
} catch (error) {
console.error("Error saving reviewed persona:", error);
toast.error("Failed to save persona changes: " + (error.message || "Unknown error"));
return false;
}
};
// Get the persona to display (review persona if in review mode, otherwise current persona)
const displayPersona = isReviewMode ? reviewPersona : currentPersona;
return {
currentPersona,
displayPersona,
isEditing,
isFromReview,
isLoading,
isReviewMode,
reviewPersona,
setIsEditing,
handleGoBack,
handleSaveEdit,
enterReviewMode,
exitReviewMode,
saveReviewedPersona
};
}