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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,4 @@ yarn-error.log*

# vercel
.vercel
/.vscode
42 changes: 33 additions & 9 deletions src/components/Dropdown/Dropdown.jsx
Original file line number Diff line number Diff line change
@@ -1,43 +1,67 @@
import { useRef, useState } from 'react';
import SearchDropdown from "./SearchDropdown"
import styles from './dropdown.module.scss';
import currencies from '../../data/currencies.json';
import { useState } from 'react';

const Dropdown = ({ currencyCode, currencySymbol, onCurrencyModify }) => {
const useFocus = () => {
const htmlElRef = useRef(null);
const setFocus = () => {
htmlElRef.current && htmlElRef.current.focus();
};
return [htmlElRef, setFocus];
};

const Dropdown = ({ currencyCode, currencySymbol, onCurrencyModify }) => {
const [suggestions, setSuggestions] = useState(currencies);
const [isActive, setIsActive] = useState(false);
const [inputRef, setInputFocus] = useFocus();

const handleClick = (currency) => {
const handleCurrencyClick = (currency) => {
onCurrencyModify(currency)
setIsActive(false);
}
const handleSelectSuggestion = (currency) => {
onCurrencyModify(currency);
setTimeout(() => {
setIsActive(false);
}, 100);
};
const handleDropdownClick = ()=>{
setIsActive(!isActive);
setTimeout(() => {
setInputFocus();
}, 100);
};

return (
<div className={styles.dropdown}>
<div
{!isActive? (<div
className={styles.dropdown__btn}
onClick={() => setIsActive(!isActive)}
onClick={handleDropdownClick}
>
<div className={styles.selected__currency}>
<span className={styles.code}>{currencyCode} </span>
<span>{currencySymbol}</span>
</div>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 256 256"><path d="M213.66,101.66l-80,80a8,8,0,0,1-11.32,0l-80-80A8,8,0,0,1,53.66,90.34L128,164.69l74.34-74.35a8,8,0,0,1,11.32,11.32Z"></path></svg>
</div>
</div>): (
<SearchDropdown handleChange={setSuggestions} selectSuggestion={handleSelectSuggestion} innerRef={inputRef} />
)}
{isActive && (
<div className={styles.dropdown__content}>
{currencies.map((currency, index) => (
{suggestions.map((currency, index) => (
currency.code === currencyCode
? <div
className={`${styles.dropdown__item} ${styles.accent}`}
key={index}
onClick={() => handleClick(currency)}>
onClick={() => handleCurrencyClick(currency)}>
<span className={styles.code}>{currency.code}</span>
<span className={styles.symbol}>{currency.symbol}</span>
</div>
: <div
className={styles.dropdown__item}
key={index}
onClick={() => handleClick(currency)}>
onClick={() => handleCurrencyClick(currency)}>
<span className={styles.code}>{currency.code}</span>
<span className={styles.symbol}>{currency.symbol}</span>
</div>
Expand Down
89 changes: 89 additions & 0 deletions src/components/Dropdown/SearchDropdown.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { useState, useEffect } from "react";
import styles from "./dropdown.module.scss";
import currencies from "../../data/currencies.json";
import Trie from "../../lib/trie";

const SearchDropdown = ({ innerRef, handleChange, selectSuggestion }) => {
const [prefix, setPrefix] = useState("");
const [suggestion, setSuggestion] = useState("");
const [suggestions, setSuggestions] = useState(currencies);
const myTrie = new Trie();

useEffect(() => {
handleChange(suggestions);
}, [suggestions]);

const addWords = () => {
currencies.forEach((currency) => {
const country = currency.country.toLowerCase();
myTrie.insert(country);
});
};
const filterBasedOnSuggestions = (found_words) => {
const temp = currencies.filter((currency) => {
return found_words.includes(currency.country.toLowerCase());
});
return temp;
};
const handleInputChange = (e) => {
const value = e.target.value;
setPrefix(value);

const words = value.split(" ");
const trie_prefix = words[words.length - 1].toLowerCase();
const found_words = myTrie.find(trie_prefix).sort((a, b) => {
return a.length - b.length;
});
const first_word = found_words[0];

if (
found_words.length !== 0 &&
value !== "" &&
value[value.length - 1] !== " "
) {
if (first_word != null) {
const remainder = first_word.slice(trie_prefix.length);
setSuggestion(value + remainder);
}
} else {
setSuggestion(value);
}
const suggestions = filterBasedOnSuggestions(found_words);
setSuggestions(suggestions);
};
const handleKeyDown = (e) => {
// Right button
if (e.keyCode === 39 || e.keyCode === 13) {
setPrefix(suggestion);
if (suggestions.length) {
selectSuggestion(suggestions[0]);
}
}
};

addWords();

return (
<div className={styles.inputs}>
<input
type="text"
name="search-bar"
className={styles.search_bar_1}
id="search_bar_1"
placeholder="Search Country..."
value={prefix}
onChange={handleInputChange}
onKeyDown={handleKeyDown}
ref={innerRef}
/>
<input
type="text"
name="search-bar"
className={styles.search_bar_2}
id="search_bar_2"
defaultValue={suggestion}
/>
</div>
);
};
export default SearchDropdown;
39 changes: 39 additions & 0 deletions src/components/Dropdown/dropdown.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
position: absolute;
top: 110%;
padding: 8px;
margin-top: 20px;
z-index: -2;
color: #333;
font-weight: 500;
background-color: #ffffff;
Expand Down Expand Up @@ -61,3 +63,40 @@
flex-grow: 1;
}
}

.inputs {
display: grid;
place-items: center;
position: relative;
margin-top: 1rem;

& input{
color: #333;
font-weight: bold;
padding: 12px 16px;
background-color: cornflowerblue;
background-color: #ffffff;
box-shadow: 3px 3px 10px 6px rgba(0,0,0,0.06);
display: flex;
align-items: center;
justify-content: space-between;
font-size: inherit;
// height: 2rem;
width: 16rem;
overflow-wrap: break-word;
border: none;
position: absolute;
word-wrap: break-word;
background-color: transparent;

&:focus {
outline: none;
}

&.search_bar_2 {
z-index: -1;
color: gray;
cursor: none;
}
}
}
Loading