Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 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
3 changes: 0 additions & 3 deletions .idea/biome.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 4 additions & 9 deletions src/main/java/codes/yam/contacts/Contact.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,11 @@ public class Contact {

private String slug;

@NotBlank
private String first;
@NotBlank private String first;

@NotBlank
private String last;
@NotBlank private String last;

@NotBlank
@Email
private String email;
@NotBlank @Email private String email;

@NotBlank
private String phone;
@NotBlank private String phone;
}
8 changes: 6 additions & 2 deletions src/main/java/codes/yam/contacts/ContactController.java
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,12 @@ public ResponseEntity<Void> deleteContact(@PathVariable String slug) {
}

@DeleteMapping
public ResponseEntity<Void> deleteManyContacts(@RequestParam List<String> slugs) {
contactService.deleteMany(slugs);
public ResponseEntity<Void> deleteManyContacts(
@RequestParam(required = false) List<String> selected_contact_slugs) {
if (selected_contact_slugs == null || selected_contact_slugs.isEmpty()) {
return ResponseEntity.noContent().build();
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved
contactService.deleteMany(selected_contact_slugs);
return ResponseEntity.status(HttpStatus.SEE_OTHER).location(URI.create("/contacts")).build();
}

Expand Down
9 changes: 5 additions & 4 deletions src/main/java/codes/yam/contacts/ContactRepository.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@ public interface ContactRepository extends JpaRepository<Contact, UUID> {

List<Contact> findAllBySlugIn(Collection<String> slugs);

@Query("SELECT c FROM Contact c WHERE " +
"LOWER(c.first) LIKE LOWER(CONCAT('%', :q, '%')) OR " +
"LOWER(c.last) LIKE LOWER(CONCAT('%', :q, '%')) OR " +
"LOWER(c.email) LIKE LOWER(CONCAT('%', :q, '%'))")
@Query(
"SELECT c FROM Contact c WHERE "
+ "LOWER(c.first) LIKE LOWER(CONCAT('%', :q, '%')) OR "
+ "LOWER(c.last) LIKE LOWER(CONCAT('%', :q, '%')) OR "
+ "LOWER(c.email) LIKE LOWER(CONCAT('%', :q, '%'))")
List<Contact> search(@Param("q") String q);
}
8 changes: 4 additions & 4 deletions src/main/java/codes/yam/contacts/WebConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ public void addViewControllers(ViewControllerRegistry registry) {

@Bean
public FilterRegistrationBean<UrlHandlerFilter> trailingSlashFilter() {
UrlHandlerFilter filter = UrlHandlerFilter
.trailingSlashHandler("/**")
.redirect(HttpStatus.PERMANENT_REDIRECT)
.build();
UrlHandlerFilter filter =
UrlHandlerFilter.trailingSlashHandler("/**")
.redirect(HttpStatus.PERMANENT_REDIRECT)
.build();
return new FilterRegistrationBean<>(filter);
}
}
24 changes: 21 additions & 3 deletions src/main/resources/data.sql
Original file line number Diff line number Diff line change
@@ -1,3 +1,21 @@
INSERT INTO contact (id, slug, first, last, email, phone) VALUES
('550e8400-e29b-41d4-a716-446655440000', 'john-doe', 'John', 'Doe', 'john@example.com', '555-1234'),
('550e8400-e29b-41d4-a716-446655440001', 'jane-doe', 'Jane', 'Doe', 'jane@example.com', '555-5678');
INSERT INTO contact (id, slug, first, last, email, phone)
VALUES ('550e8400-e29b-41d4-a716-446655440000', 'john-doe', 'John', 'Doe', 'john@example.com', '555-1234'),
('550e8400-e29b-41d4-a716-446655440001', 'jane-doe', 'Jane', 'Doe', 'jane@example.com', '555-5678'),
('550e8400-e29b-41d4-a716-446655440002', 'alice-smith', 'Alice', 'Smith', 'alice@example.com', '555-2001'),
('550e8400-e29b-41d4-a716-446655440003', 'bob-johnson', 'Bob', 'Johnson', 'bob@example.com', '555-2002'),
('550e8400-e29b-41d4-a716-446655440004', 'carol-williams', 'Carol', 'Williams', 'carol@example.com', '555-2003'),
('550e8400-e29b-41d4-a716-446655440005', 'dave-brown', 'Dave', 'Brown', 'dave@example.com', '555-2004'),
('550e8400-e29b-41d4-a716-446655440006', 'eve-jones', 'Eve', 'Jones', 'eve@example.com', '555-2005'),
('550e8400-e29b-41d4-a716-446655440007', 'frank-garcia', 'Frank', 'Garcia', 'frank@example.com', '555-2006'),
('550e8400-e29b-41d4-a716-446655440008', 'grace-martinez', 'Grace', 'Martinez', 'grace@example.com', '555-2007'),
('550e8400-e29b-41d4-a716-446655440009', 'henry-davis', 'Henry', 'Davis', 'henry@example.com', '555-2008'),
('550e8400-e29b-41d4-a716-44665544000a', 'iris-miller', 'Iris', 'Miller', 'iris@example.com', '555-2009'),
('550e8400-e29b-41d4-a716-44665544000b', 'jack-wilson', 'Jack', 'Wilson', 'jack@example.com', '555-2010'),
('550e8400-e29b-41d4-a716-44665544000c', 'karen-moore', 'Karen', 'Moore', 'karen@example.com', '555-2011'),
('550e8400-e29b-41d4-a716-44665544000d', 'leo-taylor', 'Leo', 'Taylor', 'leo@example.com', '555-2012'),
('550e8400-e29b-41d4-a716-44665544000e', 'mia-anderson', 'Mia', 'Anderson', 'mia@example.com', '555-2013'),
('550e8400-e29b-41d4-a716-44665544000f', 'nick-thomas', 'Nick', 'Thomas', 'nick@example.com', '555-2014'),
('550e8400-e29b-41d4-a716-446655440010', 'olivia-jackson', 'Olivia', 'Jackson', 'olivia@example.com', '555-2015'),
('550e8400-e29b-41d4-a716-446655440011', 'paul-white', 'Paul', 'White', 'paul@example.com', '555-2016'),
('550e8400-e29b-41d4-a716-446655440012', 'quinn-harris', 'Quinn', 'Harris', 'quinn@example.com', '555-2017'),
('550e8400-e29b-41d4-a716-446655440013', 'rachel-clark', 'Rachel', 'Clark', 'rachel@example.com', '555-2018');
32 changes: 16 additions & 16 deletions src/main/resources/templates/contacts/edit.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,26 @@
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
xmlns:th="http://www.thymeleaf.org">
<head>
<title>Edit Contact</title>
<title>Edit Contact</title>
</head>
<body>
<!--/*@thymesVar id="contact" type="codes.yam.contacts.Contact"*/-->
<div layout:fragment="content">
<h2>Edit Contact</h2>
<form method="post" th:action="@{/contacts/{slug}/edit(slug=${contact.slug})}">
<th:block th:replace="~{fragments/contact-fields::contact-fields}"></th:block>
<button type="submit">Save</button>
</form>
<button
hx-confirm="Are you sure you want to delete this contact?"
th:attr="hx-delete=@{/contacts/{slug}(slug=${contact.slug})}"
hx-push-url="true"
hx-target="body">
Delete Contact
</button>
<p>
<a href="/contacts">Back</a>
</p>
<h2>Edit Contact</h2>
<form method="post" th:action="@{/contacts/{slug}/edit(slug=${contact.slug})}">
<th:block th:replace="~{fragments/contact-fields::contact-fields}"></th:block>
<button type="submit">Save</button>
</form>
<button
hx-confirm="Are you sure you want to delete this contact?"
hx-push-url="true"
hx-target="body"
th:attr="hx-delete=@{/contacts/{slug}(slug=${contact.slug})}">
Delete Contact
</button>
<p>
<a href="/contacts">Back</a>
</p>
</div>
</body>
</html>
81 changes: 41 additions & 40 deletions src/main/resources/templates/contacts/list.html
Original file line number Diff line number Diff line change
@@ -1,51 +1,52 @@
<!DOCTYPE html>
<html layout:decorate="~{layout}" lang="en"
xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
<html lang="en" layout:decorate="~{layout}"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
xmlns:th="http://www.thymeleaf.org">
<body>
<!--/*@thymesVar id="search" type="java.lang.String"*/-->
<!--/*@thymesVar id="contacts" type="java.util.List<codes.yam.contacts.Contact>"*/-->
<div layout:fragment="content">
<form action="/contacts" method="get">
<label for="search">Search contacts:</label>
<input
id="search" name="q"
placeholder="Search contacts..."
th:value="${search}"
type="search"
/>
<button type="submit">Search</button>
</form>
<form action="/contacts" method="get">
<label for="search">Search contacts:</label>
<input
id="search" name="q"
placeholder="Search contacts..."
th:value="${search}"
type="search"
/>
<button type="submit">Search</button>
</form>

<p th:if="${search}">Results for "<span th:text="${search}"></span>":</p>
<p th:if="${search}">Results for "<span th:text="${search}"></span>":</p>

<p th:if="${contacts.isEmpty()}">No contacts found.</p>
<table th:unless="${contacts.isEmpty()}">
<thead>
<tr>
<th>First</th>
<th>Last</th>
<th>Phone</th>
<th>Email</th>
<th></th>
</tr>
</thead>
<tbody>
<tr th:each="contact : ${contacts}">
<td th:text="${contact.first}"></td>
<td th:text="${contact.last}"></td>
<td th:text="${contact.phone}"></td>
<td th:text="${contact.email}"></td>
<td>
<a th:href="@{/contacts/{slug}/edit(slug=${contact.slug})}">Edit</a>
<a th:href="@{/contacts/{slug}(slug=${contact.slug})}">View</a>
</td>
</tr>
</tbody>
<p th:if="${contacts.isEmpty()}">No contacts found.</p>
<form th:unless="${contacts.isEmpty()}">
<table>
<thead>
<tr>
<th></th>
<th>First</th>
<th>Last</th>
<th>Phone</th>
<th>Email</th>
<th></th>
</tr>
</thead>
<tbody th:insert="~{fragments/contact-list-rows :: rows}"></tbody>
</table>
<p>
<a href="/contacts/new">Add New Contact</a>
</p>
<button
hx-confirm="Are you sure you want to delete the selected contacts?"
hx-delete="/contacts"
hx-target="body"
type="button"
>
Delete Selected
</button>
</form>
<p>
<a href="/contacts/new">Add New Contact</a>
<span th:text="'(' + ${contacts.size()} + ' total contacts)'"></span>
</p>
</div>
</body>
</html>
22 changes: 11 additions & 11 deletions src/main/resources/templates/contacts/new.html
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
<!DOCTYPE html>
<html lang="en" layout:decorate="~{layout}"
xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
xmlns:th="http://www.thymeleaf.org">
<head>
<title>New Contact</title>
<title>New Contact</title>
</head>
<body>
<div layout:fragment="content">
<h2>New Contact</h2>
<form action="/contacts" method="post">
<th:block th:replace="~{fragments/contact-fields::contact-fields}"></th:block>
<button type="submit">Save</button>
</form>
<p>
<a href="/contacts">Back</a>
</p>
<h2>New Contact</h2>
<form action="/contacts" method="post">
<th:block th:replace="~{fragments/contact-fields::contact-fields}"></th:block>
<button type="submit">Save</button>
</form>
<p>
<a href="/contacts">Back</a>
</p>
</div>
</body>
</html>
26 changes: 13 additions & 13 deletions src/main/resources/templates/contacts/view.html
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
<!DOCTYPE html>
<html layout:decorate="~{layout}" lang="en"
xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
<html lang="en" layout:decorate="~{layout}"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
xmlns:th="http://www.thymeleaf.org">
<head>
<title>View Contact</title>
<title>View Contact</title>
</head>
<body>
<!--/*@thymesVar id="contact" type="codes.yam.contacts.Contact"*/-->
<div layout:fragment="content">
<h1 th:text="${contact.first} + ' ' + ${contact.last}"></h1>
<div>
<p>Phone: <span th:text="${contact.phone}"></span></p>
<p>Email: <span th:text="${contact.email}"></span></p>
</div>
<p>
<a th:href="@{/contacts}">Back</a>
<a th:href="@{/contacts/{slug}/edit(slug=${contact.slug})}">Edit</a>
</p>
<h1 th:text="${contact.first} + ' ' + ${contact.last}"></h1>
<div>
<p>Phone: <span th:text="${contact.phone}"></span></p>
<p>Email: <span th:text="${contact.email}"></span></p>
</div>
<p>
<a th:href="@{/contacts}">Back</a>
<a th:href="@{/contacts/{slug}/edit(slug=${contact.slug})}">Edit</a>
</p>
</div>
</body>
</html>
11 changes: 5 additions & 6 deletions src/main/resources/templates/error.html
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
<!DOCTYPE html>
<html layout:decorate="~{layout}" lang="en"
xmlns:th="http://www.thymeleaf.org"
<html lang="en" layout:decorate="~{layout}"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
<head>
<title>Error</title>
<title>Error</title>
</head>
<body>
<div layout:fragment="content">
<h2>Something went wrong</h2>
<p>An unexpected error occurred. Please try again later.</p>
<a href="/contacts">Back to contacts</a>
<h2>Something went wrong</h2>
<p>An unexpected error occurred. Please try again later.</p>
<a href="/contacts">Back to contacts</a>
</div>
</body>
</html>
8 changes: 4 additions & 4 deletions src/main/resources/templates/error/404.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@
<html lang="en" layout:decorate="~{layout}"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
<head>
<title>Not Found</title>
<title>Not Found</title>
</head>
<body>
<div layout:fragment="content">
<h2>Page Not Found</h2>
<p>The page you were looking for doesn't exist.</p>
<a href="/contacts">Back to contacts</a>
<h2>Page Not Found</h2>
<p>The page you were looking for doesn't exist.</p>
<a href="/contacts">Back to contacts</a>
</div>
</body>
</html>
Loading