Feature: Create Event - First Step Frontend #17

Merged
igorpropisnov merged 20 commits from feature/create-event into main 2024-08-22 14:58:36 +02:00
9 changed files with 244 additions and 17 deletions
Showing only changes of commit 56c0b51538 - Show all commits

View File

@ -20,11 +20,12 @@
<div class="flex-grow overflow-y-auto px-4 sm:px-8 py-8">
<div class="w-full max-w-4xl mx-auto">
<div class="">
@if (currentStep() === 0) {
<app-basic-step></app-basic-step>
}
</div>
@if (currentStep() === 0) {
<app-basic-step></app-basic-step>
}
@if (currentStep() === 1) {
<app-tickets-step></app-tickets-step>
}
</div>
</div>

View File

@ -8,12 +8,13 @@ import {
} from '@angular/core';
import { BasicStepComponent } from './steps/basic-step.component';
import { TicketsStepComponent } from './steps/tickets-step.component';
@Component({
selector: 'app-create-event',
standalone: true,
providers: [],
imports: [BasicStepComponent, CommonModule],
imports: [CommonModule, BasicStepComponent, TicketsStepComponent],
templateUrl: './create-event.component.html',
changeDetection: ChangeDetectionStrategy.OnPush,
})

View File

@ -0,0 +1,107 @@
<dialog id="location_modal" class="modal">
<div class="modal-box">
<h3 class="text-lg font-bold mb-4">Create New Location</h3>
<form [formGroup]="locationForm">
<label class="form-control w-full">
<div class="label">
<span class="label-text">Location Name</span>
<span class="label-text-alt">Name of the location</span>
</div>
<div class="input input-bordered flex items-center gap-2">
<input
formControlName="name"
type="text"
class="grow"
placeholder="" />
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16"
fill="currentColor"
class="h-4 w-4 opacity-70">
<path
fill-rule="evenodd"
d="M9.965 11.026a5 5 0 1 1 1.06-1.06l2.755 2.754a.75.75 0 1 1-1.06 1.06l-2.755-2.754ZM10.5 7a3.5 3.5 0 1 1-7 0 3.5 3.5 0 0 1 7 0Z"
clip-rule="evenodd" />
</svg>
</div>
<div class="label">
<span class="label-text-alt"></span>
<span class="label-text-alt"></span>
</div>
</label>
<div class="grid grid-cols-4 gap-4">
<label class="form-control col-span-1">
<div class="label">
<span class="label-text">Postal Code</span>
<span class="label-text-alt"></span>
</div>
<input
type="text"
formControlName="postalCode"
class="input input-bordered w-full" />
<div class="label">
<span class="label-text-alt"></span>
<span class="label-text-alt"></span>
</div>
</label>
<label class="form-control col-span-3">
<div class="label">
<span class="label-text">City</span>
<span class="label-text-alt">Name of the city</span>
</div>
<input
type="text"
formControlName="city"
class="input input-bordered w-full" />
<div class="label">
<span class="label-text-alt"></span>
<span class="label-text-alt"></span>
</div>
</label>
</div>
<div class="grid grid-cols-4 gap-4">
<label class="form-control col-span-3">
<div class="label">
<span class="label-text">Street</span>
<span class="label-text-alt">Name of the street</span>
</div>
<input
type="text"
formControlName="street"
class="input input-bordered w-full" />
<div class="label">
<span class="label-text-alt"></span>
<span class="label-text-alt"></span>
</div>
</label>
<label class="form-control col-span-1">
<div class="label">
<span class="label-text">Number</span>
<span class="label-text-alt"></span>
</div>
<input
type="text"
formControlName="houseNumber"
class="input input-bordered w-full" />
<div class="label">
<span class="label-text-alt"></span>
<span class="label-text-alt"></span>
</div>
</label>
</div>
</form>
<div class="modal-action flex justify-between">
<button class="btn" (click)="closeModal()">Cancel</button>
<button
class="btn btn-primary"
(click)="createLocation()"
[disabled]="locationForm.invalid">
Create Location
</button>
</div>
</div>
</dialog>

View File

@ -0,0 +1,60 @@
import { CommonModule } from '@angular/common';
import { Component, output, OutputEmitterRef } from '@angular/core';
import {
FormBuilder,
FormGroup,
ReactiveFormsModule,
Validators,
} from '@angular/forms';
export interface EventLocation {
plz: string;
stadt: string;
strasse: string;
name: string;
}
@Component({
selector: 'app-location-dialog',
templateUrl: './create-location.dialog.component.html',
standalone: true,
imports: [CommonModule, ReactiveFormsModule],
})
export class LocationDialogComponent {
public locationCreated: OutputEmitterRef<EventLocation> =
output<EventLocation>();
public locationForm: FormGroup = new FormGroup({});
public constructor(private readonly formBuilder: FormBuilder) {
this.locationForm = this.formBuilder.group({
postalCode: ['', [Validators.required, Validators.pattern(/^\d{5}$/)]],
city: ['', Validators.required],
street: ['', Validators.required],
houseNumber: ['', Validators.required],
name: ['', Validators.required],
});
}
public createLocation(): void {
if (this.locationForm.valid) {
this.locationCreated.emit(this.locationForm.value);
this.closeModal();
}
}
public openModal(): void {
const modal = document.getElementById(
'location_modal'
) as HTMLDialogElement;
modal.showModal();
}
public closeModal(): void {
const modal = document.getElementById(
'location_modal'
) as HTMLDialogElement;
modal.close();
}
}

View File

@ -24,7 +24,8 @@
dividerText="Or add a new Location"
newItemText="Create new Location"
emptyStateText="No matching Locations found"
[items]="items"></app-dropdown>
[items]="items"
(submitNewItems)="onDropdownSubmit()"></app-dropdown>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
@ -53,3 +54,6 @@
</label>
</div>
</form>
<app-location-dialog
(locationCreated)="onLocationSubmit($event)"></app-location-dialog>

View File

@ -1,19 +1,42 @@
import { CommonModule } from '@angular/common';
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { ChangeDetectionStrategy, Component, ViewChild } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { DropdownComponent } from '../../../../shared/components/dropdown/dropdown.component';
import {
EventLocation,
LocationDialogComponent,
} from '../dialog/create-location.dialog.component';
@Component({
selector: 'app-basic-step',
standalone: true,
templateUrl: './basic-step.component.html',
providers: [],
imports: [CommonModule, FormsModule, DropdownComponent],
imports: [
CommonModule,
FormsModule,
DropdownComponent,
LocationDialogComponent,
],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class BasicStepComponent {
public items: string[] = ['Option 1', 'Option 2', 'Option 3'];
@ViewChild(LocationDialogComponent)
public locationModal!: LocationDialogComponent;
public items: string[] = ['Nachtigal Köln'];
public constructor() {}
public onDropdownSubmit(): void {
this.openLocationModal();
}
public onLocationSubmit(location: EventLocation): void {
console.log(location);
}
private openLocationModal(): void {
this.locationModal.openModal();
}
}

View File

@ -0,0 +1 @@
<h1>Hello World</h1>

View File

@ -0,0 +1,13 @@
import { Component, ChangeDetectionStrategy } from '@angular/core';
@Component({
selector: 'app-tickets-step',
templateUrl: './tickets-step.component.html',
standalone: true,
providers: [],
imports: [],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class TicketsStepComponent {
public constructor() {}
}

View File

@ -27,23 +27,38 @@ export class DropdownComponent {
public hintTopRight: InputSignal<string> = input<string>('');
public hintBottomLeft: InputSignal<string> = input<string>('');
public hintBottomRight: InputSignal<string> = input<string>('');
public itemSelected: OutputEmitterRef<string> = output<string>();
public searchTerm: WritableSignal<string> = signal('');
public showDropdown: WritableSignal<boolean> = signal<boolean>(false);
public filteredItems: WritableSignal<string[]> = signal<string[]>([]);
public selectedItem: WritableSignal<string | null> = signal<string | null>(
null
);
public itemSelected: OutputEmitterRef<string> = output<string>();
public submitNewItems: OutputEmitterRef<boolean> = output<boolean>();
public onInput(event: Event): void {
const value = (event.target as HTMLInputElement).value;
this.searchTerm.set(value);
this.filteredItems.set(
this.items().filter((item) =>
item.toLowerCase().includes(value.toLowerCase())
)
const matchingItems = this.items().filter((item) =>
item.toLowerCase().includes(value.toLowerCase())
);
this.filteredItems.set(matchingItems);
const exactMatch = this.items().find(
(item) => item.toLowerCase() === value.toLowerCase()
);
if (exactMatch) {
this.selectedItem.set(exactMatch);
this.itemSelected.emit(exactMatch);
} else {
this.selectedItem.set(null);
this.itemSelected.emit('');
}
this.showDropdown.set(true);
}
@ -54,7 +69,9 @@ export class DropdownComponent {
this.itemSelected.emit(item);
}
public submitNewItem(): void {}
public submitNewItem(): void {
this.submitNewItems.emit(true);
}
public onFocus(): void {
this.showDropdown.set(true);
@ -64,6 +81,6 @@ export class DropdownComponent {
public onBlur(): void {
setTimeout(() => {
this.showDropdown.set(false);
}, 200);
}, 100);
}
}