fix(deploy): fixed deploy for gradle.
Some checks failed
Build, Test and Deploy / test-backend (push) Failing after 3s
Build, Test and Deploy / build-and-push (push) Has been skipped
Build, Test and Deploy / deploy (push) Has been skipped

This commit is contained in:
2026-02-04 15:33:28 +01:00
parent 2f7e8798d2
commit db4df2573c
7 changed files with 84 additions and 36 deletions

View File

@@ -21,13 +21,11 @@ jobs:
java-version: '21' java-version: '21'
distribution: 'temurin' distribution: 'temurin'
- name: Run Tests with Maven - name: Run Tests with Gradle
run: | run: |
echo "Installing Maven..."
apt-get update && apt-get install -y maven
echo "Starting Maven Build..."
cd backend cd backend
mvn -B test chmod +x gradlew
./gradlew test
build-and-push: build-and-push:
needs: test-backend needs: test-backend

View File

@@ -1,11 +1,12 @@
# Stage 1: Build Java JAR # Stage 1: Build Java JAR
FROM maven:3.9-eclipse-temurin-21 AS build FROM eclipse-temurin:21-jdk-jammy AS build
WORKDIR /app WORKDIR /app
COPY pom.xml . COPY gradle gradle
COPY gradlew build.gradle settings.gradle ./
# Download dependencies first to cache them # Download dependencies first to cache them
RUN mvn dependency:go-offline RUN ./gradlew dependencies --no-daemon
COPY src ./src COPY src ./src
RUN mvn clean package -DskipTests RUN ./gradlew bootJar -x test --no-daemon
# Stage 2: Runtime Environment # Stage 2: Runtime Environment
FROM eclipse-temurin:21-jre-jammy FROM eclipse-temurin:21-jre-jammy
@@ -34,7 +35,7 @@ ENV SLICER_PATH="/opt/orcaslicer/AppRun"
WORKDIR /app WORKDIR /app
# Copy JAR from build stage # Copy JAR from build stage
COPY --from=build /app/target/*.jar app.jar COPY --from=build /app/build/libs/*.jar app.jar
# Copy profiles # Copy profiles
COPY profiles ./profiles COPY profiles ./profiles

View File

@@ -106,7 +106,7 @@ export class QuoteEstimatorService {
return { return {
price: Math.round(totalPrice * 100) / 100, price: Math.round(totalPrice * 100) / 100,
currency: 'EUR', currency: 'CHF',
printTimeHours: Math.ceil(totalTime / 3600), // Ceil hours printTimeHours: Math.ceil(totalTime / 3600), // Ceil hours
materialUsageGrams: Math.ceil(totalWeight), materialUsageGrams: Math.ceil(totalWeight),
setupCost setupCost

View File

@@ -28,22 +28,27 @@ interface FilePreview {
</div> </div>
<div class="row"> <div class="row">
<!-- Email --> <!-- Phone -->
<app-input formControlName="email" type="email" label="Email *" placeholder="tuo@email.com" class="col"></app-input> <app-input formControlName="email" type="email" label="Email *" placeholder="tuo@email.com" class="col"></app-input>
<!-- Phone --> <!-- Phone -->
<app-input formControlName="phone" type="tel" [label]="('CONTACT.PHONE' | translate)" placeholder="+39 000 000 0000" class="col"></app-input> <app-input formControlName="phone" type="tel" [label]="('CONTACT.PHONE' | translate)" placeholder="+41 00 000 00 00" class="col"></app-input>
</div> </div>
<!-- Name (Always Required) --> <!-- User Type Selector (Segmented Control) -->
<app-input formControlName="name" label="Nome *" placeholder="Il tuo nome"></app-input> <div class="user-type-selector">
<div class="type-option" [class.selected]="!isCompany" (click)="setCompanyMode(false)">
<!-- Company Toggle & Fields --> {{ 'CONTACT.TYPE_PRIVATE' | translate }}
<div class="form-group checkbox-group"> </div>
<input type="checkbox" formControlName="isCompany" id="isCompany"> <div class="type-option" [class.selected]="isCompany" (click)="setCompanyMode(true)">
<label for="isCompany">{{ 'CONTACT.IS_COMPANY' | translate }}</label> {{ 'CONTACT.TYPE_COMPANY' | translate }}
</div>
</div> </div>
<div *ngIf="form.get('isCompany')?.value" class="company-fields"> <!-- Personal Name (Only if NOT Company) -->
<app-input *ngIf="!isCompany" formControlName="name" label="Nome *" placeholder="Il tuo nome"></app-input>
<!-- Company Fields (Only if Company) -->
<div *ngIf="isCompany" class="company-fields">
<app-input formControlName="companyName" [label]="('CONTACT.COMPANY_NAME' | translate) + ' *'" placeholder="Nome Azienda"></app-input> <app-input formControlName="companyName" [label]="('CONTACT.COMPANY_NAME' | translate) + ' *'" placeholder="Nome Azienda"></app-input>
<app-input formControlName="referencePerson" [label]="('CONTACT.REF_PERSON' | translate) + ' *'" placeholder="Persona di Riferimento"></app-input> <app-input formControlName="referencePerson" [label]="('CONTACT.REF_PERSON' | translate) + ' *'" placeholder="Persona di Riferimento"></app-input>
</div> </div>
@@ -114,32 +119,54 @@ interface FilePreview {
flex-direction: column; flex-direction: column;
gap: var(--space-4); gap: var(--space-4);
margin-bottom: var(--space-4); margin-bottom: var(--space-4);
@media(min-width: 768px) { @media(min-width: 768px) {
flex-direction: row; flex-direction: row;
.col { flex: 1; margin-bottom: 0; } .col { flex: 1; margin-bottom: 0; }
} }
} }
/* Modify direct app-input child of row if possible or target host */ app-input.col { width: 100%; }
app-input.col {
width: 100%; /* User Type Selector Styles */
.user-type-selector {
display: inline-flex;
background-color: var(--color-neutral-100);
border-radius: var(--radius-md);
padding: 4px;
margin-bottom: var(--space-4);
gap: 4px;
} }
.checkbox-group { .type-option {
flex-direction: row; padding: 8px 16px;
align-items: center; border-radius: var(--radius-sm);
gap: var(--space-2); cursor: pointer;
input[type="checkbox"] { width: auto; margin: 0; } font-size: 0.875rem;
label { margin: 0; } 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; /* Assuming brand color is light/yellow, black text is safer. Adjust if brand is dark. */
font-weight: 600;
box-shadow: 0 1px 2px rgba(0,0,0,0.05);
}
} }
.company-fields { .company-fields {
display: flex;
flex-direction: column;
gap: var(--space-4);
padding-left: var(--space-4); padding-left: var(--space-4);
border-left: 2px solid var(--color-border); border-left: 2px solid var(--color-border);
margin-bottom: var(--space-4); margin-bottom: var(--space-4);
} }
/* File Upload Styles */
.drop-zone { .drop-zone {
border: 2px dashed var(--color-border); border: 2px dashed var(--color-border);
border-radius: var(--radius-md); border-radius: var(--radius-md);
@@ -200,6 +227,10 @@ export class ContactFormComponent {
sent = signal(false); sent = signal(false);
files = signal<FilePreview[]>([]); files = signal<FilePreview[]>([]);
get isCompany(): boolean {
return this.form.get('isCompany')?.value;
}
requestTypes = [ requestTypes = [
{ value: 'custom', label: 'CONTACT.REQ_TYPE_CUSTOM' }, { value: 'custom', label: 'CONTACT.REQ_TYPE_CUSTOM' },
{ value: 'series', label: 'CONTACT.REQ_TYPE_SERIES' }, { value: 'series', label: 'CONTACT.REQ_TYPE_SERIES' },
@@ -221,21 +252,35 @@ export class ContactFormComponent {
// Handle conditional validation for Company fields // Handle conditional validation for Company fields
this.form.get('isCompany')?.valueChanges.subscribe(isCompany => { this.form.get('isCompany')?.valueChanges.subscribe(isCompany => {
const nameControl = this.form.get('name');
const companyNameControl = this.form.get('companyName'); const companyNameControl = this.form.get('companyName');
const refPersonControl = this.form.get('referencePerson'); const refPersonControl = this.form.get('referencePerson');
if (isCompany) { if (isCompany) {
// Company Mode: Name not required / cleared, Company defaults required
nameControl?.clearValidators();
nameControl?.setValue(''); // Optional: clear value
companyNameControl?.setValidators([Validators.required]); companyNameControl?.setValidators([Validators.required]);
refPersonControl?.setValidators([Validators.required]); refPersonControl?.setValidators([Validators.required]);
} else { } else {
// Private Mode: Name required
nameControl?.setValidators([Validators.required]);
companyNameControl?.clearValidators(); companyNameControl?.clearValidators();
refPersonControl?.clearValidators(); refPersonControl?.clearValidators();
} }
nameControl?.updateValueAndValidity();
companyNameControl?.updateValueAndValidity(); companyNameControl?.updateValueAndValidity();
refPersonControl?.updateValueAndValidity(); refPersonControl?.updateValueAndValidity();
}); });
} }
setCompanyMode(isCompany: boolean) {
this.form.patchValue({ isCompany });
}
onFileSelected(event: Event) { onFileSelected(event: Event) {
const input = event.target as HTMLInputElement; const input = event.target as HTMLInputElement;
if (input.files) this.handleFiles(Array.from(input.files)); if (input.files) this.handleFiles(Array.from(input.files));

View File

@@ -24,7 +24,7 @@ import { AppCardComponent } from '../../shared/components/app-card/app-card.comp
`, `,
styles: [` styles: [`
.contact-hero { .contact-hero {
padding: 5rem 0 3.5rem; padding: 3rem 0 2rem;
background: var(--color-bg); background: var(--color-bg);
text-align: center; text-align: center;
} }
@@ -34,7 +34,7 @@ import { AppCardComponent } from '../../shared/components/app-card/app-card.comp
margin: var(--space-3) auto 0; margin: var(--space-3) auto 0;
} }
.content { .content {
padding: 3rem 0 5rem; padding: 2rem 0 5rem;
max-width: 800px; max-width: 800px;
} }
`] `]

View File

@@ -40,7 +40,7 @@
}, },
"SHOP": { "SHOP": {
"TITLE": "Technical solutions", "TITLE": "Technical solutions",
"SUBTITLE": "Ready-made products solving practical problems, no useless decorations.", "SUBTITLE": "Ready-made products solving practical problems",
"ADD_CART": "Add to Cart", "ADD_CART": "Add to Cart",
"BACK": "Back to Shop" "BACK": "Back to Shop"
}, },
@@ -66,6 +66,8 @@
"TITLE": "Contact Us", "TITLE": "Contact Us",
"SEND": "Send Message", "SEND": "Send Message",
"REQ_TYPE_LABEL": "Type of Request", "REQ_TYPE_LABEL": "Type of Request",
"TYPE_PRIVATE": "Private",
"TYPE_COMPANY": "Business",
"REQ_TYPE_CUSTOM": "Custom Quote", "REQ_TYPE_CUSTOM": "Custom Quote",
"REQ_TYPE_SERIES": "Series Production", "REQ_TYPE_SERIES": "Series Production",
"REQ_TYPE_CONSULT": "Consultation", "REQ_TYPE_CONSULT": "Consultation",

View File

@@ -45,7 +45,7 @@
}, },
"SHOP": { "SHOP": {
"TITLE": "Soluzioni tecniche", "TITLE": "Soluzioni tecniche",
"SUBTITLE": "Prodotti pronti che risolvono problemi pratici, niente decorazioni inutili.", "SUBTITLE": "Prodotti pronti che risolvono problemi pratici",
"ADD_CART": "Aggiungi al Carrello", "ADD_CART": "Aggiungi al Carrello",
"BACK": "Torna allo Shop" "BACK": "Torna allo Shop"
}, },
@@ -71,6 +71,8 @@
"TITLE": "Contattaci", "TITLE": "Contattaci",
"SEND": "Invia Messaggio", "SEND": "Invia Messaggio",
"REQ_TYPE_LABEL": "Tipo di Richiesta", "REQ_TYPE_LABEL": "Tipo di Richiesta",
"TYPE_PRIVATE": "Privato",
"TYPE_COMPANY": "Azienda",
"REQ_TYPE_CUSTOM": "Preventivo Personalizzato", "REQ_TYPE_CUSTOM": "Preventivo Personalizzato",
"REQ_TYPE_SERIES": "Stampa in Serie", "REQ_TYPE_SERIES": "Stampa in Serie",
"REQ_TYPE_CONSULT": "Consulenza", "REQ_TYPE_CONSULT": "Consulenza",