generated from USNightOwl/reactjs-vite-tailwindcss-boilerplate
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
✨ feat: handle search word in dictionary
- Loading branch information
Showing
16 changed files
with
374 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
import { IconButton, Input, InputGroup, InputRightElement } from "@chakra-ui/react"; | ||
import { Search } from "lucide-react"; | ||
import React from "react"; | ||
import { useNavigate } from "react-router-dom"; | ||
|
||
type Props = { | ||
word: string; | ||
}; | ||
|
||
const SearchBar = ({ word }: Props) => { | ||
const navigate = useNavigate(); | ||
const [searchText, setSearchText] = React.useState(word); | ||
const handleSearch = (e: React.FormEvent) => { | ||
e.preventDefault(); | ||
navigate("/dictionary?q=" + searchText); | ||
}; | ||
|
||
return ( | ||
<form onSubmit={handleSearch}> | ||
<InputGroup size="md" width="400px"> | ||
<Input | ||
pr="4.5rem" | ||
placeholder="Search dictionary" | ||
value={searchText} | ||
onChange={(e) => setSearchText(e.target.value)} | ||
/> | ||
<InputRightElement width="4.5rem"> | ||
<IconButton | ||
w="3rem" | ||
size="sm" | ||
bgColor="transparent" | ||
_hover={{ bg: "rgba(0, 0,0, 0.04)" }} | ||
aria-label="Search dictionary" | ||
icon={<Search className="w-5 h-5" />} | ||
type="submit" | ||
/> | ||
</InputRightElement> | ||
</InputGroup> | ||
</form> | ||
); | ||
}; | ||
|
||
export default SearchBar; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
import { Volume2 } from "lucide-react"; | ||
import { Box, Code, Heading, HStack, IconButton, Text, VStack } from "@chakra-ui/react"; | ||
import { IWord, IWordNotFound } from "@/types/dictionary"; | ||
|
||
type Props = { | ||
wordFound: IWord[] | undefined; | ||
wordNotFound: IWordNotFound | undefined; | ||
}; | ||
|
||
const WordResult = ({ wordFound, wordNotFound }: Props) => { | ||
return ( | ||
<> | ||
{wordFound && ( | ||
<> | ||
<VStack alignItems="flex-start" gap="0px"> | ||
<Heading marginY="5px">{wordFound[0].word}</Heading> | ||
{wordFound[0].phonetics | ||
.filter((e) => e.audio != "") | ||
.map((phonetic, index) => ( | ||
<HStack key={`sound${index}`} alignItems="center" gap="16px"> | ||
<IconButton | ||
aria-label="audio button" | ||
icon={<Volume2 className="text-cyan-800" />} | ||
bg="transparent" | ||
_hover={{ bg: "rgba(0, 0, 0, 0.04)" }} | ||
onClick={() => new Audio(phonetic.audio).play()} | ||
/> | ||
<Text> | ||
<Code fontSize="1em">{phonetic.text}</Code> | ||
</Text> | ||
</HStack> | ||
))} | ||
</VStack> | ||
{wordFound.map((wordFound, index) => ( | ||
<VStack key={index} gap={"32px"} alignItems="flex-start" marginTop={"20px"}> | ||
{wordFound.meanings.map((meaning, index) => ( | ||
<VStack key={`meaning${index}`} gap={"16px"} alignItems="flex-start"> | ||
<Heading size="lg" color={"blue.900"}> | ||
{meaning.partOfSpeech} | ||
</Heading> | ||
{meaning.definitions.map((definition, index) => ( | ||
<Box key={`definition${index}`} gap={"16px"}> | ||
<Text>{definition.definition}</Text> | ||
{definition.example && ( | ||
<HStack alignItems={"flex-start"}> | ||
<Text fontWeight="bold" color="blue.900"> | ||
Example: | ||
</Text> | ||
<Text>{definition.example}</Text> | ||
</HStack> | ||
)} | ||
</Box> | ||
))} | ||
</VStack> | ||
))} | ||
</VStack> | ||
))} | ||
</> | ||
)} | ||
{wordNotFound && ( | ||
<VStack alignItems="flex-start" gap={"10px"} marginY={"40px"}> | ||
<Heading variant="h1">{wordNotFound.title}</Heading> | ||
<VStack alignItems="flex-start" gap={"4px"}> | ||
<Text variant="subtitle1">{wordNotFound.message}</Text> | ||
<Text variant="subtitle1">{wordNotFound.resolution}</Text> | ||
</VStack> | ||
</VStack> | ||
)} | ||
</> | ||
); | ||
}; | ||
|
||
export default WordResult; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import { AxiosResponse } from "axios"; | ||
import AxiosClient from "./axios"; | ||
|
||
export const searchWord = async (word: string) => { | ||
const response: AxiosResponse = await AxiosClient.get(`/${word}`); | ||
if (response.status == 404) { | ||
return response.data; | ||
} | ||
if (response.status != 200) { | ||
throw new Error("Something went wrong"); | ||
} | ||
return response; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import axios from "axios"; | ||
import { setupInterceptors } from "./interceptor"; | ||
|
||
const AxiosClient = axios.create({ | ||
baseURL: "https://api.dictionaryapi.dev/api/v2/entries/en", | ||
headers: { | ||
Accept: "application/json", | ||
}, | ||
}); | ||
|
||
setupInterceptors(AxiosClient); | ||
|
||
export default AxiosClient; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import { AxiosError, AxiosInstance, AxiosResponse, InternalAxiosRequestConfig } from "axios"; | ||
|
||
interface IRequestAxios extends InternalAxiosRequestConfig { | ||
skipLoading?: boolean; | ||
} | ||
|
||
const onRequestConfig = (config: IRequestAxios) => { | ||
if (!config.headers["Content-Type"]) { | ||
config.headers["Content-Type"] = "application/json"; | ||
} | ||
config.timeout = 30000; | ||
return config; | ||
}; | ||
|
||
const onRequestError = (error: AxiosError): Promise<AxiosError> => { | ||
return Promise.reject(error); | ||
}; | ||
|
||
const onResponse = (res: AxiosResponse): AxiosResponse => { | ||
return res; | ||
}; | ||
|
||
const onResponseError = async (err: AxiosError): Promise<AxiosError | undefined> => { | ||
return Promise.reject(err?.response?.data); | ||
}; | ||
|
||
export const setupInterceptors = (axiosInstance: AxiosInstance) => { | ||
axiosInstance.interceptors.request.use(onRequestConfig, onRequestError); | ||
axiosInstance.interceptors.response.use(onResponse, (err: AxiosError) => onResponseError(err)); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
import SearchBar from "@/components/search-bar/SearchBar"; | ||
import WordResult from "@/components/word-result/WordResult"; | ||
import { searchWord } from "@/config/api/dictionary/apiDictionary"; | ||
import { IWord, IWordNotFound } from "@/types/dictionary"; | ||
import { HStack } from "@chakra-ui/react"; | ||
import { AxiosResponse } from "axios"; | ||
import React from "react"; | ||
import { useSearchParams } from "react-router-dom"; | ||
|
||
const DictionaryPage = () => { | ||
const [searchParams] = useSearchParams(); | ||
const [word, setWord] = React.useState<string>(""); | ||
const [wordFound, setWordFound] = React.useState<IWord[]>(); | ||
const [wordNotFound, setWordNotFound] = React.useState<IWordNotFound>(); | ||
|
||
React.useEffect(() => { | ||
if (!searchParams.has("q")) return; | ||
setWord(searchParams.get("q")!); | ||
// handle search words | ||
searchWord(searchParams!.get("q")!) | ||
.then((res: AxiosResponse) => { | ||
setWordFound(res.data as IWord[]); | ||
setWordNotFound(undefined); | ||
}) | ||
.catch((err) => { | ||
console.log(err); | ||
setWordFound(undefined); | ||
setWordNotFound({ | ||
title: "No Definitions Found", | ||
message: "Sorry pal, we couldn't find definitions for the word you were looking for.", | ||
resolution: "You can try the search again at later time or head to the web instead", | ||
} as IWordNotFound); | ||
}); | ||
}, [searchParams]); | ||
|
||
return ( | ||
<> | ||
<HStack justifyContent="center" marginY="15px"> | ||
<SearchBar word={word} /> | ||
</HStack> | ||
<WordResult wordFound={wordFound} wordNotFound={wordNotFound} /> | ||
</> | ||
); | ||
}; | ||
|
||
export default DictionaryPage; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
const FlashCardSetsPage = () => { | ||
return <div>FlashCardSetsPage</div>; | ||
}; | ||
|
||
export default FlashCardSetsPage; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
const LearnFlashCardPage = () => { | ||
return <div>LearnFlashCardPage</div>; | ||
}; | ||
|
||
export default LearnFlashCardPage; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
const GrammarCheckPage = () => { | ||
return <div>GrammarCheckPage</div>; | ||
}; | ||
|
||
export default GrammarCheckPage; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
const LearnThroughImagesPage = () => { | ||
return <div>LearnThroughImagesPage</div>; | ||
}; | ||
|
||
export default LearnThroughImagesPage; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
const SpellCheckPage = () => { | ||
return <div>SpellCheckPage</div>; | ||
}; | ||
|
||
export default SpellCheckPage; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
export type IWordNotFound = { | ||
title: string; | ||
message: string; | ||
resolution: string; | ||
}; | ||
|
||
export type IWord = { | ||
word: string; | ||
phonetic: string; | ||
phonetics: { | ||
text: string; | ||
audio: string; | ||
sourceUrl: string; | ||
license?: { | ||
name: string; | ||
url: string; | ||
}; | ||
}[]; | ||
meanings: { | ||
partOfSpeech: string; | ||
definitions: { | ||
definition: string; | ||
synonyms: string[]; | ||
antonyms: string[]; | ||
example?: string; | ||
}[]; | ||
synonyms: string[]; | ||
antonyms: string[]; | ||
}[]; | ||
license: { | ||
name: string; | ||
url: string; | ||
}; | ||
sourceUrls: string[]; | ||
}; |
Oops, something went wrong.