| 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';
|
|
|
|
|
| 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],
|
| 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 = '';
|
|
|
|
|
| mandatoryFields: { [key: string]: boolean } = {};
|
|
|
|
|
| showTutorialModal = false;
|
|
|
|
|
| openDropdowns: { [key: string]: boolean } = {};
|
|
|
|
|
| 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
|
| ) { }
|
|
|
|
|
| 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
|
| });
|
|
|
|
|
| const nonReviewCategories = this.categoriesMeta.filter(cat => cat.key !== 'review');
|
| if (nonReviewCategories.length > 0) {
|
| this.selectedReviewCategory = nonReviewCategories[0].key;
|
| }
|
|
|
|
|
| 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() {
|
|
|
| }
|
|
|
|
|
| isAdditionalRemarksField(question?: ExpectationQuestion): boolean {
|
| if (question) {
|
|
|
| const label = question.question?.toLowerCase();
|
| const columnKey = question.column_key?.toLowerCase();
|
|
|
|
|
| const popupFields = [
|
| 'summary of expectations',
|
| 'expectation summary',
|
| 'additional remarks',
|
| 'remark',
|
| 'remarks',
|
| 'summary',
|
| 'description'
|
| ];
|
|
|
| return popupFields.some(field =>
|
| label?.includes(field) || columnKey?.includes(field)
|
| );
|
| }
|
|
|
|
|
| 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 {
|
|
|
| if (this.isAdditionalRemarksField(question)) {
|
| this.popupQuestion = question;
|
| this.popupTextValue = this.getFormValue(question.column_key) || '';
|
| this.showTextInputPopup = true;
|
|
|
|
|
| setTimeout(() => {
|
| this.initializeTextareaHeight();
|
| });
|
| }
|
|
|
| }
|
|
|
| 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();
|
| }
|
|
|
|
|
| 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();
|
|
|
|
|
| const length = textarea.value.length;
|
| textarea.setSelectionRange(length, length);
|
| }
|
| }
|
|
|
| adjustTextareaHeight(textarea: HTMLTextAreaElement): void {
|
|
|
| textarea.style.height = 'auto';
|
|
|
|
|
| const maxHeight = 400;
|
| const newHeight = Math.min(textarea.scrollHeight, maxHeight);
|
| textarea.style.height = newHeight + 'px';
|
|
|
|
|
| textarea.style.overflowY = textarea.scrollHeight > maxHeight ? 'auto' : 'hidden';
|
| }
|
|
|
|
|
| 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;
|
| }
|
|
|
| openTutorialModal(): void {
|
| this.showTutorialModal = true;
|
|
|
| localStorage.setItem('mandatory_tutorial_seen', 'true');
|
| this.cdRef.detectChanges();
|
| console.log('📚 Opening mandatory fields tutorial');
|
| }
|
|
|
| closeTutorialModal(): void {
|
| this.showTutorialModal = false;
|
| this.cdRef.detectChanges();
|
| }
|
|
|
|
|
| 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();
|
| }
|
|
|
|
|
| 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();
|
| }
|
|
|
|
|
| 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`;
|
| }
|
|
|
|
|
| @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();
|
| }
|
| }
|
|
|
|
|
| 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;
|
| }
|
|
|
|
|
| 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) {
|
|
|
| }
|
| }
|
|
|
| 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();
|
|
|
|
|
| this.showMandatoryTutorial();
|
|
|
| setTimeout(() => {
|
| this.enhanceUserExperience();
|
| }, 100);
|
|
|
| console.log('✅ UserPreferences component initialized');
|
| }
|
|
|
| private showMandatoryTutorial(): void {
|
|
|
| const tutorialSeen = localStorage.getItem('mandatory_tutorial_seen');
|
|
|
| if (!tutorialSeen) {
|
|
|
| setTimeout(() => {
|
| this.showTutorialModal = true;
|
|
|
| localStorage.setItem('mandatory_tutorial_seen', 'true');
|
| this.cdRef.detectChanges();
|
| console.log('📚 Auto-showing mandatory fields tutorial');
|
| }, 800);
|
| }
|
| }
|
|
|
| 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;
|
|
|
|
|
| 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<string, string> = {
|
| '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;
|
|
|
| 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;
|
|
|
| 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;
|
| }
|
|
|
|
|
| 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)';
|
| }
|
|
|
|
|
| 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;
|
| }
|
|
|
|
|
| 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');
|
| }
|
| }
|
|
|