ask personalized questions for site creation
This commit is contained in:
@@ -3,7 +3,8 @@ package com.krrishg.dto;
|
||||
import java.util.List;
|
||||
|
||||
public record SuggestSectionsResponse(
|
||||
List<SectionSuggestion> sections
|
||||
List<SectionSuggestion> sections,
|
||||
List<PersonalizedQuestion> personalizedQuestions
|
||||
) {
|
||||
public record SectionSuggestion(
|
||||
String title,
|
||||
@@ -16,4 +17,11 @@ public record SuggestSectionsResponse(
|
||||
String title,
|
||||
String description
|
||||
) {}
|
||||
|
||||
public record PersonalizedQuestion(
|
||||
String id,
|
||||
String question,
|
||||
String type,
|
||||
List<String> options
|
||||
) {}
|
||||
}
|
||||
@@ -617,12 +617,14 @@ public class LLMService {
|
||||
}
|
||||
|
||||
private SuggestSectionsResponse parseSectionSuggestions(String llmOutput) {
|
||||
String json = extractJsonArray(llmOutput);
|
||||
String json = extractJsonObject(llmOutput);
|
||||
try {
|
||||
JsonNode root = objectMapper.readTree(json);
|
||||
List<SuggestSectionsResponse.SectionSuggestion> sections = new ArrayList<>();
|
||||
if (root.isArray()) {
|
||||
for (JsonNode node : root) {
|
||||
List<SuggestSectionsResponse.PersonalizedQuestion> questions = new ArrayList<>();
|
||||
|
||||
if (root.has("sections") && root.get("sections").isArray()) {
|
||||
for (JsonNode node : root.get("sections")) {
|
||||
String title = node.has("title") ? node.get("title").asText() : null;
|
||||
String description = node.has("description") ? node.get("description").asText() : null;
|
||||
String slug = node.has("slug") ? node.get("slug").asText() : null;
|
||||
@@ -641,15 +643,61 @@ public class LLMService {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (root.has("personalizedQuestions") && root.get("personalizedQuestions").isArray()) {
|
||||
for (JsonNode node : root.get("personalizedQuestions")) {
|
||||
String id = node.has("id") ? node.get("id").asText() : null;
|
||||
String question = node.has("question") ? node.get("question").asText() : null;
|
||||
String type = node.has("type") ? node.get("type").asText() : "text";
|
||||
if (id != null && question != null) {
|
||||
List<String> options = null;
|
||||
if (node.has("options") && node.get("options").isArray()) {
|
||||
options = new ArrayList<>();
|
||||
for (JsonNode opt : node.get("options")) {
|
||||
options.add(opt.asText());
|
||||
}
|
||||
}
|
||||
questions.add(new SuggestSectionsResponse.PersonalizedQuestion(id, question, type, options));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (sections.isEmpty()) {
|
||||
throw new IllegalArgumentException("LLM output must contain at least one section suggestion");
|
||||
}
|
||||
return new SuggestSectionsResponse(sections);
|
||||
return new SuggestSectionsResponse(sections, questions);
|
||||
} catch (JsonProcessingException e) {
|
||||
throw new IllegalArgumentException("Failed to parse section suggestions as JSON: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private String extractJsonObject(String raw) {
|
||||
if (raw == null || raw.isBlank()) {
|
||||
throw new IllegalArgumentException("LLM output is empty");
|
||||
}
|
||||
String trimmed = raw.trim();
|
||||
if (trimmed.startsWith("```")) {
|
||||
int start = trimmed.indexOf('\n');
|
||||
int end = trimmed.lastIndexOf("```");
|
||||
if (start > 0 && end > start) {
|
||||
trimmed = trimmed.substring(start, end).trim();
|
||||
}
|
||||
}
|
||||
if (!trimmed.startsWith("{")) {
|
||||
int brace = trimmed.indexOf('{');
|
||||
if (brace >= 0) {
|
||||
trimmed = trimmed.substring(brace);
|
||||
}
|
||||
}
|
||||
if (!trimmed.endsWith("}")) {
|
||||
int brace = trimmed.lastIndexOf('}');
|
||||
if (brace >= 0) {
|
||||
trimmed = trimmed.substring(0, brace + 1);
|
||||
}
|
||||
}
|
||||
return trimmed;
|
||||
}
|
||||
|
||||
private String extractJsonArray(String raw) {
|
||||
if (raw == null || raw.isBlank()) {
|
||||
throw new IllegalArgumentException("LLM output is empty");
|
||||
|
||||
@@ -380,7 +380,8 @@ class LLMControllerTest {
|
||||
List.of(
|
||||
new SuggestSectionsResponse.SectionSuggestion("Home", "Hero section", "home", List.of()),
|
||||
new SuggestSectionsResponse.SectionSuggestion("About", "Bio", "about", List.of())
|
||||
)
|
||||
),
|
||||
List.of()
|
||||
);
|
||||
when(llmService.suggestSections(any(), anyString(), anyString(), any(), any(), any())).thenReturn(response);
|
||||
|
||||
|
||||
@@ -502,7 +502,8 @@ class LLMServiceTest {
|
||||
@Test
|
||||
void suggestSectionsReturnsParsedSuggestions() {
|
||||
geminiProvider.withContent("""
|
||||
[
|
||||
{
|
||||
"sections": [
|
||||
{"title": "Home", "description": "Hero section", "slug": "home",
|
||||
"patterns": [
|
||||
{"title": "Full-screen hero", "description": "Large image with text overlay"},
|
||||
@@ -513,7 +514,12 @@ class LLMServiceTest {
|
||||
{"title": "Timeline", "description": "Vertical story timeline"}
|
||||
]},
|
||||
{"title": "Gallery", "description": "Portfolio grid", "slug": "gallery", "patterns": []}
|
||||
]
|
||||
],
|
||||
"personalizedQuestions": [
|
||||
{"id": "name", "question": "What is your name?", "type": "text"},
|
||||
{"id": "bio", "question": "Write a short bio", "type": "textarea"}
|
||||
]
|
||||
}
|
||||
""");
|
||||
|
||||
SuggestSectionsResponse response = llmService.suggestSections(
|
||||
@@ -527,6 +533,10 @@ class LLMServiceTest {
|
||||
assertEquals("Full-screen hero", response.sections().get(0).patterns().get(0).title());
|
||||
assertEquals("Timeline", response.sections().get(1).patterns().get(0).title());
|
||||
assertEquals(0, response.sections().get(2).patterns().size());
|
||||
|
||||
assertEquals(2, response.personalizedQuestions().size());
|
||||
assertEquals("name", response.personalizedQuestions().get(0).id());
|
||||
assertEquals("textarea", response.personalizedQuestions().get(1).type());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -540,9 +550,12 @@ class LLMServiceTest {
|
||||
@Test
|
||||
void suggestSectionsUsesProvidedApiKey() {
|
||||
geminiProvider.withContent("""
|
||||
[
|
||||
{
|
||||
"sections": [
|
||||
{"title": "Home", "description": "Hero", "slug": "home", "patterns": []}
|
||||
]
|
||||
],
|
||||
"personalizedQuestions": []
|
||||
}
|
||||
""");
|
||||
|
||||
SuggestSectionsResponse response = llmService.suggestSections(
|
||||
|
||||
@@ -93,8 +93,22 @@ export interface SuggestSectionsRequest {
|
||||
model?: string;
|
||||
}
|
||||
|
||||
export interface PersonalizedQuestion {
|
||||
id: string;
|
||||
question: string;
|
||||
type: string;
|
||||
options?: string[];
|
||||
}
|
||||
|
||||
export interface QuestionAnswer {
|
||||
id: string;
|
||||
question: string;
|
||||
answer: string;
|
||||
}
|
||||
|
||||
export interface SuggestSectionsResponse {
|
||||
sections: SectionSuggestion[];
|
||||
personalizedQuestions?: PersonalizedQuestion[];
|
||||
}
|
||||
|
||||
export interface SelectedSection {
|
||||
|
||||
@@ -20,7 +20,7 @@ import { LlmApiService } from '../core/services/llm-api.service';
|
||||
import { LlmConfigService } from '../core/services/llm-config.service';
|
||||
import { LlmSessionService } from './llm-session.service';
|
||||
import { GenerationService } from './generation.service';
|
||||
import { SiteStructure, GenerationVersion, LLMKeyStatus, SectionSuggestion } from '../core/models/llm';
|
||||
import { SiteStructure, GenerationVersion, LLMKeyStatus, SectionSuggestion, PersonalizedQuestion } from '../core/models/llm';
|
||||
import { SectionConfiguratorComponent, SectionConfig } from './section-configurator/section-configurator.component';
|
||||
import { PreviewDialogComponent } from './preview-dialog/preview-dialog.component';
|
||||
import { DeleteVersionDialog } from './delete-version-dialog/delete-version-dialog';
|
||||
@@ -123,6 +123,7 @@ type Phase = 'idle' | 'suggesting' | 'configuring' | 'generating';
|
||||
|
||||
<app-section-configurator
|
||||
[suggestions]="sectionSuggestions"
|
||||
[personalizedQuestions]="personalizedQuestions"
|
||||
(configComplete)="onConfigComplete($event)"
|
||||
(stepChange)="onConfigStepChange($event)"
|
||||
></app-section-configurator>
|
||||
@@ -184,7 +185,7 @@ type Phase = 'idle' | 'suggesting' | 'configuring' | 'generating';
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div *ngIf="suggestError" class="bg-red-50 border border-red-200 rounded-lg p-4 flex items-start gap-3">
|
||||
<div *ngIf="suggestError && !showMissingKeyForm" class="bg-red-50 border border-red-200 rounded-lg p-4 flex items-start gap-3">
|
||||
<mat-icon class="text-red-500 mt-0.5">error_outline</mat-icon>
|
||||
<div class="flex-1">
|
||||
<p class="text-sm font-medium text-red-800">Suggestion failed</p>
|
||||
@@ -193,6 +194,52 @@ type Phase = 'idle' | 'suggesting' | 'configuring' | 'generating';
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<mat-card *ngIf="showMissingKeyForm" class="p-4" appearance="outlined">
|
||||
<mat-card-content class="!p-0">
|
||||
<div class="flex items-start gap-3 mb-4">
|
||||
<mat-icon class="text-amber-500 mt-0.5">info</mat-icon>
|
||||
<div>
|
||||
<p class="text-sm font-medium text-amber-800">API key required for {{ setupProvider }}</p>
|
||||
<p class="text-sm text-amber-700 mt-1">{{ suggestError }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="space-y-3">
|
||||
<mat-form-field appearance="outline" class="w-full">
|
||||
<mat-label>Provider</mat-label>
|
||||
<mat-select [(ngModel)]="setupProvider">
|
||||
<mat-option value="gemini">Gemini</mat-option>
|
||||
<mat-option value="openai">OpenAI / Compatible</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<mat-form-field appearance="outline" class="w-full">
|
||||
<mat-label>API Key</mat-label>
|
||||
<input matInput [type]="setupKeyVisible ? 'text' : 'password'" [(ngModel)]="setupApiKey" />
|
||||
<button mat-icon-button matSuffix (click)="setupKeyVisible = !setupKeyVisible" type="button"
|
||||
[attr.aria-label]="setupKeyVisible ? 'Hide key' : 'Show key'">
|
||||
<mat-icon>{{ setupKeyVisible ? 'visibility_off' : 'visibility' }}</mat-icon>
|
||||
</button>
|
||||
</mat-form-field>
|
||||
<mat-form-field appearance="outline" class="w-full" *ngIf="setupProvider === 'openai'">
|
||||
<mat-label>Base URL (optional)</mat-label>
|
||||
<input matInput placeholder="https://api.deepseek.com/v1" [(ngModel)]="setupBaseUrl" />
|
||||
<mat-hint>For OpenAI-compatible providers like DeepSeek</mat-hint>
|
||||
</mat-form-field>
|
||||
<mat-form-field appearance="outline" class="w-full">
|
||||
<mat-label>Model (optional)</mat-label>
|
||||
<input matInput placeholder="{{ setupProvider === 'gemini' ? 'gemini-2.0-flash-exp' : 'gpt-4o-mini' }}" [(ngModel)]="setupModel" />
|
||||
<mat-hint>Override the default model name</mat-hint>
|
||||
</mat-form-field>
|
||||
<div class="flex justify-end gap-2">
|
||||
<button mat-button (click)="showMissingKeyForm = false; suggestError = null">Cancel</button>
|
||||
<button mat-flat-button color="primary" [disabled]="!setupApiKey.trim() || setupSaving" (click)="saveSetupKey()">
|
||||
<mat-icon>save</mat-icon>
|
||||
{{ setupSaving ? 'Saving...' : 'Save' }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
|
||||
<div *ngIf="session.error$ | async as error" class="bg-red-50 border border-red-200 rounded-lg p-4 flex items-start gap-3">
|
||||
<mat-icon class="text-red-500 mt-0.5">error_outline</mat-icon>
|
||||
<div class="flex-1">
|
||||
@@ -398,6 +445,7 @@ export class LlmWorkspaceComponent implements OnInit, OnDestroy {
|
||||
|
||||
briefDescription = '';
|
||||
sectionSuggestions: SectionSuggestion[] = [];
|
||||
personalizedQuestions: PersonalizedQuestion[] = [];
|
||||
sectionConfig: SectionConfig | null = null;
|
||||
configStepTitle = 'Customize Your Site';
|
||||
configStepSubtitle = '';
|
||||
@@ -422,6 +470,8 @@ export class LlmWorkspaceComponent implements OnInit, OnDestroy {
|
||||
setupSaving = false;
|
||||
setupKeyVisible = false;
|
||||
|
||||
showMissingKeyForm = false;
|
||||
|
||||
private destroy$ = new Subject<void>();
|
||||
|
||||
ngOnInit(): void {
|
||||
@@ -441,6 +491,7 @@ export class LlmWorkspaceComponent implements OnInit, OnDestroy {
|
||||
this.showRefine = false;
|
||||
this.currentPhase = 'idle';
|
||||
this.sectionSuggestions = [];
|
||||
this.personalizedQuestions = [];
|
||||
this.sectionConfig = null;
|
||||
this.suggestError = null;
|
||||
this.session.clearHistory();
|
||||
@@ -519,12 +570,19 @@ export class LlmWorkspaceComponent implements OnInit, OnDestroy {
|
||||
}).pipe(takeUntil(this.destroy$)).subscribe({
|
||||
next: (response) => {
|
||||
this.sectionSuggestions = response.sections;
|
||||
this.personalizedQuestions = response.personalizedQuestions || [];
|
||||
this.suggesting = false;
|
||||
this.currentPhase = 'configuring';
|
||||
},
|
||||
error: (err) => {
|
||||
this.suggesting = false;
|
||||
this.suggestError = err.error?.error || err.statusText || 'Failed to get section suggestions';
|
||||
const errorMsg = err.error?.error || err.statusText || 'Failed to get section suggestions';
|
||||
this.suggestError = errorMsg;
|
||||
const match = errorMsg.match(/No API key configured for (\w+)/);
|
||||
if (match) {
|
||||
this.showMissingKeyForm = true;
|
||||
this.setupProvider = match[1];
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -535,7 +593,13 @@ export class LlmWorkspaceComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
onConfigStepChange(step: string): void {
|
||||
if (step.startsWith('section-')) {
|
||||
if (step === 'questions') {
|
||||
this.configStepTitle = 'Tell Us About Your Content';
|
||||
this.configStepSubtitle = 'Answer a few questions so the AI can generate authentic content.';
|
||||
} else if (step === 'sections') {
|
||||
this.configStepTitle = 'Choose Layout Patterns';
|
||||
this.configStepSubtitle = 'Pick a layout for each section, or describe your own.';
|
||||
} else if (step.startsWith('section-')) {
|
||||
const idx = parseInt(step.split('-')[1], 10);
|
||||
const section = this.sectionSuggestions[idx];
|
||||
this.configStepTitle = section ? `Configure ${section.title}` : 'Configure Sections';
|
||||
@@ -552,6 +616,7 @@ export class LlmWorkspaceComponent implements OnInit, OnDestroy {
|
||||
backToIdle(): void {
|
||||
this.currentPhase = 'idle';
|
||||
this.sectionSuggestions = [];
|
||||
this.personalizedQuestions = [];
|
||||
this.sectionConfig = null;
|
||||
}
|
||||
|
||||
@@ -586,6 +651,15 @@ export class LlmWorkspaceComponent implements OnInit, OnDestroy {
|
||||
lines.push(`Theme direction: ${config.themeVibe}`);
|
||||
}
|
||||
|
||||
const answeredQuestions = config.questionAnswers.filter(qa => qa.answer.trim());
|
||||
if (answeredQuestions.length > 0) {
|
||||
lines.push('');
|
||||
lines.push('Site content details:');
|
||||
for (const qa of answeredQuestions) {
|
||||
lines.push(`- ${qa.question}: ${qa.answer.trim()}`);
|
||||
}
|
||||
}
|
||||
|
||||
lines.push('');
|
||||
lines.push('Pages:');
|
||||
|
||||
@@ -711,6 +785,7 @@ export class LlmWorkspaceComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
goToSettings(): void {
|
||||
if (this.configuredProviders.length === 0) return;
|
||||
if (this.siteId) this.router.navigate(['/llm', this.siteId, 'settings']);
|
||||
}
|
||||
|
||||
@@ -741,6 +816,8 @@ export class LlmWorkspaceComponent implements OnInit, OnDestroy {
|
||||
this.setupApiKey = '';
|
||||
this.setupBaseUrl = '';
|
||||
this.setupModel = '';
|
||||
this.showMissingKeyForm = false;
|
||||
this.suggestError = null;
|
||||
this.snackBar.open(`${this.setupProvider} API key saved`, 'Close', { duration: 2000 });
|
||||
this.loadLlmConfig();
|
||||
},
|
||||
|
||||
@@ -6,12 +6,23 @@ import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatSelectModule } from '@angular/material/select';
|
||||
import { SectionSuggestion, SelectedSection, PatternSuggestion } from '../../core/models/llm';
|
||||
import { SectionSuggestion, PatternSuggestion, PersonalizedQuestion, QuestionAnswer } from '../../core/models/llm';
|
||||
|
||||
export interface SelectedSection {
|
||||
title: string;
|
||||
description: string;
|
||||
slug: string;
|
||||
selected: boolean;
|
||||
customNotes: string;
|
||||
selectedPattern: string | null;
|
||||
customPatternDesc: string;
|
||||
}
|
||||
|
||||
export interface SectionConfig {
|
||||
sections: SelectedSection[];
|
||||
themeVibe: string;
|
||||
additionalRequirements: string;
|
||||
questionAnswers: QuestionAnswer[];
|
||||
}
|
||||
|
||||
const THEME_VIBES = [
|
||||
@@ -47,13 +58,47 @@ const THEME_VIBES = [
|
||||
`],
|
||||
template: `
|
||||
<div class="flex items-center mb-6">
|
||||
<div class="crumb" [class.active]="phase === 'sections'" [class.completed]="phase !== 'sections'">Sections</div>
|
||||
<div class="crumb-line" [class.completed]="phase !== 'sections'"></div>
|
||||
<div class="crumb" [class.active]="phase === 'questions'" [class.completed]="phase !== 'questions'">Content</div>
|
||||
<div class="crumb-line" [class.completed]="phase !== 'questions'"></div>
|
||||
<div class="crumb" [class.active]="phase === 'sections'" [class.completed]="phase === 'theme' || phase === 'details'">Layout</div>
|
||||
<div class="crumb-line" [class.completed]="phase === 'theme' || phase === 'details'"></div>
|
||||
<div class="crumb" [class.active]="phase === 'theme'" [class.completed]="phase === 'details'">Theme</div>
|
||||
<div class="crumb-line" [class.completed]="phase === 'details'"></div>
|
||||
<div class="crumb" [class.active]="phase === 'details'">Details</div>
|
||||
</div>
|
||||
|
||||
<div *ngIf="phase === 'questions'" class="space-y-5">
|
||||
<div>
|
||||
<h4 class="text-base font-semibold text-gray-900 mb-1">Tell us about your content</h4>
|
||||
<p class="text-sm text-gray-500 mb-4">Answer a few questions so the AI can generate authentic content for your site.</p>
|
||||
</div>
|
||||
|
||||
<div *ngFor="let q of personalizedQuestions; let qi = index" class="space-y-1.5">
|
||||
<label class="text-sm font-medium text-gray-700">{{ q.question }}</label>
|
||||
<mat-form-field appearance="outline" class="w-full" *ngIf="q.type === 'textarea'">
|
||||
<textarea
|
||||
matInput
|
||||
rows="3"
|
||||
[placeholder]="'Enter your ' + q.id.replace('-', ' ')"
|
||||
[(ngModel)]="questionAnswers[qi].answer"
|
||||
></textarea>
|
||||
</mat-form-field>
|
||||
<mat-form-field appearance="outline" class="w-full" *ngIf="q.type === 'select'">
|
||||
<mat-select [(ngModel)]="questionAnswers[qi].answer">
|
||||
<mat-option value="">Select...</mat-option>
|
||||
<mat-option *ngFor="let opt of q.options" [value]="opt">{{ opt }}</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<mat-form-field appearance="outline" class="w-full" *ngIf="q.type === 'text' || (!q.type || q.type === '')">
|
||||
<input
|
||||
matInput
|
||||
[placeholder]="'Enter your ' + q.id.replace('-', ' ')"
|
||||
[(ngModel)]="questionAnswers[qi].answer"
|
||||
/>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div *ngIf="phase === 'sections' && currentSection" class="space-y-4">
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
@@ -189,7 +234,7 @@ const THEME_VIBES = [
|
||||
<button
|
||||
mat-stroked-button
|
||||
(click)="prev()"
|
||||
[disabled]="phase === 'sections' && sectionIndex === 0"
|
||||
[disabled]="phase === 'questions'"
|
||||
>
|
||||
<mat-icon>arrow_back</mat-icon>
|
||||
Back
|
||||
@@ -213,12 +258,14 @@ const THEME_VIBES = [
|
||||
})
|
||||
export class SectionConfiguratorComponent implements OnInit {
|
||||
@Input() suggestions: SectionSuggestion[] = [];
|
||||
@Input() personalizedQuestions: PersonalizedQuestion[] = [];
|
||||
@Output() configComplete = new EventEmitter<SectionConfig>();
|
||||
@Output() stepChange = new EventEmitter<string>();
|
||||
|
||||
phase: 'sections' | 'theme' | 'details' = 'sections';
|
||||
phase: 'questions' | 'sections' | 'theme' | 'details' = 'questions';
|
||||
sectionIndex = 0;
|
||||
sections: SelectedSection[] = [];
|
||||
questionAnswers: QuestionAnswer[] = [];
|
||||
|
||||
themeVibes = THEME_VIBES;
|
||||
selectedVibe = 'Any';
|
||||
@@ -235,6 +282,14 @@ export class SectionConfiguratorComponent implements OnInit {
|
||||
selectedPattern: s.patterns?.length ? s.patterns[0].title : null,
|
||||
customPatternDesc: '',
|
||||
}));
|
||||
this.questionAnswers = this.personalizedQuestions.map(q => ({
|
||||
id: q.id,
|
||||
question: q.question,
|
||||
answer: '',
|
||||
}));
|
||||
if (this.personalizedQuestions.length === 0) {
|
||||
this.phase = 'sections';
|
||||
}
|
||||
}
|
||||
|
||||
get currentSection(): SelectedSection | null {
|
||||
@@ -260,6 +315,9 @@ export class SectionConfiguratorComponent implements OnInit {
|
||||
}
|
||||
|
||||
get navLabel(): string {
|
||||
if (this.phase === 'questions') {
|
||||
return `${this.personalizedQuestions.length} question${this.personalizedQuestions.length !== 1 ? 's' : ''}`;
|
||||
}
|
||||
if (this.phase === 'sections') {
|
||||
return `Section ${this.sectionIndex + 1} of ${this.sections.length}`;
|
||||
}
|
||||
@@ -284,10 +342,14 @@ export class SectionConfiguratorComponent implements OnInit {
|
||||
}
|
||||
|
||||
prev(): void {
|
||||
if (this.phase === 'sections') {
|
||||
if (this.phase === 'questions') {
|
||||
} else if (this.phase === 'sections') {
|
||||
if (this.sectionIndex > 0) {
|
||||
this.sectionIndex--;
|
||||
this.stepChange.emit(`section-${this.sectionIndex}`);
|
||||
} else {
|
||||
this.phase = 'questions';
|
||||
this.stepChange.emit('questions');
|
||||
}
|
||||
} else if (this.phase === 'theme') {
|
||||
this.phase = 'sections';
|
||||
@@ -300,7 +362,11 @@ export class SectionConfiguratorComponent implements OnInit {
|
||||
}
|
||||
|
||||
next(): void {
|
||||
if (this.phase === 'sections') {
|
||||
if (this.phase === 'questions') {
|
||||
this.phase = 'sections';
|
||||
this.sectionIndex = 0;
|
||||
this.stepChange.emit('sections');
|
||||
} else if (this.phase === 'sections') {
|
||||
if (this.sectionIndex < this.sections.length - 1) {
|
||||
this.sectionIndex++;
|
||||
this.stepChange.emit(`section-${this.sectionIndex}`);
|
||||
@@ -319,6 +385,7 @@ export class SectionConfiguratorComponent implements OnInit {
|
||||
sections: this.sections,
|
||||
themeVibe: vibe,
|
||||
additionalRequirements: this.additionalRequirements,
|
||||
questionAnswers: this.questionAnswers,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user