-
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.
- Loading branch information
premell
committed
Aug 23, 2021
1 parent
8f3d9b2
commit d2180ba
Showing
64 changed files
with
6,461 additions
and
332 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
{ | ||
"presets": ["next/babel"], | ||
"plugins": [["styled-components", { "ssr": true }]] | ||
} |
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,225 @@ | ||
import { atom, selector } from "recoil"; | ||
import { recoilPersist } from "recoil-persist"; | ||
|
||
import { SORTING_METHODS, STATS } from "@/shared/constants" | ||
|
||
const { persistAtom } = recoilPersist(); | ||
|
||
// export const popupMessage = atom({ | ||
// key: "popupMessage", | ||
// default: { | ||
// show: false, | ||
// message: "hello", | ||
// type: "positive", | ||
// }, | ||
// }); | ||
|
||
|
||
// export const numberOfMatchedPokemon = atom({ | ||
// key: "numberOfMatchedPokemon", | ||
// default: 0 | ||
// }); | ||
|
||
export const pokemonPerPage = atom({ | ||
key: "pokemonPerPage", | ||
default: 20 | ||
}); | ||
|
||
export const currentPage = atom({ | ||
key: "currentPage", | ||
default: 1 | ||
}); | ||
|
||
export const priceFilter = atom({ | ||
key: "priceFilter", | ||
default: { | ||
currentRange: { | ||
min: 0, | ||
max: 2500, | ||
}, | ||
range: { | ||
min: 0, | ||
max: 2500, | ||
}, | ||
isFiltering: false, | ||
}, | ||
}); | ||
|
||
export const statsFilter = atom({ | ||
key: "statsFilter", | ||
default: { | ||
ATTACK: { | ||
name: STATS.ATTACK, | ||
currentRange: { | ||
min: 0, | ||
max: 200, | ||
}, | ||
range: { | ||
min: 0, | ||
max: 200, | ||
}, | ||
isFiltering: false, | ||
}, | ||
DEFENSE: { | ||
name: STATS.DEFENSE, | ||
currentRange: { | ||
min: 0, | ||
max: 250, | ||
}, | ||
range: { | ||
min: 0, | ||
max: 250, | ||
}, | ||
isFiltering: false, | ||
}, | ||
HP: { | ||
name: STATS.HP, | ||
currentRange: { | ||
min: 0, | ||
max: 300, | ||
}, | ||
range: { | ||
min: 0, | ||
max: 300, | ||
}, | ||
isFiltering: false, | ||
}, | ||
SPECIAL_ATTACK: { | ||
name: STATS.SPECIAL_ATTACK, | ||
currentRange: { | ||
min: 0, | ||
max: 200, | ||
}, | ||
range: { | ||
min: 0, | ||
max: 200, | ||
}, | ||
isFiltering: false, | ||
}, | ||
SPECIAL_DEFENSE: { | ||
name: STATS.SPECIAL_DEFENSE, | ||
currentRange: { | ||
min: 0, | ||
max: 300, | ||
}, | ||
range: { | ||
min: 0, | ||
max: 300, | ||
}, | ||
isFiltering: false, | ||
}, | ||
SPEED: { | ||
name: STATS.SPEED, | ||
currentRange: { | ||
min: 0, | ||
max: 200, | ||
}, | ||
range: { | ||
min: 0, | ||
max: 200, | ||
}, | ||
isFiltering: false, | ||
} | ||
}, | ||
}); | ||
|
||
export const typeFilter = atom({ | ||
key: "typeFilter", | ||
default: { | ||
types: [ | ||
], | ||
isFiltering: false, | ||
}, | ||
}); | ||
|
||
export const abilityFilter = atom({ | ||
key: "abilityFilter", | ||
default: { | ||
abilities: [ | ||
], | ||
isFiltering: false, | ||
}, | ||
}); | ||
|
||
export const anyFilterActive = selector({ | ||
key: 'anyFilterActive', | ||
get: ({ get }) => { | ||
let isFiltering = false | ||
if (get(abilityFilter).isFiltering) isFiltering = true | ||
else if (get(typeFilter).isFiltering) isFiltering = true | ||
else if (get(priceFilter).isFiltering) isFiltering = true | ||
const localStatsFilter = get(statsFilter) | ||
Object.keys(localStatsFilter).forEach((key) => { | ||
if (localStatsFilter[key].isFiltering) isFiltering = true | ||
}) | ||
return isFiltering | ||
} | ||
}); | ||
|
||
export const searchQuery = atom({ | ||
key: "searchQuery", | ||
default: "" | ||
}); | ||
|
||
export const sortingMethod = atom({ | ||
key: "sortingMethod", | ||
default: SORTING_METHODS.RELEASE_OLDEST_FIRST | ||
|
||
}) | ||
|
||
// export const sortedPokemon = atom({ | ||
// key: "sortedPokemon ", | ||
// default: [] | ||
// }) | ||
|
||
|
||
export const favorites = atom({ | ||
key: "favorites", | ||
default: { | ||
pokemon: { | ||
}, | ||
} | ||
}); | ||
|
||
export const cart = atom({ | ||
key: "cart", | ||
default: { | ||
pokemon: [], | ||
total: 0, | ||
} | ||
}); | ||
|
||
|
||
// export const generalModalMessage = atom({ | ||
// key: "generalModalMessage ", | ||
// default: { | ||
// message: "", | ||
// show: false, | ||
// type: "positive", | ||
// } | ||
// }) | ||
|
||
export const numberOfMatchedPokemon = atom({ | ||
key: "numberOfMatchedPokemon", | ||
default: 1000, | ||
}) | ||
|
||
export const showModalTemporarily = atom({ | ||
key: "showModalTemporarily", | ||
default: false | ||
}) | ||
|
||
export const showModalWithTimer = atom({ | ||
key: "showModalWithTimer", | ||
default: false | ||
}) | ||
|
||
export const showCartModal = atom({ | ||
key: "showCartModal", | ||
default: false | ||
}) | ||
|
||
export const showCartModalInstantly = atom({ | ||
key: "showCartModalInstantly", | ||
default: true | ||
}) |
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,23 @@ | ||
import { Links, BoldRegularText } from "shared/components"; | ||
|
||
import styled from "styled-components"; | ||
|
||
const StyledFooter = styled.div` | ||
color: white; | ||
background-color: ${(p) => p.theme.colors.gray_100}; | ||
height: 300px; | ||
width: 100%; | ||
`; | ||
|
||
const Footer = () => { | ||
return ( | ||
<StyledFooter> | ||
<p>This is a pokemon website</p> | ||
<BoldRegularText>Contact me</BoldRegularText> | ||
<p>Email: [email protected]</p> | ||
<Links /> | ||
</StyledFooter> | ||
); | ||
}; | ||
|
||
export default Footer; |
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 styled from "styled-components"; | ||
import { useRouter } from "next/router"; | ||
|
||
import { useEffect } from "react"; | ||
import Navbar from "./Navbar"; | ||
import Footer from "./Footer"; | ||
|
||
import { useCartModal } from "shared/hooks"; | ||
|
||
const MainContainer = styled.div` | ||
width: 100vw; | ||
display: flex; | ||
flex-direction: column; | ||
justify-content: center; | ||
align-items: center; | ||
background-color: ${(p) => p.theme.colors.gray_10}; | ||
`; | ||
|
||
const MainContent = styled.div` | ||
width: 100%; | ||
max-width: 1900px; | ||
margin-top: 76px; | ||
`; | ||
const Layout = ({ children }) => { | ||
const router = useRouter(); | ||
|
||
const { hideWithTimer, hideTemporarly, hideInstantly } = useCartModal(); | ||
|
||
useEffect(() => { | ||
hideWithTimer(); | ||
hideTemporarly(); | ||
hideInstantly(); | ||
}, [router.asPath]); | ||
|
||
return ( | ||
<MainContainer> | ||
<Navbar /> | ||
<MainContent>{children}</MainContent> | ||
<Footer /> | ||
</MainContainer> | ||
); | ||
}; | ||
export default Layout; |
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,92 @@ | ||
import { useRecoilState, useResetRecoilState } from "recoil"; | ||
import { priceFilter as priceFilterAtoms } from "atoms.js"; | ||
import { statsFilter as statsFilterAtoms } from "atoms.js"; | ||
import { typeFilter as typeFilterAtoms } from "atoms.js"; | ||
import { abilityFilter as abilityFilterAtoms } from "atoms.js"; | ||
|
||
import { PriceFilterFlair, NumberFilterFlair, FilterBox, Cross, AbilityFilterFlair, StyledFilterContainer, RemoveAllFilters } from "./Styles" | ||
import TypeFlair from "@/shared/TypeFlair" | ||
import { useEffect } from "react"; | ||
|
||
import { formatAsUSDWithoutTrailingZeros } from "shared/javascript" | ||
|
||
|
||
const FilterPanel = () => { | ||
|
||
const [priceFilter, setPriceFilter] = useRecoilState(priceFilterAtoms); | ||
const [statsFilter, setStatsFilter] = useRecoilState(statsFilterAtoms); | ||
const [typeFilter, setTypeFilter] = useRecoilState(typeFilterAtoms); | ||
const [abilityFilter, setAbilityFilter] = useRecoilState(abilityFilterAtoms); | ||
|
||
const defaultPriceFilter = useResetRecoilState(priceFilterAtoms) | ||
const defaultStatsFilter = useResetRecoilState(statsFilterAtoms) | ||
const defaultTypeFilter = useResetRecoilState(typeFilterAtoms) | ||
const defaultAbilityFilter = useResetRecoilState(abilityFilterAtoms) | ||
const removeAllFilters = () => { | ||
defaultPriceFilter() | ||
defaultStatsFilter() | ||
defaultTypeFilter() | ||
defaultAbilityFilter() | ||
} | ||
|
||
const removePrice = () => { | ||
//setPriceFilter({ ...priceFilter, currentRange: { min: 0, max: 2500 }, isFiltering: false }) | ||
defaultPriceFilter() | ||
} | ||
|
||
const removeStat = (stat) => { | ||
setStatsFilter(statsFilter => ({ ...statsFilter, [stat]: { ...statsFilter.[stat], currentRange: statsFilter.[stat].range, isFiltering: false } })) | ||
} | ||
|
||
const removeType = (type) => { | ||
const updatedTypes = typeFilter.types.filter((arrayType) => arrayType !== type) | ||
let isFiltering = true | ||
if (updatedTypes.length === 0) isFiltering = false | ||
setTypeFilter({ types: updatedTypes, isFiltering: isFiltering }) | ||
} | ||
|
||
const removeAbility = (ability) => { | ||
const updatedAbilities = abilityFilter.abilities.filter((arrayAbility) => arrayAbility !== ability) | ||
let isFiltering = true | ||
if (updatedAbilities.length === 0) isFiltering = false | ||
setAbilityFilter({ abilities: updatedAbilities, isFiltering: isFiltering }) | ||
} | ||
|
||
const getIsAnyFilterActive = () => { | ||
let isActive = false | ||
if (abilityFilter.isFiltering) isActive = true | ||
else if (typeFilter.isFiltering) isActive = true | ||
else if (priceFilter.isFiltering) isActive = true | ||
|
||
Object.keys(statsFilter).forEach((key) => { | ||
if (statsFilter[key].isFiltering) isActive = true | ||
}) | ||
return isActive | ||
} | ||
|
||
const isAnyFilterActive = getIsAnyFilterActive() | ||
|
||
|
||
|
||
//return <RegularText style={{ margin: 0 }}>{`Price: ${formatAsUSDWithoutTrailingZeros(min)} - ${formatAsUSDWithoutTrailingZeros(max)}`}</RegularText> | ||
//<Cross handleClick={removePrice} /> | ||
return ( | ||
<StyledFilterContainer> | ||
{priceFilter.isFiltering && <FilterBox handleClick={removePrice} text={`Price: ${formatAsUSDWithoutTrailingZeros(priceFilter.currentRange.min)} - ${formatAsUSDWithoutTrailingZeros(priceFilter.currentRange.max)}`} />} | ||
{typeFilter.isFiltering && typeFilter.types.map((type) => <FilterBox handleClick={() => removeType(type)} text={type} />)} | ||
{abilityFilter.isFiltering && abilityFilter.abilities.map((ability) => <FilterBox handleClick={() => removeAbility(ability)} text={ability} />)} | ||
{Object.keys(statsFilter).map((key) => { | ||
if (statsFilter[key].isFiltering) return ( | ||
<FilterBox handleClick={() => removeStat(key)} text={`${statsFilter[key].name}: ${statsFilter[key].currentRange.min} - ${statsFilter[key].currentRange.max}`} /> | ||
) | ||
} | ||
)} | ||
{isAnyFilterActive ? <RemoveAllFilters handleClick={removeAllFilters} /> : null} | ||
</StyledFilterContainer> | ||
) | ||
} | ||
// <FilterBox key={key}><NumberFilterFlair min={statsFilter[key].currentRange.min} | ||
// max={statsFilter[key].currentRange.max} name={statsFilter[key].name} /> <Cross handleClick={() => removeStat(key)} /></FilterBox> | ||
// ) | ||
|
||
export default FilterPanel |
Oops, something went wrong.