Skip to content

Commit ad50409

Browse files
committed
creating product form feature
1 parent e630dac commit ad50409

File tree

11 files changed

+361
-41
lines changed

11 files changed

+361
-41
lines changed

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
1313
<quarkus.platform.artifact-id>quarkus-bom</quarkus.platform.artifact-id>
1414
<quarkus.platform.group-id>io.quarkus.platform</quarkus.platform.group-id>
15-
<quarkus.platform.version>3.26.3</quarkus.platform.version>
15+
<quarkus.platform.version>3.28.1</quarkus.platform.version>
1616
<skipITs>true</skipITs>
1717
<surefire-plugin.version>3.5.2</surefire-plugin.version>
1818
</properties>
Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
package app.domain.invoices;
22

3+
import io.quarkus.qute.CheckedTemplate;
4+
import io.quarkus.qute.TemplateInstance;
35
import jakarta.inject.Inject;
46
import jakarta.ws.rs.GET;
57
import jakarta.ws.rs.Path;
6-
import jakarta.ws.rs.core.Response;
8+
import jakarta.ws.rs.Produces;
9+
import jakarta.ws.rs.core.MediaType;
710

811
import java.util.List;
912

@@ -14,11 +17,20 @@ public class InvoiceResource {
1417
InvoiceRepository invoiceRepository;
1518

1619
@GET
17-
public Response getInvoices() {
18-
List<InvoiceData> invoices = invoiceRepository.findAll().list()
20+
@Produces(MediaType.TEXT_HTML)
21+
public TemplateInstance renderInvoiceTemplate() {
22+
return Templates.invoices(getInvoices());
23+
}
24+
25+
public List<InvoiceData> getInvoices() {
26+
return invoiceRepository.findAll().list()
1927
.stream()
2028
.map(InvoiceData::from)
2129
.toList();
22-
return Response.ok(invoices).build();
30+
}
31+
32+
@CheckedTemplate
33+
public static class Templates {
34+
public static native TemplateInstance invoices(List<InvoiceData> invoices);
2335
}
2436
}

src/main/java/app/domain/orders/OrderController.java renamed to src/main/java/app/domain/orders/OrderResource.java

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,24 @@
11
package app.domain.orders;
22

3+
import app.domain.customers.CustomerResource;
4+
import app.domain.customers.model.Customer;
35
import app.domain.payments.PaymentService;
46
import app.domain.products.Product;
57
import app.domain.products.ProductRepository;
68
import app.domain.users.UserRepository;
79
import app.service.EmailService;
10+
import io.quarkus.qute.CheckedTemplate;
11+
import io.quarkus.qute.TemplateInstance;
812
import jakarta.inject.Inject;
913
import jakarta.validation.constraints.NotNull;
1014
import jakarta.ws.rs.*;
15+
import jakarta.ws.rs.core.MediaType;
1116
import jakarta.ws.rs.core.Response;
1217

1318
import java.util.List;
1419

1520
@Path("/orders")
16-
public class OrderController {
21+
public class OrderResource {
1722
@Inject
1823
OrderRepository orderRepository;
1924

@@ -32,13 +37,22 @@ public class OrderController {
3237
@Inject
3338
EmailService emailService;
3439

40+
@CheckedTemplate
41+
public static class Templates {
42+
public static native TemplateInstance orders(List<OrderData> orders);
43+
}
44+
3545
@GET
36-
public Response getOrders() {
37-
List<OrderData> orders = orderRepository.listAll()
46+
@Produces(MediaType.TEXT_HTML)
47+
public TemplateInstance renderOrderTemplate() {
48+
return Templates.orders(getOrders());
49+
}
50+
51+
private List<OrderData> getOrders() {
52+
return orderRepository.listAll()
3853
.stream()
3954
.map(OrderData::from)
4055
.toList();
41-
return Response.ok(orders).build();
4256
}
4357

4458
@POST

src/main/java/app/domain/products/CreateProductFormData.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,12 @@
1212
public record CreateProductFormData(
1313
@FormParam("name") @NotBlank(message = "Name must not be empty") String name,
1414
@FormParam("description") @NotBlank(message = "Description must not be empty") String description,
15-
@FormParam("photos") @NotEmpty(message = "At least 1 image must be provided") List<FileUpload> photos,
16-
@FormParam("inStock") int inStock,
15+
//@FormParam("photos") @NotEmpty(message = "At least 1 image must be provided") List<FileUpload> photos,
16+
@FormParam("stock") Integer stock,
1717
@FormParam("price") @NotNull BigDecimal price) {
18+
19+
public static CreateProductFormData newProductFormData(){
20+
return new CreateProductFormData("", "", null, null);
21+
}
22+
1823
}
Lines changed: 47 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,20 @@
11
package app.domain.products;
22

3-
import app.domain.employees.Employee;
3+
import io.quarkus.qute.CheckedTemplate;
4+
import io.quarkus.qute.TemplateInstance;
45
import jakarta.inject.Inject;
56
import jakarta.transaction.Transactional;
67
import jakarta.validation.ConstraintViolation;
78
import jakarta.validation.Validator;
8-
import jakarta.ws.rs.GET;
9-
import jakarta.ws.rs.POST;
10-
import jakarta.ws.rs.Path;
11-
import jakarta.ws.rs.core.Response;
9+
import jakarta.ws.rs.*;
10+
import jakarta.ws.rs.core.MediaType;
1211
import org.eclipse.microprofile.config.inject.ConfigProperty;
13-
import org.jboss.resteasy.reactive.multipart.FileUpload;
1412

1513
import java.io.IOException;
16-
import java.nio.file.Files;
17-
import java.nio.file.Paths;
1814
import java.util.List;
1915
import java.util.UUID;
2016
import java.util.stream.Collectors;
2117

22-
import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
23-
2418
@Path("/products")
2519
public class ProductResource {
2620
@Inject
@@ -33,7 +27,8 @@ public class ProductResource {
3327
String photosDir;
3428

3529
@GET
36-
public Response findProducts() {
30+
@Produces(MediaType.TEXT_HTML)
31+
public TemplateInstance products() {
3732
List<ProductData> products = repository
3833
.findAll()
3934
.list()
@@ -43,44 +38,59 @@ public Response findProducts() {
4338
p.getDescription(), p.getPrice(),
4439
p.getStock())
4540
).toList();
46-
return Response.ok(products).build();
41+
return Templates.products(products);
42+
}
43+
44+
@GET()
45+
@Path("/new")
46+
@Produces(MediaType.TEXT_HTML)
47+
public TemplateInstance newProduct() {
48+
return Templates.newProduct(CreateProductFormData.newProductFormData())
49+
.data("success", null)
50+
.data("error", null);
4751
}
4852

4953
@POST
54+
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
55+
@Produces(MediaType.TEXT_HTML)
5056
@Transactional
51-
public Response createProduct(CreateProductFormData form) throws IOException {
57+
public TemplateInstance createProduct(CreateProductFormData form) throws IOException {
5258
var violations = validator.validate(form);
5359
if (!violations.isEmpty()) {
5460
var errors = violations.stream()
5561
.collect(Collectors.toMap(v -> v.getPropertyPath().toString(),
5662
ConstraintViolation::getMessage));
57-
return Response.status(Response.Status.BAD_REQUEST).entity(errors).build();
63+
return Templates.newProduct(form)
64+
.data("success", null)
65+
.data("error", errors.values());
5866
}
5967

6068
//create product
6169
Product product = new Product();
6270
product.setName(form.name());
6371
product.setDescription(form.description());
6472
product.setPrice(form.price());
65-
product.setStock(form.inStock());
73+
product.setStock(form.stock());
6674
repository.persist(product);
6775

68-
for (FileUpload file : form.photos()) {
69-
//persist photo data in database
70-
var photo = new Photo();
71-
var filename = generateUniqueFileName(file.fileName());
72-
photo.setName(filename);
73-
photo.setSize(file.size());
74-
photo.setUrl(photosDir.concat("/").concat(filename));
75-
photo.setProduct(product);
76-
repository.savePhoto(photo);
76+
// for (FileUpload file : form.photos()) {
77+
// //persist photo data in database
78+
// var photo = new Photo();
79+
// var filename = generateUniqueFileName(file.fileName());
80+
// photo.setName(filename);
81+
// photo.setSize(file.size());
82+
// photo.setUrl(photosDir.concat("/").concat(filename));
83+
// photo.setProduct(product);
84+
// repository.savePhoto(photo);
85+
//
86+
// //copy file in filesystem
87+
// var path = file.uploadedFile();
88+
// Files.copy(path, Paths.get(photosDir).resolve(filename), REPLACE_EXISTING);
89+
// }
7790

78-
//copy file in filesystem
79-
var path = file.uploadedFile();
80-
Files.copy(path, Paths.get(photosDir).resolve(filename), REPLACE_EXISTING);
81-
}
82-
83-
return Response.ok(Employee.listAll()).build();
91+
return Templates.productForm(CreateProductFormData.newProductFormData())
92+
.data("error", null)
93+
.data("success", "Product created");
8494
}
8595

8696
private String generateUniqueFileName(String originalFileName) {
@@ -93,4 +103,11 @@ private String generateUniqueFileName(String originalFileName) {
93103
return UUID.randomUUID() + extension;
94104
}
95105

106+
@CheckedTemplate(requireTypeSafeExpressions = false)
107+
public static class Templates {
108+
public static native TemplateInstance products(List<ProductData> products);
109+
public static native TemplateInstance newProduct(CreateProductFormData product);
110+
public static native TemplateInstance productForm(CreateProductFormData product);
111+
}
112+
96113
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1" />
6+
<title>Management App</title>
7+
<link href="/webjars/bootstrap/5.3.8/css/bootstrap.min.css" rel="stylesheet">
8+
<link rel="stylesheet" href="/webjars/bootstrap-icons/1.13.1/font/bootstrap-icons.min.css">
9+
<link href="/css/dashboard.css" rel="stylesheet">
10+
</head>
11+
<body>
12+
{#include partials/header /}
13+
<div class="container-fluid">
14+
<div class="row">
15+
{#include partials/sidenav /}
16+
<main class="col-md-9 ms-sm-auto col-lg-10 px-md-4">
17+
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
18+
<h1 class="h2">Invoices</h1>
19+
<div class="btn-toolbar mb-2 mb-md-0">
20+
<div class="btn-group me-2">
21+
<button type="button" class="btn btn-sm btn-outline-secondary">
22+
Share
23+
</button>
24+
<button type="button" class="btn btn-sm btn-outline-secondary">
25+
Export
26+
</button>
27+
</div>
28+
<button type="button"
29+
class="btn btn-sm btn-outline-secondary dropdown-toggle d-flex align-items-center gap-1">
30+
<i class="bi bi-calendar3"></i>
31+
This week
32+
</button>
33+
</div>
34+
</div>
35+
<div class="table-responsive small">
36+
<table class="table table-striped table-sm">
37+
<thead>
38+
<tr>
39+
<th scope="col">Id</th>
40+
<th scope="col">Order Id</th>
41+
<th scope="col">Date</th>
42+
<th scope="col">Due Date</th>
43+
<th scope="col">Amount Paid</th>
44+
<th scope="col">Payment Status</th>
45+
</tr>
46+
</thead>
47+
<tbody>
48+
{#for invoice in invoices}
49+
<tr>
50+
<td>{invoice.id}</td>
51+
<td>{invoice.orderId}</td>
52+
<td>{invoice.date}</td>
53+
<td>{invoice.dueDate}</td>
54+
<td>{invoice.amountPaid}</td>
55+
<td>{invoice.paymentStatus}</td>
56+
</tr>
57+
{/for}
58+
</tbody>
59+
</table>
60+
</div>
61+
</main>
62+
</div>
63+
</div>
64+
<script src="/webjars/bootstrap/5.3.8/js/bootstrap.min.js"></script>
65+
<script src="/js/dashboard.js"></script>
66+
</body>
67+
</html>
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1" />
6+
<title>Management App</title>
7+
<link href="/webjars/bootstrap/5.3.8/css/bootstrap.min.css" rel="stylesheet">
8+
<link rel="stylesheet" href="/webjars/bootstrap-icons/1.13.1/font/bootstrap-icons.min.css">
9+
<link href="/css/dashboard.css" rel="stylesheet">
10+
</head>
11+
<body>
12+
{#include partials/header /}
13+
<div class="container-fluid">
14+
<div class="row">
15+
{#include partials/sidenav /}
16+
<main class="col-md-9 ms-sm-auto col-lg-10 px-md-4">
17+
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
18+
<h1 class="h2">Orders</h1>
19+
<div class="btn-toolbar mb-2 mb-md-0">
20+
<div class="btn-group me-2">
21+
<button type="button" class="btn btn-sm btn-outline-secondary">
22+
Share
23+
</button>
24+
<button type="button" class="btn btn-sm btn-outline-secondary">
25+
Export
26+
</button>
27+
</div>
28+
<button type="button"
29+
class="btn btn-sm btn-outline-secondary dropdown-toggle d-flex align-items-center gap-1">
30+
<i class="bi bi-calendar3"></i>
31+
This week
32+
</button>
33+
</div>
34+
</div>
35+
<div class="table-responsive small">
36+
<table class="table table-striped table-sm">
37+
<thead>
38+
<tr>
39+
<th scope="col">Order Id</th>
40+
<th scope="col">Order Delivery Id</th>
41+
<th scope="col">Customer Id</th>
42+
<th scope="col">Order Date</th>
43+
<th scope="col">Total Amount</th>
44+
<th scope="col">Status</th>
45+
</tr>
46+
</thead>
47+
<tbody>
48+
{#for order in orders}
49+
<tr>
50+
<td>{order.id}</td>
51+
<td>{order.orderDeliveryId}</td>
52+
<td>{order.customerId}</td>
53+
<td>{order.orderDate}</td>
54+
<td>$ {order.totalAmount}</td>
55+
<td>{order.status}</td>
56+
</tr>
57+
{/for}
58+
</tbody>
59+
</table>
60+
</div>
61+
</main>
62+
</div>
63+
</div>
64+
<script src="/webjars/bootstrap/5.3.8/js/bootstrap.min.js"></script>
65+
<script src="/js/dashboard.js"></script>
66+
</body>
67+
</html>

0 commit comments

Comments
 (0)