fix(front-end): improvements
All checks were successful
Build, Test and Deploy / test-backend (push) Successful in 41s
Build, Test and Deploy / build-and-push (push) Successful in 49s
Build, Test and Deploy / deploy (push) Successful in 9s

This commit is contained in:
2026-02-25 10:53:08 +01:00
parent 4ddd33662d
commit 54d12f4da0
12 changed files with 112 additions and 92 deletions

View File

@@ -46,14 +46,11 @@
</div>
<!-- User Type Selector -->
<div class="user-type-selector">
<div class="type-option" [class.selected]="!isCompany" (click)="setCustomerType(false)">
{{ 'CONTACT.TYPE_PRIVATE' | translate }}
</div>
<div class="type-option" [class.selected]="isCompany" (click)="setCustomerType(true)">
{{ 'CONTACT.TYPE_COMPANY' | translate }}
</div>
</div>
<app-toggle-selector
[options]="userTypeOptions"
[selectedValue]="checkoutForm.get('customerType')?.value"
(selectionChange)="setCustomerType($event)">
</app-toggle-selector>
<app-input formControlName="addressLine1" [label]="'CHECKOUT.ADDRESS_1' | translate" [required]="true"></app-input>
<app-input formControlName="addressLine2" [label]="'CHECKOUT.ADDRESS_2' | translate"></app-input>

View File

@@ -64,39 +64,7 @@
}
}
/* User Type Selector - Matching Contact Form Style */
.user-type-selector {
display: flex;
background-color: var(--color-neutral-100);
border-radius: var(--radius-md);
padding: 4px;
margin: var(--space-6) 0;
gap: 4px;
width: 100%;
max-width: 400px;
}
.type-option {
flex: 1;
text-align: center;
padding: 8px 16px;
border-radius: var(--radius-sm);
cursor: pointer;
font-size: 0.875rem;
font-weight: 500;
color: var(--color-text-muted);
transition: all 0.2s ease;
user-select: none;
&:hover { color: var(--color-text); }
&.selected {
background-color: var(--color-brand);
color: #000;
font-weight: 600;
box-shadow: 0 1px 2px rgba(0,0,0,0.05);
}
}
/* User Type Selector CSS has been extracted to app-toggle-selector component */
.company-fields {
display: flex;

View File

@@ -7,6 +7,7 @@ import { QuoteEstimatorService } from '../calculator/services/quote-estimator.se
import { AppInputComponent } from '../../shared/components/app-input/app-input.component';
import { AppButtonComponent } from '../../shared/components/app-button/app-button.component';
import { AppCardComponent } from '../../shared/components/app-card/app-card.component';
import { AppToggleSelectorComponent, ToggleOption } from '../../shared/components/app-toggle-selector/app-toggle-selector.component';
@Component({
selector: 'app-checkout',
@@ -17,7 +18,8 @@ import { AppCardComponent } from '../../shared/components/app-card/app-card.comp
TranslateModule,
AppInputComponent,
AppButtonComponent,
AppCardComponent
AppCardComponent,
AppToggleSelectorComponent
],
templateUrl: './checkout.component.html',
styleUrls: ['./checkout.component.scss']
@@ -35,6 +37,11 @@ export class CheckoutComponent implements OnInit {
isSubmitting = signal(false); // Add signal for submit state
quoteSession = signal<any>(null); // Add signal for session details
userTypeOptions: ToggleOption[] = [
{ label: 'CONTACT.TYPE_PRIVATE', value: 'PRIVATE' },
{ label: 'CONTACT.TYPE_COMPANY', value: 'BUSINESS' }
];
constructor() {
this.checkoutForm = this.fb.group({
email: ['', [Validators.required, Validators.email]],
@@ -73,9 +80,9 @@ export class CheckoutComponent implements OnInit {
return this.checkoutForm.get('customerType')?.value === 'BUSINESS';
}
setCustomerType(isCompany: boolean) {
const type = isCompany ? 'BUSINESS' : 'PRIVATE';
setCustomerType(type: string) {
this.checkoutForm.patchValue({ customerType: type });
const isCompany = type === 'BUSINESS';
const billingGroup = this.checkoutForm.get('billingAddress') as FormGroup;
const companyControl = billingGroup.get('companyName');

View File

@@ -107,6 +107,12 @@ export class OrderComponent implements OnInit {
if (lang === 'de') {
return 'https://go.twint.ch/static/img/button_dark_de.svg';
}
if (lang === 'it'){
return 'https://go.twint.ch/static/img/button_dark_it.svg';
}
if (lang === 'fr'){
return 'https://go.twint.ch/static/img/button_dark_fr.svg';
}
// Default to EN for everything else (it, fr, en) as instructed or if not DE
return 'https://go.twint.ch/static/img/button_dark_en.svg';
}

View File

@@ -8,18 +8,11 @@
<div class="locations-grid">
<div class="locations-controls">
<div class="location-tabs">
<button
class="tab-btn"
[class.active]="selectedLocation === 'ticino'"
(click)="selectLocation('ticino')">
{{ 'LOCATIONS.TICINO' | translate }}
</button>
<button
class="tab-btn"
[class.active]="selectedLocation === 'bienne'"
(click)="selectLocation('bienne')">
{{ 'LOCATIONS.BIENNE' | translate }}
</button>
<app-toggle-selector
[options]="locationOptions"
[selectedValue]="selectedLocation"
(selectionChange)="selectLocation($event)">
</app-toggle-selector>
</div>
<div class="location-details">
@@ -43,12 +36,12 @@
<div class="map-container">
<iframe
*ngIf="selectedLocation === 'ticino'"
src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d177305.41680509657!2d8.826330925208468!3d46.00511195679905!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x4784407817452d5b%3A0x6a0c0e86b976660!2sTicino%2C%20Svizzera!5e0!3m2!1sit!2sit!4v1700000000000!5m2!1sit!2sit"
src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d2753.843657475132!2d8.96627047671755!3d46.35265507912163!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x4785ca88d01d4a03%3A0xc312484ab7592fb!2sVia%20Giov.Bta.%20Pioda%2029A%2C%206710%20Biasca%2C%20Switzerland!5e0!3m2!1sen!2sch!4v1700000000000!5m2!1sen!2sch"
width="100%" height="450" style="border:0;" allowfullscreen="" loading="lazy" referrerpolicy="no-referrer-when-downgrade">
</iframe>
<iframe
*ngIf="selectedLocation === 'bienne'"
src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d43521.94247549427!2d7.211756262451172!3d47.13677764958641!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x478e192760f384f9%3A0xcb281f622956f4e6!2sBiel%2C%20Svizzera!5e0!3m2!1sit!2sit!4v1700000000000!5m2!1sit!2sit"
src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d2729.0438104193587!2d7.240752176735282!3d47.126435979155985!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x478e1eb84efba295%3A0x95924d5ba8b6f3b0!2sLyss-Strasse%2071%2C%202560%20Nidau%2C%20Switzerland!5e0!3m2!1sen!2sch!4v1700000000000!5m2!1sen!2sch"
width="100%" height="450" style="border:0;" allowfullscreen="" loading="lazy" referrerpolicy="no-referrer-when-downgrade">
</iframe>
</div>

View File

@@ -34,36 +34,10 @@
}
.location-tabs {
display: flex;
gap: 1rem;
margin-bottom: 2rem;
background: var(--color-bg);
padding: 0.5rem;
border-radius: var(--radius-md);
border: 1px solid var(--color-border);
width: 100%;
}
.tab-btn {
flex: 1;
padding: 0.75rem;
border: none;
background: transparent;
border-radius: var(--radius-sm);
color: var(--color-text-muted);
font-weight: 600;
cursor: pointer;
transition: all 0.2s ease;
&:hover {
color: var(--color-text-main);
}
&.active {
background: var(--color-primary-500);
color: var(--color-neutral-900);
box-shadow: var(--shadow-sm);
}
}
.location-details {
padding: 2rem;

View File

@@ -2,18 +2,24 @@ import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { TranslateModule } from '@ngx-translate/core';
import { RouterLink } from '@angular/router';
import { AppToggleSelectorComponent, ToggleOption } from '../app-toggle-selector/app-toggle-selector.component';
@Component({
selector: 'app-locations',
standalone: true,
imports: [CommonModule, TranslateModule, RouterLink],
imports: [CommonModule, TranslateModule, RouterLink, AppToggleSelectorComponent],
templateUrl: './app-locations.component.html',
styleUrl: './app-locations.component.scss'
})
export class AppLocationsComponent {
selectedLocation: 'ticino' | 'bienne' = 'ticino';
selectLocation(location: 'ticino' | 'bienne') {
locationOptions: ToggleOption[] = [
{ label: 'LOCATIONS.TICINO', value: 'ticino' },
{ label: 'LOCATIONS.BIENNE', value: 'bienne' },
];
selectLocation(location: any) {
this.selectedLocation = location;
}
}

View File

@@ -0,0 +1,9 @@
<div class="user-type-selector">
@for (option of options(); track option.value) {
<div class="type-option"
[class.selected]="selectedValue() === option.value"
(click)="selectOption(option.value)">
{{ option.label | translate }}
</div>
}
</div>

View File

@@ -0,0 +1,34 @@
:host {
display: block;
}
.user-type-selector {
display: flex;
background-color: var(--color-neutral-100);
border-radius: var(--radius-md);
padding: 4px;
gap: 4px;
width: 100%;
}
.type-option {
flex: 1;
text-align: center;
padding: 8px 16px;
border-radius: var(--radius-sm);
cursor: pointer;
font-size: 0.875rem;
font-weight: 500;
color: var(--color-text-muted);
transition: all 0.2s ease;
user-select: none;
&:hover { color: var(--color-text); }
&.selected {
background-color: var(--color-brand);
color: #000;
font-weight: 600;
box-shadow: 0 1px 2px rgba(0,0,0,0.05);
}
}

View File

@@ -0,0 +1,26 @@
import { Component, input, output } from '@angular/core';
import { CommonModule } from '@angular/common';
import { TranslateModule } from '@ngx-translate/core';
export interface ToggleOption {
label: string;
value: any;
}
@Component({
selector: 'app-toggle-selector',
standalone: true,
imports: [CommonModule, TranslateModule],
templateUrl: './app-toggle-selector.component.html',
styleUrl: './app-toggle-selector.component.scss'
})
export class AppToggleSelectorComponent {
options = input.required<ToggleOption[]>();
selectedValue = input.required<any>();
selectionChange = output<any>();
selectOption(value: any) {
this.selectionChange.emit(value);
}
}

View File

@@ -107,8 +107,8 @@
"SUBTITLE": "We have two locations to serve you better. Select a location to see details.",
"TICINO": "Ticino",
"BIENNE": "Bienne",
"ADDRESS_TICINO": "Ticino Office, Switzerland",
"ADDRESS_BIENNE": "Bienne Office, Switzerland",
"ADDRESS_TICINO": "Via G. Pioda 29a, 6710 Biasca (TI)",
"ADDRESS_BIENNE": "Lyss-strasse 71, Nidau 2560 Bienne",
"CONTACT_US": "Contact Us"
},
"LEGAL": {

View File

@@ -102,7 +102,7 @@
"PROCESSING": "Elaborazione...",
"NOTES_PLACEHOLDER": "Istruzioni specifiche...",
"SETUP_NOTE": "* Include {{cost}} Costo di Setup",
"STEP_WARNING": "La visualizzazione 3D non è compatibile con i file step e 3mf, ma il calcolatore funziona."
"STEP_WARNING": "La visualizzazione 3D non è compatibile con i file step e 3mf"
},
"QUOTE": {
"PROCEED_ORDER": "Procedi con l'ordine",
@@ -170,8 +170,8 @@
"SUBTITLE": "Siamo presenti in due sedi per coprire meglio il territorio. Seleziona la sede per vedere i dettagli.",
"TICINO": "Ticino",
"BIENNE": "Bienne",
"ADDRESS_TICINO": "Sede Ticino, Svizzera",
"ADDRESS_BIENNE": "Sede Bienne, Svizzera",
"ADDRESS_TICINO": "Via G. Pioda 29a, 6710 Biasca (TI)",
"ADDRESS_BIENNE": "Lyss-strasse 71, Nidau 2560 Bienne",
"CONTACT_US": "Contattaci"
},
"LEGAL": {