import { Component, OnInit, Renderer2, ElementRef, HostListener, ChangeDetectorRef } from '@angular/core'; import { FormBuilder, FormGroup, FormArray, FormControl, ReactiveFormsModule } from '@angular/forms'; import { CommonModule } from '@angular/common'; import { Router, ActivatedRoute } from '@angular/router'; import { UserPreferencesService, ExpectationQuestion } from './user-preferences.service'; import { AuthService } from '../services/auth.service'; import { FormsModule } from '@angular/forms'; // Add this import // Add Truncate Pipe import { Pipe, PipeTransform } from '@angular/core'; @Pipe({ name: 'truncate', standalone: true }) export class TruncatePipe implements PipeTransform { transform(value: string, limit: number = 100, trail: string = '...'): string { if (!value) return ''; return value.length > limit ? value.substring(0, limit) + trail : value; } } @Component({ selector: 'app-user-preferences', standalone: true, imports: [CommonModule, ReactiveFormsModule, TruncatePipe, FormsModule], // Add FormsModule here templateUrl: './user-preferences.component.html', styleUrls: ['./user-preferences.component.css'] }) export class UserPreferencesComponent implements OnInit { questions: ExpectationQuestion[] = []; form!: FormGroup; user_id = 1; role: string | null = null; isLoading = true; showModal = false; progress = 0; savedSuccessfully = false; selectedReviewCategory: string = ''; // Mandatory fields tracking mandatoryFields: { [key: string]: boolean } = {}; // Tutorial modal for mandatory fields showTutorialModal = false; // Property to track open dropdowns openDropdowns: { [key: string]: boolean } = {}; // Text input popup properties showTextInputPopup: boolean = false; popupQuestion: ExpectationQuestion | null = null; popupTextValue: string = ''; isEditingExistingPreferences = false; existingPreferencesData: any = null; categoriesMeta = [ { key: 'personal_education', title: 'Personal & Education' }, { key: 'family_values', title: 'Family & Values' }, { key: 'lifestyle', title: 'Lifestyle & Habits' }, { key: 'finances_dealbreakers', title: 'Finances & Deal Breakers' }, { key: 'review', title: 'Review' } ]; selectedCategory: string = this.categoriesMeta[0]?.key || ''; currentTabIndex: number = 0; constructor( private service: UserPreferencesService, private fb: FormBuilder, private router: Router, private route: ActivatedRoute, private renderer: Renderer2, private el: ElementRef, private authService: AuthService, private cdRef: ChangeDetectorRef ) { } // Add the missing ngOnInit method ngOnInit(): void { this.route.queryParamMap.subscribe(params => { const qpUser = params.get('user_id'); const qpRole = params.get('role'); if (qpUser) { this.user_id = Number(qpUser); } else { this.user_id = this.authService.userId || 1; } this.role = qpRole; console.log('🔍 UserPreferences initialized:', { user_id: this.user_id, role: this.role }); // Set default review category const nonReviewCategories = this.categoriesMeta.filter(cat => cat.key !== 'review'); if (nonReviewCategories.length > 0) { this.selectedReviewCategory = nonReviewCategories[0].key; } // Debug check for mandatory fields console.log('🔍 DEBUG: Checking current mandatory fields in database for user:', this.user_id); this.service.checkMandatoryFields(this.user_id).subscribe({ next: (result) => { console.log('🔍 CURRENT MANDATORY FIELDS IN DB:', result); }, error: (err) => { console.error('❌ Failed to check mandatory fields:', err); } }); this.loadQuestionsAndPreferences(); }); } private enhanceUserExperience(): void { setTimeout(() => { const formContainer = document.querySelector('.form-container'); if (formContainer) { formContainer.scrollTop = 0; } }, 150); } getProgressBarWidth(): number { if (this.selectedCategory === 'review') { return 95; } const currentIndex = this.categoriesMeta.findIndex(cat => cat.key === this.selectedCategory); if (currentIndex >= 0) { return ((currentIndex + 1) / (this.categoriesMeta.length + 1)) * 100; } return 0; } getStepLabel(title: string): string { const words = title.split(' '); return words.length > 2 ? words[0] : title.split(' ')[0]; } @HostListener('window:resize') onWindowResize() { // Trigger responsive behavior } // Text Input Popup Methods isAdditionalRemarksField(question?: ExpectationQuestion): boolean { if (question) { // Check if this is specifically the "Summary of Expectations" or similar fields const label = question.question?.toLowerCase(); const columnKey = question.column_key?.toLowerCase(); // Define which fields should use the popup const popupFields = [ 'summary of expectations', 'expectation summary', 'additional remarks', 'remark', 'remarks', 'summary', 'description' ]; return popupFields.some(field => label?.includes(field) || columnKey?.includes(field) ); } // For the popup overlay check (when no question parameter) const currentLabel = this.popupQuestion?.question?.toLowerCase(); const currentColumnKey = this.popupQuestion?.column_key?.toLowerCase(); const popupFields = [ 'summary of expectations', 'expectation summary', 'additional remarks', 'remark', 'remarks', 'summary', 'description' ]; return popupFields.some(field => currentLabel?.includes(field) || currentColumnKey?.includes(field) ); } openTextInputPopup(question: ExpectationQuestion): void { // Only open popup for specific fields (like Summary of Expectations) if (this.isAdditionalRemarksField(question)) { this.popupQuestion = question; this.popupTextValue = this.getFormValue(question.column_key) || ''; this.showTextInputPopup = true; // Initialize textarea height after view updates setTimeout(() => { this.initializeTextareaHeight(); }); } // For other fields, do nothing (no popup will open) } closeTextInputPopup(): void { this.showTextInputPopup = false; this.popupQuestion = null; this.popupTextValue = ''; } saveTextInputPopup(): void { if (this.popupQuestion) { const control = this.form.get(this.popupQuestion.column_key); if (control) { control.setValue(this.popupTextValue); } this.onInputChange(this.popupQuestion.column_key); } this.closeTextInputPopup(); } // Auto-expanding textarea functionality for popup only onTextareaInput(event: Event): void { const textarea = event.target as HTMLTextAreaElement; this.adjustTextareaHeight(textarea); } initializeTextareaHeight(): void { const textarea = document.querySelector('.text-input-popup-field') as HTMLTextAreaElement; if (textarea) { this.adjustTextareaHeight(textarea); textarea.focus(); // Set cursor to end of text const length = textarea.value.length; textarea.setSelectionRange(length, length); } } adjustTextareaHeight(textarea: HTMLTextAreaElement): void { // Reset height to auto to get the correct scrollHeight textarea.style.height = 'auto'; // Set the height to scrollHeight to expand, with max limit const maxHeight = 400; const newHeight = Math.min(textarea.scrollHeight, maxHeight); textarea.style.height = newHeight + 'px'; // Enable scrolling only when content exceeds max height textarea.style.overflowY = textarea.scrollHeight > maxHeight ? 'auto' : 'hidden'; } // Mandatory Fields Methods isMandatory(columnKey: string): boolean { return this.mandatoryFields[columnKey] === true; } onMandatoryChange(columnKey: string, value: string): void { this.mandatoryFields[columnKey] = value === 'mandatory'; console.log(`🎯 Mandatory changed for ${columnKey}:`, this.mandatoryFields[columnKey]); this.updateProgress(); this.cdRef.detectChanges(); } getMandatoryFieldsCount(): number { const count = Object.values(this.mandatoryFields).filter(isMandatory => isMandatory).length; console.log(`📊 Mandatory fields count: ${count}`); return count; } // In the UserPreferencesComponent class openTutorialModal(): void { this.showTutorialModal = true; // Mark as seen when opened (optional) localStorage.setItem('mandatory_tutorial_seen', 'true'); this.cdRef.detectChanges(); console.log('📚 Opening mandatory fields tutorial'); } closeTutorialModal(): void { this.showTutorialModal = false; this.cdRef.detectChanges(); } // Event Handler Methods onTextInputChange(event: any, columnKey: string): void { const value = event.target.value; this.form.get(columnKey)?.setValue(value); this.updateProgress(); this.cdRef.detectChanges(); } onSelectChange(event: any, columnKey: string): void { const value = event.target.value; this.form.get(columnKey)?.setValue(value); this.updateProgress(); this.cdRef.detectChanges(); } onRadioChange(event: any, columnKey: string): void { const value = event.target.value; this.form.get(columnKey)?.setValue(value); this.updateProgress(); this.cdRef.detectChanges(); } onCheckboxSingleChange(event: any, columnKey: string): void { const value = event.target.checked; this.form.get(columnKey)?.setValue(value); this.updateProgress(); this.cdRef.detectChanges(); } // Multi-select checkbox handler (used in both original and dropdown) onCheckboxChange(event: any, columnKey: string): void { const formArray: FormArray = this.form.get(columnKey) as FormArray; const value = event.target.value; const isChecked = event.target.checked; if (isChecked) { if (!formArray.value.includes(value)) { formArray.push(new FormControl(value)); } } else { const index = formArray.controls.findIndex(x => x.value === value); if (index >= 0) { formArray.removeAt(index); } } this.updateProgress(); this.cdRef.detectChanges(); } // Dropdown multi-select specific methods toggleDropdown(columnKey: string): void { this.openDropdowns[columnKey] = !this.openDropdowns[columnKey]; } isDropdownOpen(columnKey: string): boolean { return this.openDropdowns[columnKey] === true; } getSelectedOptionsText(columnKey: string): string { const formArray = this.form.get(columnKey) as FormArray; if (!formArray || formArray.value.length === 0) { return ''; } const selectedValues = formArray.value; if (selectedValues.length === 1) { return selectedValues[0]; } return `${selectedValues.length} options selected`; } // Close dropdown when clicking outside @HostListener('document:click', ['$event']) onDocumentClick(event: MouseEvent): void { const target = event.target as HTMLElement; if (!target.closest('.multiselect-dropdown-checkbox')) { this.openDropdowns = {}; this.cdRef.detectChanges(); } } // Check if all options are selected areAllOptionsSelected(question: ExpectationQuestion): boolean { const formArray = this.form.get(question.column_key) as FormArray; const options = this.getOptions(question); return formArray && options.length > 0 && formArray.value.length === options.length; } // Toggle select all toggleSelectAll(question: ExpectationQuestion): void { const formArray: FormArray = this.form.get(question.column_key) as FormArray; const options = this.getOptions(question); formArray.clear(); if (!this.areAllOptionsSelected(question)) { options.forEach(option => { formArray.push(new FormControl(option)); }); } this.updateProgress(); this.cdRef.detectChanges(); } isRadioSelected(columnKey: string, option: any): boolean { const value = this.getFormValue(columnKey); return value === option; } isCheckboxSelected(columnKey: string, option: any): boolean { const formArray = this.form.get(columnKey) as FormArray; return formArray && formArray.value.includes(option); } getFormValue(columnKey: string): any { const control = this.form?.get(columnKey); if (!control) return ''; if (control instanceof FormArray) { return control.value || []; } return control.value || ''; } private cleanValue(value: string): string { if (!value) return value; let cleaned = value .replace(/^\["+|"+]$/g, '') .replace(/^"+|"+$/g, '') .replace(/\\"/g, '"') .trim(); if (cleaned.startsWith('[') || cleaned.startsWith('{')) { try { const parsed = JSON.parse(cleaned); if (Array.isArray(parsed) && parsed.length > 0) { return parsed.map(item => this.cleanValue(String(item))).join(', '); } return String(parsed); } catch (e) { // If parsing fails, return the cleaned version } } return cleaned; } private loadQuestionsAndPreferences(): void { this.isLoading = true; console.log('📥 Loading questions and preferences...'); this.service.getQuestions().subscribe({ next: (data) => { this.questions = data; console.log('✅ Total questions loaded:', this.questions.length); this.buildForm(); this.checkExistingPreferences(); }, error: (error) => { console.error('❌ Error loading questions:', error); this.isLoading = false; this.cdRef.detectChanges(); } }); } private checkExistingPreferences(): void { console.log('🔍 Checking for existing preferences...'); this.service.getExistingPreferences(this.user_id).subscribe({ next: (existingData: any) => { if (existingData && Object.keys(existingData).length > 0) { this.isEditingExistingPreferences = true; this.existingPreferencesData = existingData; console.log('📝 Loading existing preferences data:', existingData); this.populateFormWithExistingData(); } else { console.log('📝 No existing preferences found, creating new ones'); } this.finalizeInitialization(); }, error: (err) => { console.log('📝 No existing preferences found or error checking:', err); this.finalizeInitialization(); } }); } private finalizeInitialization(): void { this.setInitialSelectedCategory(); this.updateProgress(); this.isLoading = false; this.debugCategoriesAndQuestions(); this.cdRef.detectChanges(); // Auto-show tutorial on first load this.showMandatoryTutorial(); setTimeout(() => { this.enhanceUserExperience(); }, 100); console.log('✅ UserPreferences component initialized'); } private showMandatoryTutorial(): void { // Check if user has seen the tutorial before const tutorialSeen = localStorage.getItem('mandatory_tutorial_seen'); if (!tutorialSeen) { // Show tutorial on first load with a slight delay setTimeout(() => { this.showTutorialModal = true; // Mark as seen when shown automatically localStorage.setItem('mandatory_tutorial_seen', 'true'); this.cdRef.detectChanges(); console.log('📚 Auto-showing mandatory fields tutorial'); }, 800); // Slightly longer delay for better UX } } private buildForm(): void { const group: any = {}; this.questions.forEach(q => { if (q.input_type === 'multi_select') { group[q.column_key] = this.fb.array([]); } else { const existingValue = this.existingPreferencesData ? this.existingPreferencesData[q.column_key] : ''; let initialValue: any = ''; if (q.input_type === 'checkbox') { initialValue = existingValue === true || existingValue === 'true' || existingValue === '1' || existingValue === 1; } else if (q.input_type === 'radio' || q.input_type === 'select') { if (Array.isArray(existingValue)) { initialValue = existingValue[0] || ''; } else if (typeof existingValue === 'string') { initialValue = this.cleanValue(existingValue); } else { initialValue = existingValue || ''; } } else { initialValue = existingValue || ''; } group[q.column_key] = new FormControl(initialValue); } this.mandatoryFields[q.column_key] = false; }); this.form = this.fb.group(group); console.log('✅ Form built with questions:', this.questions.length); console.log('📋 Form controls:', Object.keys(this.form.controls)); this.questions.forEach(q => { const control = this.form.get(q.column_key); console.log(`🔍 Control for ${q.column_key}:`, control?.constructor.name, 'Type:', q.input_type); }); this.updateProgress(); this.form.valueChanges.subscribe(() => { this.updateProgress(); this.cdRef.detectChanges(); }); console.log('✅ Form built with', this.questions.length, 'questions'); } private populateFormWithExistingData(): void { console.log('🔄 Populating form with existing data...'); let existingMandatoryFields: { [key: string]: any } = {}; if (this.existingPreferencesData['_mandatory_fields']) { try { if (typeof this.existingPreferencesData['_mandatory_fields'] === 'string') { existingMandatoryFields = JSON.parse(this.existingPreferencesData['_mandatory_fields']); } else { existingMandatoryFields = this.existingPreferencesData['_mandatory_fields']; } console.log('🎯 Parsed mandatory fields:', existingMandatoryFields); } catch (e) { console.error('❌ Error parsing mandatory fields:', e); } } this.questions.forEach(q => { const existingValue = this.existingPreferencesData[q.column_key]; const existingMandatory = existingMandatoryFields[q.column_key]; console.log(`📝 Processing ${q.column_key}:`, { existingValue, existingMandatory, inputType: q.input_type }); if (q.input_type === 'multi_select') { const formControl = this.form.get(q.column_key); if (formControl && formControl instanceof FormArray) { const formArray: FormArray = formControl; let values: string[] = []; if (existingValue) { if (typeof existingValue === 'string') { const cleanValue = existingValue.replace(/[\[\]"]/g, ''); values = cleanValue.split(',').map(item => item.trim()).filter(item => item.length > 0); } else if (Array.isArray(existingValue)) { values = existingValue.filter(item => item && item.length > 0); } } console.log(`📋 Multi-select values for ${q.column_key}:`, values); formArray.clear(); values.forEach(value => { formArray.push(new FormControl(value)); }); } else { console.warn(`⚠️ FormArray not found for multi-select question: ${q.column_key}`); } } else { const finalValue = existingValue || ''; console.log(`📋 Setting ${q.column_key} to:`, finalValue); const formControl = this.form.get(q.column_key); if (formControl) { formControl.setValue(finalValue); } else { console.warn(`⚠️ FormControl not found for question: ${q.column_key}`); } } if (existingMandatory !== undefined && existingMandatory !== null) { this.mandatoryFields[q.column_key] = existingMandatory === true || existingMandatory === 'mandatory' || existingMandatory === 'true'; console.log(`🎯 Mandatory for ${q.column_key}:`, this.mandatoryFields[q.column_key]); } else { this.mandatoryFields[q.column_key] = false; } }); console.log('✅ Form populated with existing data'); console.log('📋 Current form values:', this.form.value); console.log('📋 Current mandatory fields:', this.mandatoryFields); setTimeout(() => { this.updateProgress(); }); } getOptions(q: ExpectationQuestion): string[] { const opts = q.options; if (Array.isArray(opts)) return (opts as string[]).filter(Boolean); if (typeof opts === 'string') return opts.split(',').map(s => s.trim()).filter(Boolean); return []; } getQuestionsByCategory(category: string): ExpectationQuestion[] { const categoryMappings: { [key: string]: string[] } = { 'personal_education': ['demographics', 'educationcareer', 'education', 'career', 'personal'], 'family_values': ['family', 'values', 'family_values', 'family&values'], 'finances_dealbreakers': ['finances', 'dealbreakers', 'financial', 'deal_breakers', 'finances_dealbreakers'], 'lifestyle': ['lifestyle', 'habits', 'lifestyle_habits'], 'interests': ['interests', 'hobbies', 'social', 'interests_social'] }; const targetCategories = categoryMappings[category] || [category]; const filteredQuestions = this.questions.filter(q => { if (!q.category) return false; const qCategory = q.category.toLowerCase().trim(); return targetCategories.some(target => qCategory.includes(target.toLowerCase()) || target.toLowerCase().includes(qCategory) ); }); return filteredQuestions; } private debugCategoriesAndQuestions(): void { console.log('=== DEBUG: Available Categories and Questions ==='); const allCategories = [...new Set(this.questions.map(q => q.category))]; console.log('All categories in questions:', allCategories); this.categoriesMeta.forEach(cat => { if (cat.key !== 'review') { const questions = this.getQuestionsByCategory(cat.key); console.log(`Category ${cat.key} (${cat.title}): ${questions.length} questions`); questions.forEach(q => { console.log(` - ${q.column_key}: ${q.question}`); }); } }); console.log('=== END DEBUG ==='); } selectCategory(key: string): void { this.selectedCategory = key; const categoryIndex = this.categoriesMeta.findIndex(cat => cat.key === key); this.currentTabIndex = categoryIndex >= 0 ? categoryIndex : this.categoriesMeta.length; // Initialize selected review category when entering review tab if (key === 'review') { const nonReviewCategories = this.categoriesMeta.filter(cat => cat.key !== 'review'); if (nonReviewCategories.length > 0) { this.selectedReviewCategory = nonReviewCategories[0].key; } } if (key === 'review') { setTimeout(() => { this.debugReviewData(); this.debugFormValues(); }, 100); } this.enhanceUserExperience(); this.cdRef.detectChanges(); } selectReviewCategory(categoryKey: string): void { this.selectedReviewCategory = categoryKey; } getReviewCategoryTitle(categoryKey: string): string { const category = this.categoriesMeta.find(c => c.key === categoryKey); return category?.title || categoryKey; } private setInitialSelectedCategory(): void { const firstWithQuestions = this.categoriesMeta.find(c => c.key !== 'review' && this.getQuestionsByCategory(c.key).length > 0); if (firstWithQuestions) { this.selectedCategory = firstWithQuestions.key; this.currentTabIndex = this.categoriesMeta.findIndex(c => c.key === firstWithQuestions.key); } } getCategoryAnsweredCount(key: string): number { const qs = this.getQuestionsByCategory(key); return qs.reduce((acc, q) => { return acc + (this.isAnswered(q) ? 1 : 0); }, 0); } getCategoryPercent(key: string): number { const total = this.getQuestionsByCategory(key).length || 1; const answered = this.getCategoryAnsweredCount(key); return Math.round((answered / total) * 100); } getCategoryIcon(categoryKey: string): string { const iconMap: { [key: string]: string } = { 'personal_education': 'fa-user-graduate', 'family_values': 'fa-people-roof', 'lifestyle': 'fa-heart', 'finances_dealbreakers': 'fa-sack-dollar', 'interests': 'fa-bullseye', 'review': 'fa-check' }; return iconMap[categoryKey] || 'fa-question'; } getCurrentCategoryIcon(): string { return this.getCategoryIcon(this.selectedCategory); } getCurrentCategoryTitle(): string { const category = this.categoriesMeta.find(c => c.key === this.selectedCategory); return category?.title || 'Category'; } getCurrentCategoryDescription(): string { const descriptions: Record = { 'personal_education': 'Share your background, education, and career details', 'family_values': 'Tell us about your family expectations and core values', 'lifestyle': 'Describe your daily habits and lifestyle preferences', 'finances_dealbreakers': 'Set your financial expectations and deal breakers', 'interests': 'Share your hobbies, interests, and social preferences', 'review': 'Review all the information you have provided' }; return descriptions[this.selectedCategory] || 'Complete this section to improve your matches'; } onInputChange(columnKey: string): void { this.updateProgress(); this.cdRef.detectChanges(); } updateProgress(): void { const total = Object.keys(this.form.controls).length || 1; const filled = Object.values(this.form.value).filter(v => { if (Array.isArray(v)) return v.length > 0; return !!v && v.toString().trim().length > 0; }).length; this.progress = Math.round((filled / total) * 100); } submit(): void { console.log('🚀 SUBMITTING USER PREFERENCES FORM...'); if (this.form.valid) { this.savedSuccessfully = false; this.showModal = true; this.isLoading = true; const payload: any = { user_id: this.user_id, ...this.form.value, _mandatory_fields: this.mandatoryFields }; console.log('🎯 Mandatory fields to save:', this.mandatoryFields); console.log('📊 Mandatory fields count:', this.getMandatoryFieldsCount()); console.log('📤 COMPLETE PAYLOAD:', JSON.stringify(payload, null, 2)); const submitObservable = this.isEditingExistingPreferences ? this.service.updatePreferences(this.user_id, payload) : this.service.saveResponse(payload); submitObservable.subscribe({ next: (response) => { console.log('✅ Successfully saved preferences with mandatory fields:', response); this.savedSuccessfully = true; this.isLoading = false; }, error: (err) => { console.error('❌ Error saving preferences:', err); this.savedSuccessfully = false; this.isLoading = false; } }); } else { console.error('❌ Form is invalid!'); console.log('Form validation errors:', this.form.errors); console.log('Form controls status:', this.form.status); } } closeModal(): void { this.showModal = false; // Remove blur effects if any const container = document.querySelector('.container'); if (container) { container.classList.remove('blur-background'); } } redirectToHome(): void { this.showModal = false; this.router.navigate(['/']); } redirectToAssessment(): void { this.showModal = false; this.router.navigate(['/llmquiz'], { queryParams: { user_id: this.user_id } }); } goToPreviousCategory(currentKey: string): void { const currentIndex = this.categoriesMeta.findIndex(cat => cat.key === currentKey); if (currentIndex > 0) { this.selectedCategory = this.categoriesMeta[currentIndex - 1].key; this.currentTabIndex = currentIndex - 1; this.enhanceUserExperience(); this.cdRef.detectChanges(); } } goToNextCategory(currentKey: string): void { const currentIndex = this.categoriesMeta.findIndex(cat => cat.key === currentKey); if (currentIndex < this.categoriesMeta.length - 1) { this.selectedCategory = this.categoriesMeta[currentIndex + 1].key; this.currentTabIndex = currentIndex + 1; } else { this.selectedCategory = 'review'; this.currentTabIndex = this.categoriesMeta.length; // Ensure review category is set when navigating to review const nonReviewCategories = this.categoriesMeta.filter(cat => cat.key !== 'review'); if (nonReviewCategories.length > 0) { this.selectedReviewCategory = nonReviewCategories[0].key; } } if (this.selectedCategory === 'review') { setTimeout(() => { this.cdRef.detectChanges(); }, 50); } this.enhanceUserExperience(); this.cdRef.detectChanges(); } trackQuestion(index: number, item: ExpectationQuestion): string { return item.column_key; } // REVIEW TAB METHODS get allFieldsAnswered(): boolean { return this.questions.length > 0 && this.questions.every(q => this.isAnswered(q)); } get unansweredCount(): number { return this.questions.filter(q => !this.isAnswered(q)).length; } isAnswered(q: ExpectationQuestion): boolean { const control = this.getFormControl(q.column_key); if (!control) return false; const value = control.value; if (q.input_type === 'multi_select') { return Array.isArray(value) && value.length > 0; } if (q.input_type === 'checkbox') { return value === true || value === 'true' || value === '1' || value === 1; } return !!value && value.toString().trim().length > 0; } getAnswerDisplay(question: ExpectationQuestion): string { const control = this.getFormControl(question.column_key); if (!control) return '(Not answered)'; let value = control.value; if (typeof value === 'string') { value = this.cleanValue(value); } if (value === null || value === undefined || value === '') { return '(Not answered)'; } // For popup fields, show truncated preview if (this.isAdditionalRemarksField(question) && typeof value === 'string' && value.length > 100) { return value.substring(0, 100) + '...'; } if (question.input_type === 'multi_select') { if (Array.isArray(value)) { const cleanedValues = value.map(v => { if (typeof v === 'string') { return this.cleanValue(v); } return v; }); return cleanedValues.length > 0 ? cleanedValues.join(', ') : '(Not answered)'; } return this.cleanValue(String(value)) || '(Not answered)'; } if (question.input_type === 'checkbox') { if (typeof value === 'boolean') { return value ? 'Yes' : 'No'; } if (typeof value === 'string') { return value.toLowerCase() === 'true' || value === '1' ? 'Yes' : 'No'; } if (typeof value === 'number') { return value === 1 ? 'Yes' : 'No'; } return value ? 'Yes' : 'No'; } if (question.input_type === 'select' || question.input_type === 'radio') { if (Array.isArray(value)) { const firstValue = value[0]; return this.cleanValue(String(firstValue)) || '(Not answered)'; } return this.cleanValue(String(value)) || '(Not answered)'; } if (Array.isArray(value)) { const cleanedValues = value.map(v => this.cleanValue(String(v))); return cleanedValues.length > 0 ? cleanedValues.join(', ') : '(Not answered)'; } if (typeof value === 'boolean') { return value ? 'Yes' : 'No'; } return this.cleanValue(String(value)) || '(Not answered)'; } getFormControl(columnKey: string): FormControl | FormArray | null { return this.form?.get(columnKey) as FormControl | FormArray | null; } // DEBUG METHODS debugFormValues(): void { console.log('=== USER PREFERENCES FORM VALUES DEBUG ==='); this.questions.forEach(q => { const value = this.getFormControl(q.column_key)?.value; const answered = this.isAnswered(q); console.log(`${q.column_key}:`, value, `(Type: ${q.input_type}, Answered: ${answered})`); }); console.log('=== END FORM VALUES DEBUG ==='); } debugReviewData(): void { console.log('=== USER PREFERENCES REVIEW TAB DEBUG ==='); console.log('Form valid:', this.form.valid); console.log('Form values:', this.form.value); console.log('All fields answered:', this.allFieldsAnswered); console.log('Unanswered count:', this.unansweredCount); console.log('Mandatory fields count:', this.getMandatoryFieldsCount()); this.categoriesMeta.forEach(cat => { if (cat.key !== 'review') { const questions = this.getQuestionsByCategory(cat.key); console.log(`Category: ${cat.title} (${cat.key})`); questions.forEach(q => { const value = this.getFormControl(q.column_key)?.value; const answered = this.isAnswered(q); const display = this.getAnswerDisplay(q); const mandatory = this.isMandatory(q.column_key); console.log(` ${q.column_key}:`, value, `Answered: ${answered}, Mandatory: ${mandatory}, Display: "${display}"`); }); } }); console.log('=== END REVIEW DEBUG ==='); } getReviewCategories(): any[] { return this.categoriesMeta.filter(cat => cat.key !== 'review'); } }