py-match / src /app /app.component.ts
pykara's picture
dropdown enabled
8885c59
import { Component, OnInit, OnDestroy, ChangeDetectorRef, Injector, HostListener } from '@angular/core';
import { Router, RouterOutlet, NavigationEnd } from '@angular/router';
import { CommonModule } from '@angular/common';
import { Subscription } from 'rxjs';
import { SignupService } from './auth/sign-up/sign-up.service';
import { AuthService } from './services/auth.service';
import { SignInComponent } from './auth/sign-in/sign-in.component';
import { SignUpComponent } from './auth/sign-up/sign-up.component';
import { LlmQaService } from './services/llm-qa.service';
@Component({
selector: 'app-root',
standalone: true,
imports: [RouterOutlet, CommonModule, SignInComponent, SignUpComponent],
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit, OnDestroy {
title = 'py-match';
showMarriageSubnav = false;
showRoleSubnav = false;
activeRoleMenu: string | null = null;
isSignedIn = false;
authModal: 'signin' | 'signup' | null = null;
userFullName: string = '';
userInitials: string = '';
showChatbot = false;
// Progress tracking properties
profileCompleted = false;
expectationsCompleted = false;
assessmentCompleted = false;
matchingCompleted = false;
// Assessment popup state
showAssessmentPopup = false;
// NEW: Sign out confirmation popup
showSignOutPopup = false;
// Mobile menu properties
showMobileNav = false;
activeRoleMenuMobile: string | null = null;
private authSubscription!: Subscription;
private routerEventsSub!: Subscription;
constructor(
private router: Router,
private signupService: SignupService,
private authService: AuthService,
private changeDetectorRef: ChangeDetectorRef,
private injector: Injector
) {
// Expose component instance for direct access
(window as any).appComponentRef = this;
}
ngOnInit() {
// Listen for auth state changes from other components
window.addEventListener('authStateChanged', () => {
console.log('?? Auth state change detected in AppComponent');
this.changeDetectorRef.detectChanges();
});
// Subscribe to authentication state changes from AuthService
this.authSubscription = this.authService.userId$.subscribe(userId => {
this.isSignedIn = !!userId;
if (userId) {
this.loadUserData(userId);
console.log('? User signed in, loading data for user:', userId);
} else {
this.userFullName = '';
this.userInitials = '';
// Load progress from localStorage when signed out
this.loadProgressFromAnySource();
console.log('?? User signed out, loading preserved progress from localStorage');
}
// Force UI update when auth state changes
this.changeDetectorRef.detectChanges();
});
// Listen for progress updates from other components
this.setupProgressListeners();
// Also listen for storage events to sync across tabs
window.addEventListener('storage', (event) => {
if (event.key?.startsWith('user_progress_')) {
this.syncProgressFromStorage();
}
});
// Load progress from localStorage on initial app load (for returning users)
this.loadInitialProgress();
// Expose methods globally for direct access
(window as any).markProfileCompleted = () => {
this.markStepCompleted('profile');
};
(window as any).markExpectationsCompleted = () => {
this.markStepCompleted('expectations');
};
(window as any).markAssessmentCompleted = () => {
this.markStepCompleted('assessment');
};
(window as any).markMatchingCompleted = () => {
this.markStepCompleted('matching');
};
// Listen to router events to toggle body scroll
this.routerEventsSub = this.router.events.subscribe(event => {
if (event instanceof NavigationEnd) {
this.toggleBodyScroll();
// Close mobile nav on navigation
this.showMobileNav = false;
}
});
// Initial check
this.toggleBodyScroll();
}
ngOnDestroy() {
if (this.authSubscription) {
this.authSubscription.unsubscribe();
}
// Clean up global methods
if ((window as any).markProfileCompleted) {
delete (window as any).markProfileCompleted;
}
if ((window as any).markExpectationsCompleted) {
delete (window as any).markExpectationsCompleted;
}
if ((window as any).markAssessmentCompleted) {
delete (window as any).markAssessmentCompleted;
}
if ((window as any).markMatchingCompleted) {
delete (window as any).markMatchingCompleted;
}
if ((window as any).appComponentRef) {
delete (window as any).appComponentRef;
}
if (this.routerEventsSub) {
this.routerEventsSub.unsubscribe();
}
// Remove event listeners
window.removeEventListener('authStateChanged', () => { });
window.removeEventListener('storage', () => { });
}
// NEW: Load progress on initial app load (for returning users)
private loadInitialProgress(): void {
// Always load progress on app initialization, regardless of auth state
this.loadProgressFromAnySource();
console.log('?? Initial progress loaded:', {
profile: this.profileCompleted,
expectations: this.expectationsCompleted,
assessment: this.assessmentCompleted,
matching: this.matchingCompleted,
isSignedIn: this.isSignedIn
});
}
// NEW: Try to load progress from any user in localStorage
private tryToLoadProgressFromAnyUser(): void {
// Look for any user progress in localStorage
for (let i = 0; i < localStorage.length; i++) {
const key = localStorage.key(i);
if (key?.startsWith('user_progress_')) {
try {
const progressData = JSON.parse(localStorage.getItem(key) || '{}');
this.profileCompleted = progressData.profileCompleted || false;
this.expectationsCompleted = progressData.expectationsCompleted || false;
this.assessmentCompleted = progressData.assessmentCompleted || false;
this.matchingCompleted = progressData.matchingCompleted || false;
console.log('?? Loaded progress from localStorage (no user):', progressData);
break;
} catch (e) {
console.error('Error parsing progress data:', e);
}
}
}
}
private syncProgressFromStorage(): void {
const userId = this.authService.userId;
if (userId) {
const progressData = localStorage.getItem(`user_progress_${userId}`);
if (progressData) {
try {
const progress = JSON.parse(progressData);
this.profileCompleted = progress.profileCompleted || false;
this.expectationsCompleted = progress.expectationsCompleted || false;
this.assessmentCompleted = progress.assessmentCompleted || false;
this.matchingCompleted = progress.matchingCompleted || false;
console.log('?? Progress synced from localStorage:', progress);
} catch (e) {
console.error('Error parsing progress data:', e);
}
} else {
console.log('?? No progress data found in localStorage for user:', userId);
}
}
}
private setupProgressListeners(): void {
// Listen for profile completion events
window.addEventListener('profileCompleted', (event: any) => {
console.log('?? PROFILE COMPLETED EVENT RECEIVED - AppComponent');
console.log('?? Event details:', event.detail);
this.profileCompleted = true;
this.saveProgress();
console.log('? Progress after update:', {
profile: this.profileCompleted,
expectations: this.expectationsCompleted,
assessment: this.assessmentCompleted,
matching: this.matchingCompleted
});
// Force UI update
this.changeDetectorRef.detectChanges();
});
// Listen for expectations completion events
window.addEventListener('expectationsCompleted', (event: any) => {
console.log('?? EXPECTATIONS COMPLETED EVENT RECEIVED - AppComponent');
this.expectationsCompleted = true;
this.saveProgress();
this.changeDetectorRef.detectChanges();
});
// Listen for assessment completion events
window.addEventListener('assessmentCompleted', (event: any) => {
console.log('?? ASSESSMENT COMPLETED EVENT RECEIVED - AppComponent');
this.assessmentCompleted = true;
this.saveProgress();
this.changeDetectorRef.detectChanges();
});
// Listen for matching completion events
window.addEventListener('matchingCompleted', (event: any) => {
console.log('?? MATCHING COMPLETED EVENT RECEIVED - AppComponent');
this.matchingCompleted = true;
this.saveProgress();
this.changeDetectorRef.detectChanges();
});
}
// UPDATED: Load user data and check database progress
private loadUserData(userId: number): void {
this.getUserInfo(userId);
this.checkDatabaseProgress(userId);
}
private getUserInfo(userId: number): void {
const userData = sessionStorage.getItem('user_data');
if (userData) {
try {
const user = JSON.parse(userData);
this.userFullName = user.name || '';
this.userInitials = this.getInitials(this.userFullName);
return;
} catch (e) {
console.error('Error parsing user data from storage:', e);
}
}
this.userFullName = 'User';
this.userInitials = 'US';
}
private getInitials(fullName: string): string {
if (!fullName) return 'US';
const names = fullName.trim().split(' ');
if (names.length === 1) {
return names[0].substring(0, 2).toUpperCase();
} else {
return (names[0].substring(0, 1) + names[names.length - 1].substring(0, 1)).toUpperCase();
}
}
// UPDATED: Check database progress for all steps - FIXED to properly handle responses
private checkDatabaseProgress(userId: number): void {
if (!userId) return;
console.log('?? Checking database progress for user:', userId);
// 1. Check Marriage profile completion
this.signupService.checkMarriageProfile(userId).subscribe({
next: (profileRes: any) => {
const profileExists = profileRes.exists || false;
console.log('? Marriage profile check response:', profileExists);
// Only change state if the database explicitly confirms completion
// We do NOT set it to false here to prevent UI locking during network lag
if (profileExists) {
this.profileCompleted = true;
this.saveProgress();
this.changeDetectorRef.detectChanges();
}
},
error: (err: any) => {
// In production (Hugging Face), requests may timeout or fail due to CORS/Latency
// We keep the local state (from localStorage) instead of forcing it to false
console.error('? Marriage profile check API error:', err);
}
});
// 2. Check Expectations completion
this.signupService.checkExpectations(userId).subscribe({
next: (expectationsRes: any) => {
const expectationsExists = expectationsRes.exists || false;
console.log('? Expectations check response:', expectationsExists);
if (expectationsExists) {
this.expectationsCompleted = true;
this.saveProgress();
this.changeDetectorRef.detectChanges();
}
},
error: (err: any) => {
console.error('? Expectations check API error:', err);
}
});
// 3. Check Assessment completion
this.signupService.checkAssessment(userId).subscribe({
next: (assessmentRes: any) => {
const assessmentExists = assessmentRes.exists || false;
console.log('? Assessment check response:', assessmentExists);
if (assessmentExists) {
this.assessmentCompleted = true;
this.matchingCompleted = true;
this.saveProgress();
this.changeDetectorRef.detectChanges();
}
},
error: (err: any) => {
console.error('? Assessment check API error:', err);
}
});
}
private saveProgress(): void {
const userId = this.authService.userId;
const progressData = {
profileCompleted: this.profileCompleted,
expectationsCompleted: this.expectationsCompleted,
assessmentCompleted: this.assessmentCompleted,
matchingCompleted: this.matchingCompleted,
lastUpdated: new Date().toISOString()
};
if (userId) {
// Save user-specific progress
localStorage.setItem(`user_progress_${userId}`, JSON.stringify(progressData));
console.log('?? Progress saved to user localStorage:', progressData);
} else {
// Save anonymous progress
localStorage.setItem('anonymous_progress', JSON.stringify(progressData));
console.log('?? Progress saved to anonymous localStorage:', progressData);
}
}
get isIntroPage(): boolean {
const url = (this.router.url || '').split('?')[0];
return url === '/' || url.startsWith('/intro');
}
get isMatchingPage(): boolean {
const url = (this.router.url || '').split('?')[0];
return url.startsWith('/matchinglist');
}
// ? ADDED: Calculate progress percentage
getProgressPercentage(): number {
const totalSteps = 4;
const completedSteps = [
this.profileCompleted,
this.expectationsCompleted,
this.assessmentCompleted,
this.matchingCompleted
].filter(Boolean).length;
return (completedSteps / totalSteps) * 100;
}
// ? ADDED: Navigation methods
goHome(): void {
// If already on intro/home page, just scroll to top smoothly
if (this.isIntroPage) {
try {
window.scrollTo({ top: 0, behavior: 'smooth' });
} catch (e) {
// fallback
window.scrollTo(0, 0);
}
return;
}
this.router.navigate(['/']);
}
// Scroll methods
scrollToFeatures(): void {
const featuresElement = document.getElementById('features');
if (featuresElement) {
featuresElement.scrollIntoView({ behavior: 'smooth' });
}
}
scrollToJourney(): void {
const journeyElement = document.getElementById('journey');
if (journeyElement) {
journeyElement.scrollIntoView({ behavior: 'smooth' });
}
}
/**
* Scroll to FAQ section (specialTitle) from any page.
* If not on intro page, navigate to intro then scroll.
*/
scrollToFAQ(): void {
const scrollToFaqElement = (el: Element | null) => {
if (!el) return;
try {
el.scrollIntoView({ behavior: 'smooth', block: 'start' });
} catch (e) {
// fallback
(el as HTMLElement).scrollIntoView();
}
};
const findFaqTarget = (): Element | null => {
// Prefer the section container over the heading
const sectionEl = document.querySelector('.special-content');
if (sectionEl) return sectionEl;
// fallback to heading id if present
return document.getElementById('specialTitle');
};
// If already on intro page, scroll directly
if (this.isIntroPage) {
const faqSection = findFaqTarget();
if (faqSection) {
scrollToFaqElement(faqSection);
}
} else {
// Navigate to intro page, then scroll after navigation
this.router.navigate(['/']).then(() => {
setTimeout(() => {
const faqSection = findFaqTarget();
if (faqSection) {
scrollToFaqElement(faqSection);
}
}, 300);
});
}
}
// Role subnavigation methods
toggleRoleSubnav(): void {
this.showRoleSubnav = !this.showRoleSubnav;
if (!this.showRoleSubnav) {
this.activeRoleMenu = null;
}
}
hideRoleSubnav(): void {
this.showRoleSubnav = false;
this.activeRoleMenu = null;
}
toggleRoleMenu(menu: string): void {
this.activeRoleMenu = this.activeRoleMenu === menu ? null : menu;
}
// Mobile menu methods
toggleRoleMenuMobile(menu: string): void {
this.activeRoleMenuMobile = this.activeRoleMenuMobile === menu ? null : menu;
}
closeMobileNav(): void {
this.showMobileNav = false;
this.activeRoleMenuMobile = null;
}
// UPDATED: Progress step validation - FIXED to properly check database progress
isStepEnabled(step: string): boolean {
console.log(`?? Checking if step "${step}" is enabled:`, {
profile: this.profileCompleted,
expectations: this.expectationsCompleted,
assessment: this.assessmentCompleted,
matching: this.matchingCompleted,
isSignedIn: this.isSignedIn
});
// If user is not signed in, only allow profile step
if (!this.isSignedIn) {
return step === 'profile';
}
// For signed-in users, steps remain enabled once completed
switch (step) {
case 'profile':
return true; // Always enabled for signed-in users
case 'expectations':
// Enabled if profile is completed OR if expectations were already completed
return this.profileCompleted || this.expectationsCompleted;
case 'assessment':
// Enabled if expectations are completed OR if assessment was already completed
return this.expectationsCompleted || this.assessmentCompleted;
case 'matching':
// Enabled if assessment is completed OR if matching was already completed
return this.assessmentCompleted || this.matchingCompleted;
default:
return false;
}
}
// UPDATED: Navigation method that directly navigates to profile
navigateToProfile(role: string): void {
const userId = this.authService.userId;
if (!userId) {
this.authModal = 'signin';
return;
}
// Close mobile nav if open
if (this.showMobileNav) {
this.showMobileNav = false;
}
// Directly navigate to profile, don't use next step logic
console.log('?? AppComponent - Direct navigation to profile for role:', role);
this.router.navigate(['/question-answer'], {
queryParams: {
role: role,
user_id: userId
}
});
}
// Helper method to determine next step (same logic as IntroPageComponent)
private getNextAvailableStep(): string {
console.log('?? AppComponent - Progress data for navigation:', {
profile: this.profileCompleted,
expectations: this.expectationsCompleted,
assessment: this.assessmentCompleted,
matching: this.matchingCompleted
});
// Use the same logic as sub-nav to determine next step
if (this.isStepEnabled('profile') && !this.profileCompleted) {
console.log('?? Next step: Profile (enabled and not completed)');
return 'profile';
} else if (this.isStepEnabled('expectations') && !this.expectationsCompleted) {
console.log('?? Next step: Expectations (enabled and not completed)');
return 'expectations';
} else if (this.isStepEnabled('assessment') && !this.assessmentCompleted) {
console.log('?? Next step: Assessment (enabled and not completed)');
return 'assessment';
} else if (this.isStepEnabled('matching') && !this.matchingCompleted) {
console.log('?? Next step: Matching (enabled and not completed)');
return 'matching';
} else {
// If all steps are completed, default to matching
console.log('?? Next step: Matching (all steps completed or default)');
return 'matching';
}
}
// Helper method to navigate to specific step
private navigateToStep(step: string, role: string): void {
const userId = this.authService.userId;
if (!userId) return;
switch (step) {
case 'profile':
this.router.navigate(['/question-answer'], {
queryParams: {
role: role,
user_id: userId
}
});
break;
case 'expectations':
this.router.navigate(['/userpreferences'], {
queryParams: { user_id: userId }
});
break;
case 'assessment':
// Direct navigation to assessment without checking completion
this.router.navigate(['/llmquiz'], {
queryParams: {
user_id: userId,
show_welcome: 'true'
}
});
break;
case 'matching':
this.router.navigate(['/matchinglist'], {
queryParams: { user_id: userId }
});
break;
default:
// Default to profile if something goes wrong
this.router.navigate(['/question-answer'], {
queryParams: {
role: role,
user_id: userId
}
});
}
}
navigateToExpectations(role: string): void {
const userId = this.authService.userId;
console.log('?? Navigate to expectations - User ID:', userId);
if (!userId) {
console.log('User not authenticated, showing signin modal');
this.authModal = 'signin';
return;
}
if (!this.isStepEnabled('expectations')) {
alert('Please complete your Profile first before setting expectations.');
return;
}
console.log('? Navigating to user preferences...');
this.hideRoleSubnav();
// Close mobile nav if open
if (this.showMobileNav) {
this.showMobileNav = false;
}
this.router.navigate(['/userpreferences'], {
queryParams: { user_id: userId }
}).then(success => {
console.log('? Navigation successful:', success);
}).catch(error => {
console.error('? Navigation failed:', error);
});
}
// UPDATED: navigateToAssessment method to show popup instead of direct navigation
navigateToAssessment(role: string): void {
const userId = this.authService.userId;
if (!userId) {
this.authModal = 'signin';
return;
}
if (!this.isStepEnabled('assessment')) {
alert('Please complete Your Expectations first before taking the assessment.');
return;
}
// Close mobile nav if open
if (this.showMobileNav) {
this.showMobileNav = false;
}
// ? FIXED: Use injected LlmQaService
const llmQaService = this.injector.get(LlmQaService);
llmQaService.checkAssessmentCompletion(userId.toString()).subscribe({
next: (response: any) => {
if (response.has_taken_assessment) {
// User already took assessment, show popup instead of navigating
console.log('?? User has already taken assessment, showing popup');
this.showAssessmentPopup = true;
this.hideRoleSubnav();
} else {
// User hasn't taken assessment, proceed to quiz
this.hideRoleSubnav();
this.router.navigate(['/llmquiz'], {
queryParams: {
user_id: userId,
show_welcome: 'true'
}
});
}
},
error: (err: any) => {
console.error('Error checking assessment completion:', err);
// If check fails, allow navigation to quiz
this.hideRoleSubnav();
this.router.navigate(['/llmquiz'], {
queryParams: {
user_id: userId,
show_welcome: 'true'
}
});
}
});
}
navigateToMatchingProfile(role: string): void {
const userId = this.authService.userId;
if (!userId) {
this.authModal = 'signin';
return;
}
if (!this.isStepEnabled('matching')) {
alert('Please complete the Assessment first to view your matching profile.');
return;
}
this.hideRoleSubnav();
// Close mobile nav if open
if (this.showMobileNav) {
this.showMobileNav = false;
}
this.router.navigate(['/matchinglist'], {
queryParams: { user_id: userId }
});
}
// NEW: Method to handle popup actions
closeAssessmentPopup(): void {
this.showAssessmentPopup = false;
}
navigateToMatchingFromPopup(): void {
this.showAssessmentPopup = false;
const userId = this.authService.userId;
if (userId) {
this.router.navigate(['/matchinglist'], {
queryParams: { user_id: userId }
});
}
}
goHomeFromPopup(): void {
this.showAssessmentPopup = false;
this.goHome();
}
// Other navigation methods remain the same...
navigateToJobRequirements(): void {
const userId = this.authService.userId;
if (!userId) {
this.authModal = 'signin';
return;
}
this.hideRoleSubnav();
// Close mobile nav if open
if (this.showMobileNav) {
this.showMobileNav = false;
}
console.log('Navigate to job requirements');
this.router.navigate(['/job-requirements'], {
queryParams: { user_id: userId }
});
}
navigateToInterviewAssessment(): void {
const userId = this.authService.userId;
if (!userId) {
this.authModal = 'signin';
return;
}
this.hideRoleSubnav();
// Close mobile nav if open
if (this.showMobileNav) {
this.showMobileNav = false;
}
console.log('Navigate to interview assessment');
this.router.navigate(['/interview-assessment'], {
queryParams: { user_id: userId }
});
}
navigateToCandidateMatching(): void {
const userId = this.authService.userId;
if (!userId) {
this.authModal = 'signin';
return;
}
this.hideRoleSubnav();
// Close mobile nav if open
if (this.showMobileNav) {
this.showMobileNav = false;
}
console.log('Navigate to candidate matching');
this.router.navigate(['/candidate-matching'], {
queryParams: { user_id: userId }
});
}
navigateToBusinessGoals(): void {
const userId = this.authService.userId;
if (!userId) {
this.authModal = 'signin';
return;
}
this.hideRoleSubnav();
// Close mobile nav if open
if (this.showMobileNav) {
this.showMobileNav = false;
}
console.log('Navigate to business goals');
this.router.navigate(['/business-goals'], {
queryParams: { user_id: userId }
});
}
navigateToPartnershipAssessment(): void {
const userId = this.authService.userId;
if (!userId) {
this.authModal = 'signin';
return;
}
this.hideRoleSubnav();
// Close mobile nav if open
if (this.showMobileNav) {
this.showMobileNav = false;
}
console.log('Navigate to partnership assessment');
this.router.navigate(['/partnership-assessment'], {
queryParams: { user_id: userId }
});
}
navigateToPartnerMatching(): void {
const userId = this.authService.userId;
if (!userId) {
this.authModal = 'signin';
return;
}
this.hideRoleSubnav();
// Close mobile nav if open
if (this.showMobileNav) {
this.showMobileNav = false;
}
console.log('Navigate to partner matching');
this.router.navigate(['/partner-matching'], {
queryParams: { user_id: userId }
});
}
// Legacy methods
toggleMarriageSubnav(): void {
this.showMarriageSubnav = !this.showMarriageSubnav;
}
hideMarriageSubnav(): void {
this.showMarriageSubnav = false;
}
onSelectRole(role: string): void {
const userId = this.authService.userId;
if (!userId) {
this.authModal = 'signin';
return;
}
if (role === 'marriage') {
this.router.navigate(['/question-answer'], {
queryParams: {
role: 'marriage',
user_id: userId
}
});
} else {
this.router.navigate(['/question-answer'], {
queryParams: {
role,
user_id: userId
}
});
}
this.hideMarriageSubnav();
}
// Auth methods
onOpenSignIn(): void {
this.authModal = 'signin';
// Close mobile nav if open
if (this.showMobileNav) {
this.showMobileNav = false;
}
}
onOpenSignUp(): void {
this.authModal = 'signup';
// Close mobile nav if open
if (this.showMobileNav) {
this.showMobileNav = false;
}
}
closeAuthModal(evt?: MouseEvent): void {
if (evt && (evt.target as HTMLElement).classList.contains('modal-backdrop')) {
this.authModal = null;
} else if (!evt) {
this.authModal = null;
}
}
// Replace the existing onSignOut method with this:
onSignOut(): void {
console.log('?? Saving progress before sign out...');
this.saveProgress();
// Close mobile nav if open
if (this.showMobileNav) {
this.showMobileNav = false;
}
// Show the sign-out popup first
this.showSignOutPopup = true;
this.hideMarriageSubnav();
this.hideRoleSubnav();
console.log('?? Showing sign out popup, will logout after animation');
console.log('?? Current progress state:', {
profile: this.profileCompleted,
expectations: this.expectationsCompleted,
assessment: this.assessmentCompleted,
matching: this.matchingCompleted
});
// Wait for the tick animation to complete (4 seconds) before actually logging out
setTimeout(() => {
this.showSignOutPopup = false;
// Now perform the actual logout
this.authService.logout();
this.isSignedIn = false;
this.userFullName = '';
this.userInitials = '';
this.changeDetectorRef.detectChanges();
console.log('? Sign out completed after animation');
}, 4000);
this.changeDetectorRef.detectChanges();
}
// UPDATED: Auth success handlers
onSignInSuccess(): void {
this.isSignedIn = true;
this.authModal = null;
const userId = this.authService.userId;
if (userId) {
this.loadUserData(userId);
this.mergeProgressOnSignIn(userId);
}
this.router.navigate(['/']);
}
onSignUpSuccess(): void {
// After a successful sign-up, prompt the user to sign in.
// Navigate home then open the sign-in modal so the user can complete authentication.
this.router.navigate(['/']).then(() => {
this.authModal = 'signin';
// Ensure UI updates
this.changeDetectorRef.detectChanges();
});
}
// Legacy navigation methods
navigateToProfileLegacy(): void {
this.navigateToProfile('marriage');
}
navigateToExpectationsLegacy(): void {
this.navigateToExpectations('marriage');
}
navigateToAssessmentLegacy(): void {
this.navigateToAssessment('marriage');
}
navigateToMatchingProfileLegacy(): void {
this.navigateToMatchingProfile('marriage');
}
navigateToLikedProfiles(): void {
const userId = this.authService.userId;
if (!userId) {
this.authModal = 'signin';
return;
}
this.router.navigate(['/matchinglist'], {
queryParams: {
user_id: userId,
view: 'liked'
}
});
}
// Role selection
selectRole(role: string): void {
const userId = this.authService.userId;
if (!userId) {
this.authModal = 'signin';
return;
}
this.signupService.assignRole(userId, role).subscribe({
next: (res: any) => {
console.log('Role saved:', res);
this.router.navigate(['/question-answer'], {
queryParams: {
role,
user_id: userId
}
});
},
error: (err: any) => {
console.error('Role assign failed:', err);
alert('Failed to assign role.');
}
});
}
// UPDATED: Chatbot methods to match IntroPageComponent functionality
openChatbot(): void {
// Close mobile nav if open
if (this.showMobileNav) {
this.showMobileNav = false;
}
this.showChatbot = true;
document.body.style.overflow = 'hidden';
this.changeDetectorRef.detectChanges();
}
closeChatbot(evt?: MouseEvent): void {
if (evt && (evt.target as HTMLElement).classList.contains('modal-backdrop')) {
this.showChatbot = false;
} else if (!evt) {
this.showChatbot = false;
}
if (!this.authModal) {
document.body.style.overflow = '';
}
this.changeDetectorRef.detectChanges();
}
askQuickQuestion(question: string): void {
console.log('Quick question asked:', question);
this.addUserMessage(question);
// Simulate bot response after delay
setTimeout(() => {
let response = '';
switch (question) {
case 'How does the matching process work?':
response = 'Our matching process uses adaptive assessment technology combined with established psychological frameworks. You\'ll complete a 15-20 minute assessment, and our system analyzes your responses to find compatible matches based on behavioral patterns and compatibility factors.';
break;
case 'What personality models do you use?':
response = 'We use several established psychological frameworks including the Big Five personality model (Openness, Conscientiousness, Extraversion, Agreeableness, Neuroticism), along with complementary models for specific contexts like marriage compatibility and workplace dynamics.';
break;
case 'How do I reset my password?':
response = 'To reset your password, click on the "Sign In" button, then select "Forgot Password" on the login screen. You\'ll receive an email with instructions to reset your password. If you need further assistance, contact our support team at support@pykara.com.';
break;
case 'Contact support team':
response = 'You can reach our human support team by emailing info@pykara.ai or calling +91 99941 90964. Our support hours are Monday-Friday, 9 AM - 6 PM EST. For urgent matters, please include "URGENT" in your email subject line.';
break;
default:
response = 'Thank you for your question. Our support team will get back to you shortly. For immediate assistance, please contact us at support@pykara.com';
}
this.addBotMessage(response);
}, 1000);
}
sendMessage(chatInput: any): void {
const message = chatInput.value.trim();
if (message) {
console.log('Message sent:', message);
this.addUserMessage(message);
setTimeout(() => {
this.addBotMessage('Thank you for your message. Our support team will review your question and get back to you within 24 hours. For immediate assistance, please contact us at info@pykara.ai or call +91 99941 90964.');
}, 1000);
chatInput.value = '';
}
}
private addUserMessage(message: string): void {
const chatMessages = document.querySelector('.chat-messages');
if (chatMessages) {
const userMessage = document.createElement('div');
userMessage.className = 'message user-message';
userMessage.innerHTML = `
<div class="message-avatar">
<i class="fa-solid fa-user"></i>
</div>
<div class="message-content">
<p>${message}</p>
</div>
`;
chatMessages.appendChild(userMessage);
this.scrollToBottom();
}
}
private addBotMessage(message: string): void {
const chatMessages = document.querySelector('.chat-messages');
if (chatMessages) {
const botMessage = document.createElement('div');
botMessage.className = 'message bot-message';
botMessage.innerHTML = `
<div class="message-avatar">
<i class="fa-solid fa-robot"></i>
</div>
<div class="message-content">
<p>${message}</p>
</div>
`;
chatMessages.appendChild(botMessage);
this.scrollToBottom();
}
}
private scrollToBottom(): void {
setTimeout(() => {
const chatMessages = document.querySelector('.chat-messages');
if (chatMessages) {
chatMessages.scrollTop = chatMessages.scrollHeight;
}
}, 100);
}
// CORRECTED: Single onEsc method that handles all cases
// Update onEsc method to close mobile nav
@HostListener('document:keydown.escape')
onEsc(): void {
if (this.showSignOutPopup) {
return;
}
if (this.showMobileNav) {
this.showMobileNav = false;
this.activeRoleMenuMobile = null;
} else if (this.showChatbot) {
this.closeChatbot();
} else if (this.authModal) {
this.closeAuthModal();
} else if (this.showAssessmentPopup) {
this.showAssessmentPopup = false;
}
}
// Add click outside to close mobile nav
@HostListener('document:click', ['$event'])
onClickOutside(event: MouseEvent): void {
const target = event.target as HTMLElement;
if (this.showMobileNav &&
!target.closest('.mobile-nav-overlay') &&
!target.closest('.mobile-menu-toggle') &&
!target.closest('.mobile-nav-link')) {
this.showMobileNav = false;
this.activeRoleMenuMobile = null;
}
}
// Method to manually update progress
updateProgress(step: string, completed: boolean): void {
console.log(`?? Updating progress: ${step} = ${completed}`);
switch (step) {
case 'profile':
this.profileCompleted = completed;
break;
case 'expectations':
this.expectationsCompleted = completed;
break;
case 'assessment':
this.assessmentCompleted = completed;
break;
case 'matching':
this.matchingCompleted = completed;
break;
}
this.saveProgress();
this.changeDetectorRef.detectChanges();
}
// Add this method to trigger progress updates from other components
markStepCompleted(step: string): void {
console.log(`?? Marking step as completed: ${step}`);
this.updateProgress(step, true);
this.saveProgress();
this.changeDetectorRef.detectChanges();
const event = new CustomEvent(`${step}Completed`, {
detail: { timestamp: Date.now() }
});
window.dispatchEvent(event);
console.log(`? Step ${step} marked as completed`);
}
// Add a method to force progress refresh
refreshProgress(): void {
this.syncProgressFromStorage();
this.changeDetectorRef.detectChanges();
}
// Debug method to check current state
debugProgress(): void {
console.log('?? DEBUG - Current Progress State:', {
profileCompleted: this.profileCompleted,
expectationsCompleted: this.expectationsCompleted,
assessmentCompleted: this.assessmentCompleted,
matchingCompleted: this.matchingCompleted,
userId: this.authService.userId,
localStorage: localStorage.getItem(`user_progress_${this.authService.userId}`)
});
}
// NEW: Load progress from any available source (user-specific or general)
private loadProgressFromAnySource(): void {
const currentUserId = this.authService.userId;
if (currentUserId) {
this.syncProgressFromStorage();
} else {
const genericProgress = localStorage.getItem('anonymous_progress');
if (genericProgress) {
try {
const progressData = JSON.parse(genericProgress);
this.profileCompleted = progressData.profileCompleted || false;
this.expectationsCompleted = progressData.expectationsCompleted || false;
this.assessmentCompleted = progressData.assessmentCompleted || false;
this.matchingCompleted = progressData.matchingCompleted || false;
console.log('?? Loaded anonymous progress from localStorage:', progressData);
} catch (e) {
console.error('Error parsing anonymous progress data:', e);
}
} else {
this.tryToLoadProgressFromAnyUser();
}
}
}
// NEW: Merge anonymous progress with user progress when signing in
private mergeProgressOnSignIn(userId: number): void {
const anonymousProgress = localStorage.getItem('anonymous_progress');
let anonymousData: any = {};
if (anonymousProgress) {
try {
anonymousData = JSON.parse(anonymousProgress);
console.log('?? Found anonymous progress to merge:', anonymousData);
} catch (e) {
console.error('Error parsing anonymous progress:', e);
}
}
const userProgress = localStorage.getItem(`user_progress_${userId}`);
let userData: any = {};
if (userProgress) {
try {
userData = JSON.parse(userProgress);
console.log('?? Found existing user progress:', userData);
} catch (e) {
console.error('Error parsing user progress:', e);
}
}
const mergedProgress = {
profileCompleted: userData.profileCompleted || anonymousData.profileCompleted || false,
expectationsCompleted: userData.expectationsCompleted || anonymousData.expectationsCompleted || false,
assessmentCompleted: userData.assessmentCompleted || anonymousData.assessmentCompleted || false,
matchingCompleted: userData.matchingCompleted || anonymousData.matchingCompleted || false,
lastUpdated: new Date().toISOString()
};
localStorage.setItem(`user_progress_${userId}`, JSON.stringify(mergedProgress));
this.profileCompleted = mergedProgress.profileCompleted;
this.expectationsCompleted = mergedProgress.expectationsCompleted;
this.assessmentCompleted = mergedProgress.assessmentCompleted;
this.matchingCompleted = mergedProgress.matchingCompleted;
localStorage.removeItem('anonymous_progress');
console.log('? Progress merged after sign in:', mergedProgress);
this.changeDetectorRef.detectChanges();
}
private toggleBodyScroll(): void {
const url = (this.router.url || '').split('?')[0];
if (url === '/' || url.startsWith('/intro')) {
document.body.classList.add('body-scrollable');
} else {
document.body.classList.remove('body-scrollable');
}
}
}