Mise en ligne de la version 0.2.0
All checks were successful
Build & Push Images / build (brain) (push) Successful in 46s
Build & Push Images / build (core) (push) Successful in 1m21s
Build & Push Images / build (web) (push) Successful in 1m25s

This commit is contained in:
2026-04-21 14:25:17 +02:00
parent ebee8e106b
commit ba8a503b3e
300 changed files with 35329 additions and 1 deletions

View File

@@ -0,0 +1,38 @@
<div class="chapter-create-page">
<div class="page-header">
<h1>Créer un nouveau chapitre</h1>
<p class="arc-ref" *ngIf="arcName">Arc : {{ arcName }}</p>
</div>
<form [formGroup]="form" (ngSubmit)="submit()" class="chapter-form">
<div class="field">
<label>Nom du chapitre *</label>
<input
type="text"
formControlName="name"
placeholder="Ex: Chapitre 1: Les Disparitions"
[class.invalid]="form.get('name')?.invalid && form.get('name')?.touched"
/>
</div>
<div class="field">
<label>Description</label>
<textarea
formControlName="description"
placeholder="Décrivez ce chapitre..."
rows="5">
</textarea>
</div>
<div class="form-actions">
<button type="submit" class="btn-primary" [disabled]="form.invalid">
Créer le chapitre
</button>
<button type="button" class="btn-secondary" (click)="cancel()">Annuler</button>
</div>
</form>
</div>

View File

@@ -0,0 +1,21 @@
.chapter-create-page {
padding: 2.5rem 2rem;
max-width: 640px;
}
// Overrides locaux :
// - titre en violet (au lieu de blanc comme le .page-header global)
// - sous-titre .arc-ref spécifique à cet écran (référence à l'arc parent)
.page-header {
h1 { color: #a5b4fc; }
.arc-ref { color: #6b7280; font-size: 0.85rem; margin: 0; }
}
.chapter-form {
display: flex;
flex-direction: column;
gap: 1.5rem;
}
// Le bouton "Créer" prend toute la largeur restante.
.btn-primary { flex: 1; }

View File

@@ -0,0 +1,97 @@
import { Component, OnInit, OnDestroy } from '@angular/core';
import { CommonModule } from '@angular/common';
import { ReactiveFormsModule, FormBuilder, FormGroup, Validators } from '@angular/forms';
import { ActivatedRoute, Router } from '@angular/router';
import { forkJoin } from 'rxjs';
import { LucideAngularModule } from 'lucide-angular';
import { CampaignService } from '../../services/campaign.service';
import { LayoutService, GlobalItem } from '../../services/layout.service';
import { Campaign } from '../../services/campaign.model';
import { loadCampaignTreeData, buildCampaignTree } from '../campaign-tree.helper';
/**
* Écran de création d'un nouveau chapitre rattaché à un arc.
* Route : /campaigns/:campaignId/arcs/:arcId/chapters/create
*/
@Component({
selector: 'app-chapter-create',
standalone: true,
imports: [CommonModule, ReactiveFormsModule, LucideAngularModule],
templateUrl: './chapter-create.component.html',
styleUrls: ['./chapter-create.component.scss']
})
export class ChapterCreateComponent implements OnInit, OnDestroy {
form: FormGroup;
campaignId = '';
arcId = '';
arcName = '';
private existingChapterCount = 0;
constructor(
private fb: FormBuilder,
private route: ActivatedRoute,
private router: Router,
private campaignService: CampaignService,
private layoutService: LayoutService
) {
this.form = this.fb.group({
name: ['', Validators.required],
description: ['']
});
}
ngOnInit(): void {
this.campaignId = this.route.snapshot.paramMap.get('campaignId')!;
this.arcId = this.route.snapshot.paramMap.get('arcId')!;
this.loadLayout();
}
private loadLayout(): void {
forkJoin({
campaign: this.campaignService.getCampaignById(this.campaignId),
allCampaigns: this.campaignService.getAllCampaigns(),
treeData: loadCampaignTreeData(this.campaignService, this.campaignId)
}).subscribe(({ campaign, allCampaigns, treeData }) => {
const currentArc = treeData.arcs.find(a => a.id === this.arcId);
this.arcName = currentArc?.name ?? '';
this.existingChapterCount = treeData.chaptersByArc[this.arcId]?.length ?? 0;
const globalItems: GlobalItem[] = allCampaigns.map((c: Campaign) => ({
id: c.id!, name: c.name, route: `/campaigns/${c.id}`
}));
this.layoutService.show({
title: campaign.name,
items: buildCampaignTree(this.campaignId, treeData),
footerLabel: 'Toutes les campagnes',
createActions: [
{ id: 'create-arc', label: '+ Nouvel arc', variant: 'primary', route: `/campaigns/${this.campaignId}/arcs/create` }
],
globalItems,
globalBackLabel: 'Toutes les campagnes',
globalBackRoute: '/campaigns'
});
});
}
submit(): void {
if (this.form.invalid) return;
this.campaignService.createChapter({
name: this.form.value.name,
description: this.form.value.description,
arcId: this.arcId,
order: this.existingChapterCount + 1
}).subscribe({
next: (created) => this.router.navigate(['/campaigns', this.campaignId, 'arcs', this.arcId, 'chapters', created.id]),
error: () => console.error('Erreur lors de la création du chapitre')
});
}
cancel(): void {
this.router.navigate(['/campaigns', this.campaignId]);
}
ngOnDestroy(): void {
this.layoutService.hide();
}
}