Files
427e7578-d7bf-49c8-aee9-2dd…/src/app/pages/create-survey/create-survey.page.ts
Dimas Wiese 6b0f87199c init
2026-03-15 23:53:59 +01:00

204 lines
5.9 KiB
TypeScript

/**
* create-survey.page.ts
* Page for creating a new survey or editing an existing one.
*
* When accessed via /create-survey → creates a new survey
* When accessed via /create-survey/:id → loads and edits the existing survey
*/
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { ToastController } from '@ionic/angular';
import { SurveyService } from '../../services/survey.service';
import type { Survey, Question } from '../../shared/models/survey.models';
@Component({
selector: 'app-create-survey',
templateUrl: './create-survey.page.html',
styleUrls: ['./create-survey.page.scss'],
standalone: false,
})
export class CreateSurveyPage implements OnInit {
/** True when editing an existing survey */
isEditMode = false;
existingSurveyId?: string;
// Form fields
title = '';
description = '';
questions: Question[] = [];
/** Track which question's options are being edited */
expandedQuestionIndex: number | null = null;
constructor(
private route: ActivatedRoute,
private router: Router,
private surveyService: SurveyService,
private toastCtrl: ToastController
) {}
async ngOnInit(): Promise<void> {
const id = this.route.snapshot.paramMap.get('id');
if (id) {
this.isEditMode = true;
this.existingSurveyId = id;
await this.loadSurvey(id);
} else {
// Start with one empty question for a better UX
this.addQuestion();
}
}
private async loadSurvey(id: string): Promise<void> {
const survey = await this.surveyService.getSurvey(id);
if (!survey) {
const toast = await this.toastCtrl.create({
message: 'Survey not found.',
duration: 2000,
color: 'danger',
});
await toast.present();
this.router.navigate(['/home']);
return;
}
this.title = survey.title;
this.description = survey.description ?? '';
// Deep copy so edits don't mutate the original until saved
this.questions = JSON.parse(JSON.stringify(survey.questions));
}
// -------------------------------------------------------------------------
// Question management
// -------------------------------------------------------------------------
addQuestion(): void {
const question: Question = {
id: crypto.randomUUID(),
text: '',
type: 'text',
required: false,
};
this.questions.push(question);
this.expandedQuestionIndex = this.questions.length - 1;
}
removeQuestion(index: number): void {
this.questions.splice(index, 1);
if (this.expandedQuestionIndex === index) {
this.expandedQuestionIndex = null;
}
}
moveQuestionUp(index: number): void {
if (index === 0) return;
const temp = this.questions[index - 1];
this.questions[index - 1] = this.questions[index];
this.questions[index] = temp;
}
moveQuestionDown(index: number): void {
if (index === this.questions.length - 1) return;
const temp = this.questions[index + 1];
this.questions[index + 1] = this.questions[index];
this.questions[index] = temp;
}
toggleExpand(index: number): void {
this.expandedQuestionIndex =
this.expandedQuestionIndex === index ? null : index;
}
onTypeChange(question: Question): void {
// Initialise options array when switching to multiple_choice
if (question.type === 'multiple_choice' && !question.options?.length) {
question.options = ['Option 1', 'Option 2'];
}
}
addOption(question: Question): void {
if (!question.options) question.options = [];
question.options.push(`Option ${question.options.length + 1}`);
}
removeOption(question: Question, optIndex: number): void {
question.options?.splice(optIndex, 1);
}
trackOption(index: number): number {
return index;
}
trackQuestion(index: number): number {
return index;
}
// -------------------------------------------------------------------------
// Validation
// -------------------------------------------------------------------------
get isFormValid(): boolean {
if (!this.title.trim()) return false;
if (this.questions.length === 0) return false;
return this.questions.every(
(q) =>
q.text.trim() &&
(q.type !== 'multiple_choice' || (q.options && q.options.length >= 2))
);
}
// -------------------------------------------------------------------------
// Save / Update
// -------------------------------------------------------------------------
async save(): Promise<void> {
if (!this.isFormValid) return;
const questionsToSave = this.questions.map((q) => ({
...q,
text: q.text.trim(),
// Strip empty options for multiple_choice
options:
q.type === 'multiple_choice'
? q.options?.filter((o) => o.trim()) ?? []
: undefined,
}));
if (this.isEditMode && this.existingSurveyId) {
await this.surveyService.updateSurvey(this.existingSurveyId, {
title: this.title.trim(),
description: this.description.trim() || undefined,
questions: questionsToSave,
});
const toast = await this.toastCtrl.create({
message: 'Survey updated.',
duration: 2000,
color: 'success',
});
await toast.present();
this.router.navigate(['/survey', this.existingSurveyId]);
} else {
const survey = await this.surveyService.createSurvey({
title: this.title.trim(),
description: this.description.trim() || undefined,
questions: questionsToSave,
});
const toast = await this.toastCtrl.create({
message: 'Survey created.',
duration: 2000,
color: 'success',
});
await toast.present();
this.router.navigate(['/survey', survey.id]);
}
}
cancel(): void {
if (this.isEditMode && this.existingSurveyId) {
this.router.navigate(['/survey', this.existingSurveyId]);
} else {
this.router.navigate(['/home']);
}
}
}