Update with new components
This commit is contained in:
@ -24,6 +24,16 @@
|
||||
<label for="subTitle" class="form-label text-primary">Subtitle</label>
|
||||
<input id="subTitle" formControlName="subTitle" class="form-control" />
|
||||
</div>
|
||||
<div class="form-group mb-3">
|
||||
<label for="description" class="form-label text-primary">Description</label>
|
||||
<textarea id="description" formControlName="description" class="form-control" rows="3"
|
||||
placeholder="Brief description for the event card"></textarea>
|
||||
</div>
|
||||
<div class="form-group mb-3">
|
||||
<label for="detail" class="form-label text-primary">Detail</label>
|
||||
<textarea id="detail" formControlName="detail" class="form-control" rows="3"
|
||||
placeholder="Detailed information about the event"></textarea>
|
||||
</div>
|
||||
<div class="form-group mb-3">
|
||||
<label for="date" class="form-label text-primary">Date</label>
|
||||
<input id="date" formControlName="date" class="form-control" />
|
||||
@ -43,6 +53,119 @@
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<!-- Main Image Section -->
|
||||
<div class="form-group mb-3">
|
||||
<label class="form-label text-primary">Main Image</label>
|
||||
|
||||
<!-- Image Upload Section -->
|
||||
<div class="card mb-2">
|
||||
<div class="card-body">
|
||||
<h6 class="card-title">Upload Image File</h6>
|
||||
<div class="row">
|
||||
<div class="col-8">
|
||||
<input type="file"
|
||||
class="form-control"
|
||||
accept="image/*"
|
||||
(change)="onMainImageFileSelected($event)"
|
||||
#mainImageFile>
|
||||
</div>
|
||||
<div class="col-4">
|
||||
<button type="button"
|
||||
class="btn btn-primary btn-sm w-100"
|
||||
(click)="uploadMainImage()"
|
||||
[disabled]="!selectedMainImageFile || mainImageUploading">
|
||||
<span *ngIf="mainImageUploading" class="spinner-border spinner-border-sm me-1"></span>
|
||||
{{ mainImageUploading ? 'Uploading...' : 'Upload' }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- URL Input Section -->
|
||||
<div class="card mb-2">
|
||||
<div class="card-body">
|
||||
<h6 class="card-title">Or Enter Image URL</h6>
|
||||
<input id="mainImage"
|
||||
formControlName="mainImage"
|
||||
class="form-control"
|
||||
placeholder="https://images.unsplash.com/..." />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Image Preview -->
|
||||
<div *ngIf="eventForm.get('mainImage')?.value" class="mt-2">
|
||||
<img [src]="eventForm.get('mainImage')?.value"
|
||||
alt="Main Image Preview"
|
||||
class="img-thumbnail"
|
||||
style="max-width: 200px; max-height: 150px;">
|
||||
</div>
|
||||
|
||||
<small class="form-text text-muted">This will be the primary image displayed for the event</small>
|
||||
</div>
|
||||
|
||||
<!-- Gallery Images Section -->
|
||||
<div class="form-group mb-3">
|
||||
<label class="form-label text-primary">Gallery Images</label>
|
||||
|
||||
<!-- Gallery Upload Section -->
|
||||
<div class="card mb-2">
|
||||
<div class="card-body">
|
||||
<h6 class="card-title">Upload Gallery Images</h6>
|
||||
<div class="row">
|
||||
<div class="col-8">
|
||||
<input type="file"
|
||||
class="form-control"
|
||||
accept="image/*"
|
||||
multiple
|
||||
(change)="onGalleryImagesSelected($event)"
|
||||
#galleryImageFiles>
|
||||
</div>
|
||||
<div class="col-4">
|
||||
<button type="button"
|
||||
class="btn btn-primary btn-sm w-100"
|
||||
(click)="uploadGalleryImages()"
|
||||
[disabled]="!selectedGalleryImageFiles?.length || galleryImagesUploading">
|
||||
<span *ngIf="galleryImagesUploading" class="spinner-border spinner-border-sm me-1"></span>
|
||||
{{ galleryImagesUploading ? 'Uploading...' : 'Upload' }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Manual Gallery URL Entry -->
|
||||
<div class="card mb-2">
|
||||
<div class="card-body">
|
||||
<h6 class="card-title">Or Add Gallery URLs</h6>
|
||||
<div formArrayName="galleryImages">
|
||||
<div *ngFor="let image of galleryImages.controls; let i = index" class="row mb-2">
|
||||
<div class="col-8">
|
||||
<input [formControlName]="i" class="form-control" placeholder="https://images.unsplash.com/..." />
|
||||
</div>
|
||||
<div class="col-4">
|
||||
<button type="button" class="btn btn-danger btn-sm w-100" (click)="removeGalleryImage(i)">
|
||||
Remove
|
||||
</button>
|
||||
</div>
|
||||
<!-- Image Preview -->
|
||||
<div class="col-12" *ngIf="galleryImages.at(i).value">
|
||||
<img [src]="galleryImages.at(i).value"
|
||||
alt="Gallery Preview"
|
||||
class="img-thumbnail mt-2"
|
||||
style="max-width: 100px; max-height: 80px;">
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" class="btn btn-outline-primary btn-sm" (click)="addGalleryImage()">
|
||||
Add Gallery URL
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<small class="form-text text-muted">Add up to 4 gallery images for the event grid</small>
|
||||
</div>
|
||||
|
||||
<div class="form-group mb-3">
|
||||
<label class="form-label text-primary">Venues</label>
|
||||
<div formArrayName="venues">
|
||||
@ -69,7 +192,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" class="btn btn-danger btn-sm float-end" (click)="removeVenue(i)">
|
||||
<!-- <i class="bi bi-trash"></i> -->X
|
||||
X
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@ -86,7 +209,7 @@
|
||||
<div class="card-body">
|
||||
<input [formControlName]="i" class="form-control" placeholder="Highlight" />
|
||||
<button type="button" class="btn btn-danger btn-sm float-end mt-2" (click)="removeHighlight(i)">
|
||||
<!-- <i class="bi bi-trash"></i> -->X
|
||||
X
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@ -103,7 +226,7 @@
|
||||
<div class="card-body">
|
||||
<input [formControlName]="i" class="form-control" placeholder="Organiser" />
|
||||
<button type="button" class="btn btn-danger btn-sm float-end mt-2" (click)="removeOrganiser(i)">
|
||||
<!-- <i class="bi bi-trash"></i> -->X
|
||||
X
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@ -121,7 +244,7 @@
|
||||
<div [formGroupName]="i">
|
||||
<div class="row mb-2">
|
||||
<div class="col-8">
|
||||
<input formControlName="desc" placeholder="Description" class="form-control" />
|
||||
<input formControlName="description" placeholder="Description" class="form-control" />
|
||||
</div>
|
||||
<div class="col-4">
|
||||
<input formControlName="cost" placeholder="Cost" type="number" class="form-control" />
|
||||
@ -129,7 +252,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" class="btn btn-danger btn-sm float-end mt-2" (click)="removeFee(i)">
|
||||
<!-- <i class="bi bi-trash"></i> -->X
|
||||
X
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@ -142,4 +265,4 @@
|
||||
</div>
|
||||
<button type="submit" class="btn btn-success">Submit</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@ -1,4 +1,3 @@
|
||||
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { FormBuilder, FormGroup, FormArray, Validators } from '@angular/forms';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
@ -11,125 +10,334 @@ import { EventService } from 'src/app/service/event.service';
|
||||
})
|
||||
export class EventFormComponent implements OnInit {
|
||||
|
||||
eventForm: FormGroup;
|
||||
eventId: number | null;
|
||||
|
||||
// File upload properties
|
||||
selectedMainImageFile: File | null = null;
|
||||
selectedGalleryImageFiles: File[] = [];
|
||||
mainImageUploading = false;
|
||||
galleryImagesUploading = false;
|
||||
|
||||
|
||||
eventForm: FormGroup;
|
||||
|
||||
constructor(
|
||||
private fb: FormBuilder,
|
||||
private eventService: EventService,
|
||||
private route: ActivatedRoute,
|
||||
private router: Router
|
||||
|
||||
) {}
|
||||
eventId: number | null;
|
||||
|
||||
ngOnInit() {
|
||||
this.eventForm = this.fb.group({
|
||||
code: ['', Validators.required],
|
||||
year: ['', Validators.required],
|
||||
subject: ['', Validators.required],
|
||||
title: ['', Validators.required],
|
||||
subTitle: [''],
|
||||
date: ['', Validators.required],
|
||||
venues: this.fb.array([]),
|
||||
highlights: this.fb.array([]),
|
||||
organisers: this.fb.array([]),
|
||||
fees: this.fb.array([]),
|
||||
phone: ['', Validators.required],
|
||||
email: ['', [Validators.required, Validators.email]],
|
||||
isActive: [true]
|
||||
});
|
||||
|
||||
this.route.paramMap.subscribe(params => {
|
||||
const idParam = params.get('id');
|
||||
this.eventId = idParam ? +idParam : null;
|
||||
|
||||
if (this.eventId !== null) {
|
||||
this.loadEvent(this.eventId);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
loadEvent(id: number): void {
|
||||
this.eventService.getEvent(id).subscribe(event => {
|
||||
this.eventForm.patchValue(event);
|
||||
this.setArrayValues('venues', event.venues);
|
||||
this.setArrayValues('highlights', event.highlights);
|
||||
this.setArrayValues('organisers', event.organisers);
|
||||
this.setArrayValues('fees', event.fees);
|
||||
});
|
||||
}
|
||||
|
||||
setArrayValues(controlName: string, values: any[]): void {
|
||||
const array = this.eventForm.get(controlName) as FormArray;
|
||||
values.forEach(value => array.push(this.fb.group(value)));
|
||||
}
|
||||
|
||||
get venues(): FormArray {
|
||||
return this.eventForm.get('venues') as FormArray;
|
||||
}
|
||||
|
||||
get highlights(): FormArray {
|
||||
return this.eventForm.get('highlights') as FormArray;
|
||||
}
|
||||
|
||||
get organisers(): FormArray {
|
||||
return this.eventForm.get('organisers') as FormArray;
|
||||
}
|
||||
|
||||
get fees(): FormArray {
|
||||
return this.eventForm.get('fees') as FormArray;
|
||||
}
|
||||
|
||||
addVenue() {
|
||||
this.venues.push(this.fb.group({
|
||||
title: [''],
|
||||
date: [''],
|
||||
address: [''],
|
||||
info: ['']
|
||||
}));
|
||||
}
|
||||
|
||||
removeVenue(index: number) {
|
||||
this.venues.removeAt(index);
|
||||
}
|
||||
|
||||
addHighlight() {
|
||||
this.highlights.push(this.fb.control(''));
|
||||
}
|
||||
|
||||
removeHighlight(index: number) {
|
||||
this.highlights.removeAt(index);
|
||||
}
|
||||
|
||||
addOrganiser() {
|
||||
this.organisers.push(this.fb.control(''));
|
||||
}
|
||||
|
||||
removeOrganiser(index: number) {
|
||||
this.organisers.removeAt(index);
|
||||
}
|
||||
|
||||
addFee() {
|
||||
this.fees.push(this.fb.group({
|
||||
desc: [''],
|
||||
cost: ['']
|
||||
}));
|
||||
}
|
||||
|
||||
removeFee(index: number) {
|
||||
this.fees.removeAt(index);
|
||||
}
|
||||
|
||||
onSubmit(): void {
|
||||
if (this.eventForm.valid) {
|
||||
if (this.eventId) {
|
||||
this.eventService.updateEvent(this.eventId, this.eventForm.value).subscribe(() => this.router.navigate(['/events']));
|
||||
} else {
|
||||
this.eventService.createEvent(this.eventForm.value).subscribe(() => this.router.navigate(['/events']));
|
||||
}
|
||||
constructor(
|
||||
private fb: FormBuilder,
|
||||
private eventService: EventService,
|
||||
private route: ActivatedRoute,
|
||||
private router: Router
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.eventForm = this.fb.group({
|
||||
code: ['', Validators.required],
|
||||
year: ['', Validators.required],
|
||||
subject: ['', Validators.required],
|
||||
title: ['', Validators.required],
|
||||
subTitle: [''],
|
||||
description: ['', Validators.required],
|
||||
detail: ['', Validators.required],
|
||||
date: ['', Validators.required],
|
||||
mainImage: [''],
|
||||
galleryImages: this.fb.array([]),
|
||||
venues: this.fb.array([]), // Form uses 'venues' (plural)
|
||||
highlights: this.fb.array([]),
|
||||
organisers: this.fb.array([]),
|
||||
fees: this.fb.array([]), // Form uses 'fees' (plural)
|
||||
phone: ['', Validators.required],
|
||||
email: ['', [Validators.required, Validators.email]],
|
||||
isActive: [true]
|
||||
});
|
||||
|
||||
this.route.paramMap.subscribe(params => {
|
||||
const idParam = params.get('id');
|
||||
this.eventId = idParam ? +idParam : null;
|
||||
|
||||
if (this.eventId !== null) {
|
||||
this.loadEvent(this.eventId);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// File selection methods
|
||||
onMainImageFileSelected(event: any): void {
|
||||
const file = event.target.files[0];
|
||||
if (file) {
|
||||
this.selectedMainImageFile = file;
|
||||
console.log('Main image file selected:', file.name);
|
||||
}
|
||||
}
|
||||
|
||||
onGalleryImagesSelected(event: any): void {
|
||||
const files = Array.from(event.target.files) as File[];
|
||||
if (files.length > 0) {
|
||||
this.selectedGalleryImageFiles = files;
|
||||
console.log('Gallery image files selected:', files.map(f => f.name));
|
||||
}
|
||||
}
|
||||
|
||||
// Upload methods
|
||||
uploadMainImage(): void {
|
||||
if (!this.selectedMainImageFile) return;
|
||||
|
||||
this.mainImageUploading = true;
|
||||
this.eventService.uploadImage(this.selectedMainImageFile).subscribe({
|
||||
next: (response) => {
|
||||
console.log('Main image uploaded:', response);
|
||||
this.eventForm.patchValue({ mainImage: response.url });
|
||||
this.selectedMainImageFile = null;
|
||||
this.mainImageUploading = false;
|
||||
|
||||
// Clear the file input
|
||||
const fileInput = document.querySelector('input[type="file"]') as HTMLInputElement;
|
||||
if (fileInput) fileInput.value = '';
|
||||
},
|
||||
error: (error) => {
|
||||
console.error('Error uploading main image:', error);
|
||||
this.mainImageUploading = false;
|
||||
alert('Error uploading image. Please try again.');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
uploadGalleryImages(): void {
|
||||
if (!this.selectedGalleryImageFiles || this.selectedGalleryImageFiles.length === 0) return;
|
||||
|
||||
this.galleryImagesUploading = true;
|
||||
this.eventService.uploadMultipleImages(this.selectedGalleryImageFiles).subscribe({
|
||||
next: (responses) => {
|
||||
console.log('Gallery images uploaded:', responses);
|
||||
|
||||
// Add uploaded image URLs to the form array
|
||||
const galleryArray = this.galleryImages;
|
||||
responses.forEach((response: any) => {
|
||||
if (response && response.url) {
|
||||
galleryArray.push(this.fb.control(response.url));
|
||||
}
|
||||
});
|
||||
|
||||
this.selectedGalleryImageFiles = [];
|
||||
this.galleryImagesUploading = false;
|
||||
|
||||
// Clear the file input
|
||||
const fileInputs = document.querySelectorAll('input[type="file"]');
|
||||
fileInputs.forEach((input: any) => {
|
||||
if (input.multiple) input.value = '';
|
||||
});
|
||||
},
|
||||
error: (error) => {
|
||||
console.error('Error uploading gallery images:', error);
|
||||
this.galleryImagesUploading = false;
|
||||
alert('Error uploading gallery images. Please try again.');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
loadEvent(id: number): void {
|
||||
this.eventService.getEvent(id).subscribe(event => {
|
||||
if (event) {
|
||||
this.eventForm.patchValue({
|
||||
code: event.code,
|
||||
year: event.year,
|
||||
subject: event.subject,
|
||||
title: event.title,
|
||||
subTitle: event.subTitle,
|
||||
description: event.description,
|
||||
detail: event.detail,
|
||||
date: event.date,
|
||||
mainImage: event.mainImage,
|
||||
phone: event.phone,
|
||||
email: event.email,
|
||||
isActive: event.isActive
|
||||
});
|
||||
|
||||
// Map backend 'venue' to form 'venues'
|
||||
this.setArrayValues('venues', event.venue || []);
|
||||
|
||||
// Map backend 'fee' to form 'fees'
|
||||
this.setArrayValues('fees', event.fee || []);
|
||||
|
||||
this.setArrayValues('highlights', event.highlights || []);
|
||||
this.setArrayValues('organisers', event.organisers || []);
|
||||
this.setStringArrayValues('galleryImages', event.galleryImages || []);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
setArrayValues(controlName: string, values: any[]): void {
|
||||
const array = this.eventForm.get(controlName) as FormArray;
|
||||
array.clear();
|
||||
|
||||
if (values && values.length > 0) {
|
||||
values.forEach(value => {
|
||||
if (controlName === 'venues') {
|
||||
array.push(this.fb.group({
|
||||
title: [value.title || ''],
|
||||
date: [value.date || ''],
|
||||
address: [value.address || ''],
|
||||
info: [value.info || '']
|
||||
}));
|
||||
} else if (controlName === 'fees') {
|
||||
array.push(this.fb.group({
|
||||
description: [value.description || ''], // Changed from 'desc' to 'description'
|
||||
cost: [value.cost || '']
|
||||
}));
|
||||
} else {
|
||||
array.push(this.fb.control(value));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
setStringArrayValues(controlName: string, values: string[]): void {
|
||||
const array = this.eventForm.get(controlName) as FormArray;
|
||||
array.clear();
|
||||
if (values && values.length > 0) {
|
||||
values.forEach(value => array.push(this.fb.control(value)));
|
||||
}
|
||||
}
|
||||
|
||||
get venues(): FormArray {
|
||||
return this.eventForm.get('venues') as FormArray;
|
||||
}
|
||||
|
||||
get highlights(): FormArray {
|
||||
return this.eventForm.get('highlights') as FormArray;
|
||||
}
|
||||
|
||||
get organisers(): FormArray {
|
||||
return this.eventForm.get('organisers') as FormArray;
|
||||
}
|
||||
|
||||
get fees(): FormArray {
|
||||
return this.eventForm.get('fees') as FormArray;
|
||||
}
|
||||
|
||||
get galleryImages(): FormArray {
|
||||
return this.eventForm.get('galleryImages') as FormArray;
|
||||
}
|
||||
|
||||
addGalleryImage() {
|
||||
this.galleryImages.push(this.fb.control(''));
|
||||
}
|
||||
|
||||
removeGalleryImage(index: number) {
|
||||
this.galleryImages.removeAt(index);
|
||||
}
|
||||
|
||||
addVenue() {
|
||||
this.venues.push(this.fb.group({
|
||||
title: [''],
|
||||
date: [''],
|
||||
address: [''],
|
||||
info: ['']
|
||||
}));
|
||||
}
|
||||
|
||||
removeVenue(index: number) {
|
||||
this.venues.removeAt(index);
|
||||
}
|
||||
|
||||
addHighlight() {
|
||||
this.highlights.push(this.fb.control(''));
|
||||
}
|
||||
|
||||
removeHighlight(index: number) {
|
||||
this.highlights.removeAt(index);
|
||||
}
|
||||
|
||||
addOrganiser() {
|
||||
this.organisers.push(this.fb.control(''));
|
||||
}
|
||||
|
||||
removeOrganiser(index: number) {
|
||||
this.organisers.removeAt(index);
|
||||
}
|
||||
|
||||
addFee() {
|
||||
this.fees.push(this.fb.group({
|
||||
description: [''], // Changed from 'desc' to 'description'
|
||||
cost: ['']
|
||||
}));
|
||||
}
|
||||
|
||||
removeFee(index: number) {
|
||||
this.fees.removeAt(index);
|
||||
}
|
||||
|
||||
onSubmit(): void {
|
||||
if (this.eventForm.valid) {
|
||||
const formValue = this.eventForm.value;
|
||||
|
||||
// Transform form data to match backend structure
|
||||
const eventData = {
|
||||
...formValue,
|
||||
venue: formValue.venues, // Map 'venues' to 'venue' for backend
|
||||
fee: formValue.fees, // Map 'fees' to 'fee' for backend
|
||||
galleryImages: formValue.galleryImages?.filter((img: string) => img?.trim() !== '') || [],
|
||||
isDeleted: false // Add default value for isDeleted
|
||||
};
|
||||
|
||||
// Remove the plural properties that don't exist in backend
|
||||
delete eventData.venues;
|
||||
delete eventData.fees;
|
||||
|
||||
console.log('Submitting event data:', eventData);
|
||||
|
||||
if (this.eventId) {
|
||||
this.eventService.updateEvent(this.eventId, eventData).subscribe({
|
||||
next: (response) => {
|
||||
console.log('Event updated successfully:', response);
|
||||
this.router.navigate(['/events']);
|
||||
},
|
||||
error: (error) => {
|
||||
console.error('Error updating event:', error);
|
||||
alert('Error updating event. Please check the console for details.');
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.eventService.createEvent(eventData).subscribe({
|
||||
next: (response) => {
|
||||
console.log('Event created successfully:', response);
|
||||
this.router.navigate(['/events']);
|
||||
},
|
||||
error: (error) => {
|
||||
console.error('Error creating event:', error);
|
||||
alert('Error creating event. Please check the console for details.');
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
console.log('Form is invalid');
|
||||
console.log('Form errors:', this.getFormValidationErrors());
|
||||
|
||||
// Mark all fields as touched to show validation errors
|
||||
Object.keys(this.eventForm.controls).forEach(key => {
|
||||
const control = this.eventForm.get(key);
|
||||
if (control) {
|
||||
control.markAsTouched();
|
||||
if (control instanceof FormArray) {
|
||||
control.controls.forEach(arrayControl => {
|
||||
arrayControl.markAsTouched();
|
||||
if (arrayControl instanceof FormGroup) {
|
||||
Object.keys(arrayControl.controls).forEach(innerKey => {
|
||||
arrayControl.get(innerKey)?.markAsTouched();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Helper method to debug form validation errors
|
||||
getFormValidationErrors() {
|
||||
const formErrors: any = {};
|
||||
Object.keys(this.eventForm.controls).forEach(key => {
|
||||
const controlErrors = this.eventForm.get(key)?.errors;
|
||||
if (controlErrors) {
|
||||
formErrors[key] = controlErrors;
|
||||
}
|
||||
});
|
||||
return formErrors;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user