Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public class Visit extends BaseEntity {
@DateTimeFormat(pattern = "yyyy-MM-dd")
private LocalDate date;

@NotBlank
@NotBlank(message = "Description is required")
private String description;

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,7 @@
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.*;

import jakarta.validation.Valid;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
Expand Down Expand Up @@ -61,7 +57,7 @@ public void setAllowedFields(WebDataBinder dataBinder) {
*/
@ModelAttribute("visit")
public Visit loadPetWithVisit(@PathVariable("ownerId") int ownerId, @PathVariable("petId") int petId,
Map<String, Object> model) {
@RequestParam(value = "visitId", required = false) Integer visitId, Map<String, Object> model) {
Optional<Owner> optionalOwner = owners.findById(ownerId);
Owner owner = optionalOwner.orElseThrow(() -> new IllegalArgumentException(
"Owner not found with id: " + ownerId + ". Please ensure the ID is correct "));
Expand All @@ -74,6 +70,14 @@ public Visit loadPetWithVisit(@PathVariable("ownerId") int ownerId, @PathVariabl
model.put("pet", pet);
model.put("owner", owner);

if (visitId != null) {
return pet.getVisits()
.stream()
.filter(v -> v.getId().equals(visitId))
.findFirst()
.orElseThrow(() -> new IllegalArgumentException("Visit not found"));
}

Visit visit = new Visit();
pet.addVisit(visit);
return visit;
Expand Down Expand Up @@ -101,4 +105,31 @@ public String processNewVisitForm(@ModelAttribute Owner owner, @PathVariable int
return "redirect:/owners/{ownerId}";
}

@GetMapping("/owners/{ownerId}/pets/{petId}/visits/{visitId}/edit")
public String initUpdateVisitForm() {
return "pets/editVisitForm";
}

@PostMapping("/owners/{ownerId}/pets/{petId}/visits/{visitId}/edit")
public String processUpdateVisitForm(@PathVariable int ownerId, @PathVariable int petId, @PathVariable int visitId,
@Valid Visit visit, BindingResult result, RedirectAttributes redirectAttributes) {

if (result.hasErrors()) {
return "pets/editVisitForm";
}

Owner owner = owners.findById(ownerId).orElseThrow();
Pet pet = owner.getPet(petId);

Visit existingVisit = pet.getVisits().stream().filter(v -> v.getId().equals(visitId)).findFirst().orElseThrow();

existingVisit.setDescription(visit.getDescription());
existingVisit.setDate(visit.getDate());

owners.save(owner);

redirectAttributes.addFlashAttribute("message", "Visit updated");
return "redirect:/owners/{ownerId}";
}

}
1 change: 1 addition & 0 deletions src/main/resources/messages/messages.properties
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ type=Type
previousVisits=Previous Visits
date=Date
description=Description
edit=Edit
new=New
addVisit=Add Visit
editPet=Edit Pet
Expand Down
91 changes: 56 additions & 35 deletions src/main/resources/templates/owners/ownerDetails.html
Original file line number Diff line number Diff line change
Expand Up @@ -37,46 +37,67 @@ <h2 th:text="#{ownerInformation}">Owner Information</h2>
Owner</a>
<a th:href="@{__${owner.id}__/pets/new}" class="btn btn-primary" th:text="#{addNewPet}">Add
New Pet</a>

<br />
<br />
<br />
<h2 th:text="#{petsAndVisits}">Pets and Visits</h2>

<table class="table table-striped">

<tr th:each="pet : ${owner.pets}">
<td valign="top">
<dl class="dl-horizontal">
<dt th:text="#{name}">Name</dt>
<dd th:text="${pet.name}"></dd>
<dt th:text="#{birthDate}">Birth Date</dt>
<dd th:text="${#temporals.format(pet.birthDate, 'yyyy-MM-dd')}"></dd>
<dt th:text="#{type}">Type</dt>
<dd th:text="${pet.type}"></dd>
</dl>
</td>
<td valign="top">
<table class="table-condensed">
<thead>
<tr>
<th th:text="#{visitDate}">Visit Date</th>
<th th:text="#{description}">Description</th>
</tr>
</thead>
<tr th:each="visit : ${pet.visits}">
<td th:text="${#temporals.format(visit.date, 'yyyy-MM-dd')}"></td>
<td th:text="${visit?.description}"></td>
</tr>
<tr>
<td><a th:href="@{__${owner.id}__/pets/__${pet.id}__/edit}" th:text="#{editPet}">Edit Pet</a></td>
<td><a th:href="@{__${owner.id}__/pets/__${pet.id}__/visits/new}" th:text="#{addVisit}">Add Visit</a></td>
</tr>
</table>
</td>
</tr>
<div th:each="pet : ${owner.pets}" class="panel panel-default">

</table>
<div class="panel-heading">
<strong th:text="${pet.name}"></strong>
<strong> | </strong>
<strong th:text="${pet.type}"></strong>
<strong> | </strong>
<strong th:text="${#temporals.format(pet.birthDate, 'yyyy-MM-dd')}"></strong>
</div>

<div class="panel-body">
<table class="table table-striped">
<thead>
<tr>
<th th:text="#{visitDate}">Visit Date</th>
<th th:text="#{description}">Description</th>
<th>Actions</th>
</tr>
</thead>

<tbody>
<tr th:each="visit : ${pet.visits}">
<td th:text="${#temporals.format(visit.date, 'yyyy-MM-dd')}"></td>
<td th:text="${visit.description}"></td>
<td>
<a class="btn btn-sm btn-primary"
th:href="@{/owners/{ownerId}/pets/{petId}/visits/{visitId}/edit(
ownerId=${owner.id},
petId=${pet.id},
visitId=${visit.id}
)}">
Edit
</a>
</td>
</tr>

<tr th:if="${#lists.isEmpty(pet.visits)}">
<td colspan="3">No visits yet</td>
</tr>
</tbody>
</table>

<div>
<a class="btn btn-default"
th:href="@{__${owner.id}__/pets/__${pet.id}__/edit}">
Edit Pet
</a>

<a class="btn btn-success"
th:href="@{__${owner.id}__/pets/__${pet.id}__/visits/new}">
Add Visit
</a>
</div>

</div>
</div>
<script>
// Function to hide the success and error messages after 3 seconds
function hideMessages() {
Expand All @@ -93,4 +114,4 @@ <h2 th:text="#{petsAndVisits}">Pets and Visits</h2>
</body>


</html>
</html>
43 changes: 43 additions & 0 deletions src/main/resources/templates/pets/editVisitForm.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<!DOCTYPE html>

<html xmlns:th="https://www.thymeleaf.org"
th:replace="~{fragments/layout :: layout (~{::body},'owners')}">

<body>

<h2>Edit Visit</h2>

<form th:object="${visit}" class="form-horizontal" method="post">

<input type="hidden" th:field="*{id}" />

<div class="form-group"
th:classappend="${#fields.hasErrors('description')} ? 'has-error'">

<label class="col-sm-2 control-label">Date</label>
<div class="col-sm-10">
<input th:field="*{date}" type="date" class="form-control"/>
</div>
</div>

<div class="form-group">
<label class="col-sm-2 control-label">Description</label>
<div class="col-sm-10">
<input th:field="*{description}" type="text" class="form-control"/>
<span class="help-block"
th:if="${#fields.hasErrors('description')}"
th:errors="*{description}">
</span>
</div>
</div>

<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button class="btn btn-primary" type="submit">Update Visit</button>
</div>
</div>

</form>

</body>
</html>