Skip to content
Merged
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
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(name = "selected_contact_slugs", required = false)
List<String> selectedContactSlugs) {
if (selectedContactSlugs != null && !selectedContactSlugs.isEmpty()) {
contactService.deleteMany(selectedContactSlugs);
}
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