dev #8
@@ -3,7 +3,7 @@
|
||||
<p class="subtitle">{{ 'CALC.SUBTITLE' | translate }}</p>
|
||||
|
||||
@if (error()) {
|
||||
<app-alert type="error">{{ 'CALC.ERROR_GENERIC' | translate }}</app-alert>
|
||||
<app-alert type="error">{{ errorKey() | translate }}</app-alert>
|
||||
}
|
||||
</div>
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ export class CalculatorPageComponent implements OnInit {
|
||||
uploadProgress = signal(0);
|
||||
result = signal<QuoteResult | null>(null);
|
||||
error = signal<boolean>(false);
|
||||
errorKey = signal<string>('CALC.ERROR_GENERIC');
|
||||
|
||||
orderSuccess = signal(false);
|
||||
|
||||
@@ -64,6 +65,14 @@ export class CalculatorPageComponent implements OnInit {
|
||||
next: (data) => {
|
||||
// 1. Map to Result
|
||||
const result = this.estimator.mapSessionToQuoteResult(data);
|
||||
if (this.isInvalidQuote(result)) {
|
||||
this.setQuoteError('CALC.ERROR_ZERO_PRICE');
|
||||
this.loading.set(false);
|
||||
return;
|
||||
}
|
||||
|
||||
this.error.set(false);
|
||||
this.errorKey.set('CALC.ERROR_GENERIC');
|
||||
this.result.set(result);
|
||||
this.step.set('quote');
|
||||
|
||||
@@ -79,7 +88,7 @@ export class CalculatorPageComponent implements OnInit {
|
||||
},
|
||||
error: (err) => {
|
||||
console.error('Failed to load session', err);
|
||||
this.error.set(true);
|
||||
this.setQuoteError('CALC.ERROR_GENERIC');
|
||||
this.loading.set(false);
|
||||
}
|
||||
});
|
||||
@@ -146,6 +155,7 @@ export class CalculatorPageComponent implements OnInit {
|
||||
this.loading.set(true);
|
||||
this.uploadProgress.set(0);
|
||||
this.error.set(false);
|
||||
this.errorKey.set('CALC.ERROR_GENERIC');
|
||||
this.result.set(null);
|
||||
this.orderSuccess.set(false);
|
||||
|
||||
@@ -163,6 +173,14 @@ export class CalculatorPageComponent implements OnInit {
|
||||
} else {
|
||||
// It's the result
|
||||
const res = event as QuoteResult;
|
||||
if (this.isInvalidQuote(res)) {
|
||||
this.setQuoteError('CALC.ERROR_ZERO_PRICE');
|
||||
this.loading.set(false);
|
||||
return;
|
||||
}
|
||||
|
||||
this.error.set(false);
|
||||
this.errorKey.set('CALC.ERROR_GENERIC');
|
||||
this.result.set(res);
|
||||
this.loading.set(false);
|
||||
this.uploadProgress.set(100);
|
||||
@@ -180,7 +198,7 @@ export class CalculatorPageComponent implements OnInit {
|
||||
}
|
||||
},
|
||||
error: () => {
|
||||
this.error.set(true);
|
||||
this.setQuoteError('CALC.ERROR_GENERIC');
|
||||
this.loading.set(false);
|
||||
}
|
||||
});
|
||||
@@ -216,10 +234,19 @@ export class CalculatorPageComponent implements OnInit {
|
||||
next: () => {
|
||||
// 3. Fetch the updated session totals from the backend
|
||||
this.estimator.getQuoteSession(currentSessionId).subscribe({
|
||||
next: (sessionData) => {
|
||||
next: (sessionData) => {
|
||||
const newResult = this.estimator.mapSessionToQuoteResult(sessionData);
|
||||
// Preserve notes
|
||||
newResult.notes = this.result()?.notes;
|
||||
|
||||
if (this.isInvalidQuote(newResult)) {
|
||||
this.setQuoteError('CALC.ERROR_ZERO_PRICE');
|
||||
this.loading.set(false);
|
||||
return;
|
||||
}
|
||||
|
||||
this.error.set(false);
|
||||
this.errorKey.set('CALC.ERROR_GENERIC');
|
||||
this.result.set(newResult);
|
||||
this.loading.set(false);
|
||||
},
|
||||
@@ -282,4 +309,14 @@ export class CalculatorPageComponent implements OnInit {
|
||||
|
||||
this.router.navigate(['/contact']);
|
||||
}
|
||||
|
||||
private isInvalidQuote(result: QuoteResult): boolean {
|
||||
return !Number.isFinite(result.totalPrice) || result.totalPrice <= 0;
|
||||
}
|
||||
|
||||
private setQuoteError(key: string): void {
|
||||
this.errorKey.set(key);
|
||||
this.error.set(true);
|
||||
this.result.set(null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,7 +90,8 @@
|
||||
"PROCESSING": "Verarbeitung...",
|
||||
"NOTES_PLACEHOLDER": "Spezifische Anweisungen...",
|
||||
"SETUP_NOTE": "* Beinhaltet {{cost}} als Einrichtungskosten",
|
||||
"SHIPPING_NOTE": "** Versandkosten ausgeschlossen, werden im nächsten Schritt berechnet"
|
||||
"SHIPPING_NOTE": "** Versandkosten ausgeschlossen, werden im nächsten Schritt berechnet",
|
||||
"ERROR_ZERO_PRICE": "Etwas ist schiefgelaufen. Versuche ein anderes Format oder kontaktiere uns."
|
||||
},
|
||||
"SHOP": {
|
||||
"TITLE": "Technische Lösungen",
|
||||
|
||||
@@ -90,7 +90,8 @@
|
||||
"PROCESSING": "Processing...",
|
||||
"NOTES_PLACEHOLDER": "Specific instructions...",
|
||||
"SETUP_NOTE": "* Includes {{cost}} as setup cost",
|
||||
"SHIPPING_NOTE": "** Shipping costs excluded, calculated at the next step"
|
||||
"SHIPPING_NOTE": "** Shipping costs excluded, calculated at the next step",
|
||||
"ERROR_ZERO_PRICE": "Something went wrong. Try another format or contact us."
|
||||
},
|
||||
"SHOP": {
|
||||
"TITLE": "Technical solutions",
|
||||
|
||||
@@ -115,7 +115,8 @@
|
||||
"REMOVE_FILE": "Supprimer le fichier",
|
||||
"FALLBACK_MATERIAL": "PLA (fallback)",
|
||||
"FALLBACK_QUALITY_STANDARD": "Standard",
|
||||
"ERR_FILE_TOO_LARGE": "Certains fichiers dépassent la limite de 200MB et n'ont pas été ajoutés."
|
||||
"ERR_FILE_TOO_LARGE": "Certains fichiers dépassent la limite de 200MB et n'ont pas été ajoutés.",
|
||||
"ERROR_ZERO_PRICE": "Quelque chose s'est mal passé. Essayez un autre format ou contactez-nous."
|
||||
},
|
||||
"QUOTE": {
|
||||
"PROCEED_ORDER": "Procéder à la commande",
|
||||
|
||||
@@ -115,7 +115,8 @@
|
||||
"REMOVE_FILE": "Rimuovi file",
|
||||
"FALLBACK_MATERIAL": "PLA (fallback)",
|
||||
"FALLBACK_QUALITY_STANDARD": "Standard",
|
||||
"ERR_FILE_TOO_LARGE": "Alcuni file superano il limite di 200MB e non sono stati aggiunti."
|
||||
"ERR_FILE_TOO_LARGE": "Alcuni file superano il limite di 200MB e non sono stati aggiunti.",
|
||||
"ERROR_ZERO_PRICE": "Qualcosa è andato storto. Prova con un altro formato oppure contattaci."
|
||||
},
|
||||
"QUOTE": {
|
||||
"PROCEED_ORDER": "Procedi con l'ordine",
|
||||
|
||||
Reference in New Issue
Block a user