feat(front-end): make responsive back-office

This commit is contained in:
2026-03-03 08:43:13 +01:00
parent b7c399e3cb
commit 25afb355b4
16 changed files with 441 additions and 105 deletions

View File

@@ -1,60 +0,0 @@
package com.printcalculator.controller;
import org.springframework.context.annotation.Profile;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
@RestController
@RequestMapping("/api/dev/email")
@Profile("local")
public class DevEmailTestController {
private final TemplateEngine templateEngine;
public DevEmailTestController(TemplateEngine templateEngine) {
this.templateEngine = templateEngine;
}
@GetMapping("/test-template")
public ResponseEntity<String> testTemplate() {
Context context = new Context();
Map<String, Object> templateData = new HashMap<>();
UUID orderId = UUID.randomUUID();
templateData.put("customerName", "Mario Rossi");
templateData.put("orderId", orderId);
templateData.put("orderNumber", orderId.toString().split("-")[0]);
templateData.put("orderDetailsUrl", "https://tuosito.it/it/co/" + orderId);
templateData.put("orderDate", OffsetDateTime.now().format(DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm")));
templateData.put("totalCost", "CHF 45.50");
templateData.put("currentYear", OffsetDateTime.now().getYear());
templateData.put("emailTitle", "Conferma ordine");
templateData.put("headlineText", "Grazie per il tuo ordine #" + templateData.get("orderNumber"));
templateData.put("greetingText", "Ciao Mario,");
templateData.put("introText", "Abbiamo ricevuto il tuo ordine e iniziato l'elaborazione.");
templateData.put("detailsTitleText", "Dettagli ordine");
templateData.put("labelOrderNumber", "Numero ordine");
templateData.put("labelDate", "Data");
templateData.put("labelTotal", "Totale");
templateData.put("orderDetailsCtaText", "Visualizza stato ordine");
templateData.put("attachmentHintText", "In allegato trovi la conferma ordine in PDF con QR bill.");
templateData.put("supportText", "Se hai domande, rispondi a questa email.");
templateData.put("footerText", "Messaggio automatico di 3D-Fab.");
context.setVariables(templateData);
String html = templateEngine.process("email/order-confirmation", context);
return ResponseEntity.ok()
.header("Content-Type", "text/html; charset=utf-8")
.body(html);
}
}

View File

@@ -5,6 +5,7 @@ import com.printcalculator.dto.AdminContactRequestAttachmentDto;
import com.printcalculator.dto.AdminContactRequestDetailDto;
import com.printcalculator.dto.AdminFilamentStockDto;
import com.printcalculator.dto.AdminQuoteSessionDto;
import com.printcalculator.dto.AdminUpdateContactRequestStatusRequest;
import com.printcalculator.entity.CustomQuoteRequest;
import com.printcalculator.entity.CustomQuoteRequestAttachment;
import com.printcalculator.entity.FilamentVariant;
@@ -28,7 +29,9 @@ import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.server.ResponseStatusException;
@@ -41,15 +44,18 @@ import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.OffsetDateTime;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static org.springframework.http.HttpStatus.BAD_REQUEST;
import static org.springframework.http.HttpStatus.CONFLICT;
import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR;
import static org.springframework.http.HttpStatus.NOT_FOUND;
@@ -60,6 +66,9 @@ import static org.springframework.http.HttpStatus.NOT_FOUND;
public class AdminOperationsController {
private static final Logger logger = LoggerFactory.getLogger(AdminOperationsController.class);
private static final Path CONTACT_ATTACHMENTS_ROOT = Paths.get("storage_requests").toAbsolutePath().normalize();
private static final Set<String> CONTACT_REQUEST_ALLOWED_STATUSES = Set.of(
"NEW", "PENDING", "IN_PROGRESS", "DONE", "CLOSED"
);
private final FilamentVariantStockKgRepository filamentStockRepo;
private final FilamentVariantRepository filamentVariantRepo;
@@ -156,22 +165,40 @@ public class AdminOperationsController {
.map(this::toContactRequestAttachmentDto)
.toList();
AdminContactRequestDetailDto dto = new AdminContactRequestDetailDto();
dto.setId(request.getId());
dto.setRequestType(request.getRequestType());
dto.setCustomerType(request.getCustomerType());
dto.setEmail(request.getEmail());
dto.setPhone(request.getPhone());
dto.setName(request.getName());
dto.setCompanyName(request.getCompanyName());
dto.setContactPerson(request.getContactPerson());
dto.setMessage(request.getMessage());
dto.setStatus(request.getStatus());
dto.setCreatedAt(request.getCreatedAt());
dto.setUpdatedAt(request.getUpdatedAt());
dto.setAttachments(attachments);
return ResponseEntity.ok(toContactRequestDetailDto(request, attachments));
}
return ResponseEntity.ok(dto);
@PatchMapping("/contact-requests/{requestId}/status")
@Transactional
public ResponseEntity<AdminContactRequestDetailDto> updateContactRequestStatus(
@PathVariable UUID requestId,
@RequestBody AdminUpdateContactRequestStatusRequest payload
) {
CustomQuoteRequest request = customQuoteRequestRepo.findById(requestId)
.orElseThrow(() -> new ResponseStatusException(NOT_FOUND, "Contact request not found"));
String requestedStatus = payload != null && payload.getStatus() != null
? payload.getStatus().trim().toUpperCase(Locale.ROOT)
: "";
if (!CONTACT_REQUEST_ALLOWED_STATUSES.contains(requestedStatus)) {
throw new ResponseStatusException(
BAD_REQUEST,
"Invalid status. Allowed: " + String.join(", ", CONTACT_REQUEST_ALLOWED_STATUSES)
);
}
request.setStatus(requestedStatus);
request.setUpdatedAt(OffsetDateTime.now());
CustomQuoteRequest saved = customQuoteRequestRepo.save(request);
List<AdminContactRequestAttachmentDto> attachments = customQuoteRequestAttachmentRepo
.findByRequest_IdOrderByCreatedAtAsc(requestId)
.stream()
.map(this::toContactRequestAttachmentDto)
.toList();
return ResponseEntity.ok(toContactRequestDetailDto(saved, attachments));
}
@GetMapping("/contact-requests/{requestId}/attachments/{attachmentId}/file")
@@ -291,6 +318,27 @@ public class AdminOperationsController {
return dto;
}
private AdminContactRequestDetailDto toContactRequestDetailDto(
CustomQuoteRequest request,
List<AdminContactRequestAttachmentDto> attachments
) {
AdminContactRequestDetailDto dto = new AdminContactRequestDetailDto();
dto.setId(request.getId());
dto.setRequestType(request.getRequestType());
dto.setCustomerType(request.getCustomerType());
dto.setEmail(request.getEmail());
dto.setPhone(request.getPhone());
dto.setName(request.getName());
dto.setCompanyName(request.getCompanyName());
dto.setContactPerson(request.getContactPerson());
dto.setMessage(request.getMessage());
dto.setStatus(request.getStatus());
dto.setCreatedAt(request.getCreatedAt());
dto.setUpdatedAt(request.getUpdatedAt());
dto.setAttachments(attachments);
return dto;
}
private AdminQuoteSessionDto toQuoteSessionDto(QuoteSession session) {
AdminQuoteSessionDto dto = new AdminQuoteSessionDto();
dto.setId(session.getId());

View File

@@ -0,0 +1,13 @@
package com.printcalculator.dto;
public class AdminUpdateContactRequestStatusRequest {
private String status;
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
}