diff --git a/client/src/api-service/homeService.ts b/client/src/api-service/homeService.ts index 7d9bf47..a29c46e 100644 --- a/client/src/api-service/homeService.ts +++ b/client/src/api-service/homeService.ts @@ -1,11 +1,16 @@ import { API_TOKEN } from '../app-constants/app-constants'; +import { HomeSearchResponse } from '../types/HomeSearchResponse'; import { SummaryResponse } from '../types/SummaryResponse'; import ApiConfig from './apiConfig'; /** + * Sends a GET request to the server to get summaries for the home page. * + * @returns {Promise} A promise that resolves to SummaryResponse if the request + * was successful. + * @throws {Error} An error object if there was an error */ -async function getHomeSummary(): Promise { +async function getHomeSummary(): Promise { try { const tokenState = localStorage.getItem(API_TOKEN); const response = await fetch(`${ApiConfig.homeUrl}/summary`, { @@ -21,17 +26,53 @@ async function getHomeSummary(): Promise { return data; } if (response.status === 403) { - return new Error('Forbidden! Access denied'); + throw new Error('Forbidden! Access denied'); } if (response.status === 500) { - return new Error('Internal Server Error!'); + throw new Error('Internal Server Error!'); } } catch (e) { if (typeof e === 'string') { - return new Error(e as string); + throw new Error(e as string); } } - return new Error('Unknown error'); + throw new Error('Unknown error'); } -export { getHomeSummary }; +/** + * Sends a GET request to the server to get summaries for the home page. + * + * @returns {Promise} A promise that resolves to HomeSearchResponse if the + * request was successful. + * @throws {Error} An error object if there was an error + */ +async function searchHomeRequest(term: string): Promise { + try { + const tokenState = localStorage.getItem(API_TOKEN); + const response = await fetch(`${ApiConfig.homeUrl}/search?term=${term}`, { + method: 'GET', + mode: 'cors', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${tokenState}` + } + }); + if (response.ok) { + const data = await response.json(); + return data; + } + if (response.status === 403) { + throw new Error('Forbidden! Access denied'); + } + if (response.status === 500) { + throw new Error('Internal Server Error!'); + } + } catch (e) { + if (typeof e === 'string') { + throw new Error(e as string); + } + } + throw new Error('Unknown error'); +} + +export { getHomeSummary, searchHomeRequest }; diff --git a/client/src/types/HomeSearchResponse.ts b/client/src/types/HomeSearchResponse.ts new file mode 100644 index 0000000..cd3b655 --- /dev/null +++ b/client/src/types/HomeSearchResponse.ts @@ -0,0 +1,7 @@ +import { NoteResponse } from './NoteResponse'; +import { TaskResponse } from './TaskResponse'; + +export type HomeSearchResponse = { + tasks: TaskResponse[], + notes: NoteResponse[] +} diff --git a/client/src/views/Home/index.tsx b/client/src/views/Home/index.tsx index 0cb5428..fd13d59 100644 --- a/client/src/views/Home/index.tsx +++ b/client/src/views/Home/index.tsx @@ -1,11 +1,15 @@ import React, { useEffect, useState } from 'react'; import { + Accordion, Alert, Button, Card, Col, Container, Form, InputGroup, Row } from 'react-bootstrap'; import './style.css'; -import { getHomeSummary } from '../../api-service/homeService'; +import { getHomeSummary, searchHomeRequest } from '../../api-service/homeService'; import { SummaryResponse } from '../../types/SummaryResponse'; +import { HomeSearchResponse } from '../../types/HomeSearchResponse'; +import { TaskResponse } from '../../types/TaskResponse'; +import { NoteResponse } from '../../types/NoteResponse'; /** * @@ -15,6 +19,7 @@ function Home(): JSX.Element { const [summary, setSummary] = useState(); const [validated, setValidated] = useState(true); const [formInvalid, setFormInvalid] = useState(false); + const [searchResults, setSearchResults] = useState(null); const handleError = (e: unknown): void => { if (typeof e === 'string') { @@ -25,14 +30,25 @@ function Home(): JSX.Element { }; const getSummary = async () => { - const response = await getHomeSummary(); - if (response instanceof Error) { - handleError(response); - } else { + try { + const response = await getHomeSummary(); setSummary(response); + } catch (e) { + handleError(e); } }; + const searchTerm = async (term: string): Promise => { + try { + const response: HomeSearchResponse = await searchHomeRequest(term); + setSearchResults(response); + return true; + } catch (e) { + handleError(e); + } + return false; + }; + const handleSearch = async (event: React.FormEvent): Promise => { event.preventDefault(); event.stopPropagation(); @@ -41,15 +57,15 @@ function Home(): JSX.Element { const form = event.currentTarget; if (form.checkValidity() === false) { setFormInvalid(true); + setErrorMessage('Please type at least 3 characters'); return; } setFormInvalid(false); - // console.log('search for', form.search_term.value); - // const added: boolean = await addTask(form.description.value, form.url.value); - // if (added) { - // form.reset(); - // } + const searched: boolean = await searchTerm(form.search_term.value); + if (searched) { + form.reset(); + } }; useEffect(() => { @@ -58,11 +74,51 @@ function Home(): JSX.Element { return ( - +

Welcome to Your Dashboard

+ + + + + + Tasks Summary + + + + {summary?.pendingTaskCount || '0'} + + + {summary?.pendingTaskCount && summary?.pendingTaskCount > 0 + ? 'Pending Tasks' + : 'No pending tasks!'} + + + + + + + + + + Notes Summary + + + 10 + Notes + + + + + + + - Search task or note + Search Tasks and Notes {formInvalid ? ( @@ -78,51 +134,59 @@ function Home(): JSX.Element { type="text" id="search_term" name="search_term" - placeholder="Search term" + placeholder="Enter your search term..." /> - - 3 record(s) found! - - - - Tasks summary - - - {summary?.pendingTaskCount && summary?.pendingTaskCount > 0 - ? `${summary?.pendingTaskCount}` : 'Zero!'} - - - {summary?.pendingTaskCount && summary?.pendingTaskCount > 0 - ? `❗ ${summary?.pendingTaskCount} Pending Tasks` : 'No pending tasks!'} - - - - - {summary?.doneTaskCount && summary?.doneTaskCount > 0 - ? 'All tasks finished! Well done!' : '🤔 No tasks done yet!?'} - - - - - - Notes - - Notes summary - - 10 - - - - Test? - + + + +

Search Results

+ + + {searchResults && searchResults.tasks.length > 0 && ( + searchResults.tasks.map((task: TaskResponse) => ( + + + [Task] + {' '} + {task.description} + + + {task.urls.length > 0 ? ( + {task.urls[0].url} + ) : 'No URL!'} + + + )) + )} + {searchResults && searchResults.notes.length > 0 && ( + searchResults.notes.map((note: NoteResponse) => ( + + + [Note] + {' '} + {note.title} + + + + { note.description } + + + + )) + )} + {searchResults?.tasks.length === 0 && searchResults?.notes.length === 0 && ( +

No results

+ )} +
diff --git a/java-api/src/main/java/br/com/tasknoteapp/java_api/controller/HomeController.java b/java-api/src/main/java/br/com/tasknoteapp/java_api/controller/HomeController.java index 9b4e890..ec5d640 100644 --- a/java-api/src/main/java/br/com/tasknoteapp/java_api/controller/HomeController.java +++ b/java-api/src/main/java/br/com/tasknoteapp/java_api/controller/HomeController.java @@ -82,6 +82,5 @@ public class HomeController { @RequestParam(value = "term", required = false) String term) { return homeService.search(term); - // keep going from here } } diff --git a/java-api/src/main/java/br/com/tasknoteapp/java_api/response/SearchResponse.java b/java-api/src/main/java/br/com/tasknoteapp/java_api/response/SearchResponse.java index 5bb8414..c197e4f 100644 --- a/java-api/src/main/java/br/com/tasknoteapp/java_api/response/SearchResponse.java +++ b/java-api/src/main/java/br/com/tasknoteapp/java_api/response/SearchResponse.java @@ -2,9 +2,4 @@ package br.com.tasknoteapp.java_api.response; import java.util.List; -public record SearchResponse( - List tasks - //List notes -) { - -} +public record SearchResponse(List tasks, List notes) {} diff --git a/java-api/src/main/java/br/com/tasknoteapp/java_api/service/impl/HomeServiceImpl.java b/java-api/src/main/java/br/com/tasknoteapp/java_api/service/impl/HomeServiceImpl.java index 02daaff..a6ad519 100644 --- a/java-api/src/main/java/br/com/tasknoteapp/java_api/service/impl/HomeServiceImpl.java +++ b/java-api/src/main/java/br/com/tasknoteapp/java_api/service/impl/HomeServiceImpl.java @@ -1,9 +1,11 @@ package br.com.tasknoteapp.java_api.service.impl; +import br.com.tasknoteapp.java_api.response.NoteResponse; import br.com.tasknoteapp.java_api.response.SearchResponse; import br.com.tasknoteapp.java_api.response.SummaryResponse; import br.com.tasknoteapp.java_api.response.TaskResponse; import br.com.tasknoteapp.java_api.service.HomeService; +import br.com.tasknoteapp.java_api.service.NoteService; import br.com.tasknoteapp.java_api.service.TaskService; import java.util.List; import lombok.AllArgsConstructor; @@ -18,6 +20,8 @@ class HomeServiceImpl implements HomeService { private final TaskService taskService; + private final NoteService noteService; + /** * Get summary for the home page. * @@ -45,7 +49,11 @@ class HomeServiceImpl implements HomeService { log.info("Searching for {}", term); List tasks = taskService.searchTasks(term); + log.info("{} tasks found!", tasks.size()); - return new SearchResponse(tasks); + List notes = noteService.searchNotes(term); + log.info("{} notes found!", notes.size()); + + return new SearchResponse(tasks, notes); } } diff --git a/java-api/src/main/java/br/com/tasknoteapp/java_api/service/impl/NoteServiceImpl.java b/java-api/src/main/java/br/com/tasknoteapp/java_api/service/impl/NoteServiceImpl.java index 3e42c83..c8b9f07 100644 --- a/java-api/src/main/java/br/com/tasknoteapp/java_api/service/impl/NoteServiceImpl.java +++ b/java-api/src/main/java/br/com/tasknoteapp/java_api/service/impl/NoteServiceImpl.java @@ -143,7 +143,8 @@ public class NoteServiceImpl implements NoteService { log.info("Searching notes to user {}", user.getId()); - List notes = noteRepository.findAllBySearchTerm(searchTerm, user.getId()); + List notes = + noteRepository.findAllBySearchTerm(searchTerm.toUpperCase(), user.getId()); log.info("{} tasks found!", notes.size()); return notes.stream().map(NoteResponse::fromEntity).toList(); diff --git a/java-api/src/main/java/br/com/tasknoteapp/java_api/service/impl/TaskServiceImpl.java b/java-api/src/main/java/br/com/tasknoteapp/java_api/service/impl/TaskServiceImpl.java index 768ef88..a98f23d 100644 --- a/java-api/src/main/java/br/com/tasknoteapp/java_api/service/impl/TaskServiceImpl.java +++ b/java-api/src/main/java/br/com/tasknoteapp/java_api/service/impl/TaskServiceImpl.java @@ -144,7 +144,8 @@ class TaskServiceImpl implements TaskService { log.info("Searching tasks to user {}", user.getId()); - List tasks = taskRepository.findAllBySearchTerm(searchTerm, user.getId()); + List tasks = + taskRepository.findAllBySearchTerm(searchTerm.toUpperCase(), user.getId()); log.info("{} tasks found!", tasks.size()); return tasks.stream().map(TaskResponse::fromEntity).toList();