-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Pull request to make a code review #1
base: release_1
Are you sure you want to change the base?
Changes from 60 commits
56dfa24
72f4eb4
493b6fd
0377ce8
96c7090
5dc6739
013a2ca
fca218e
3a6ba10
ff2ed21
38fd092
f687773
d447c11
c5cad12
bf59be7
e2e947c
b59e49a
ad62c6d
0cbe43e
733ab38
0ea9771
e00444e
63543f3
25e2d33
b13c50f
7cf3588
9159357
a97c136
947cb13
9ae2a41
2edd12c
8920f95
cc634de
51e83f2
3352b8a
8169104
52642d4
e9bbd79
f79ba71
de5ec20
3c6f8b1
0dcbada
58b9453
e7bfcf4
fad621b
c124506
ddc4058
f23297b
3563cf1
5500ffd
16d59de
1979606
dfe55a7
445c906
1280f5f
e1b9009
97678e3
80d13b4
4c1274b
287c4cc
a5a27c9
722fbb9
b0bb14b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
{ | ||
"presets": [ | ||
"@babel/preset-env", | ||
"@babel/preset-react", | ||
"@babel/preset-typescript" | ||
] | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
root = true | ||
|
||
[*] | ||
charset = utf-8 | ||
end_of_line = lf | ||
insert_final_newline = true | ||
indent_size = 2 | ||
indent_style = tab |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
node_modules/ | ||
.vscode | ||
yarn-error.log | ||
.DS_Store | ||
.env |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
// declaration.d.ts | ||
declare module '*.css' { | ||
const content: Record<string, string>; | ||
export default content; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
{ | ||
"name": "bank-account", | ||
"version": "1.0.0", | ||
"main": "index.js", | ||
"repository": "git@github.com:KhristenkoE/bank-account.git", | ||
"author": "Eugene Khristenko <ekhristenko0@gmail.com>", | ||
"license": "MIT", | ||
"scripts": { | ||
"start": "webpack serve --config webpack.config.js --mode development --hot", | ||
"build": "webpack --mode production" | ||
}, | ||
"devDependencies": { | ||
"@babel/core": "^7.17.2", | ||
"@babel/preset-env": "^7.16.11", | ||
"@babel/preset-react": "^7.16.7", | ||
"@babel/preset-typescript": "^7.18.6", | ||
"@types/react": "^18.0.15", | ||
"@types/react-dom": "^18.0.6", | ||
"@types/uuid": "^8.3.4", | ||
"babel-loader": "^8.2.3", | ||
"css-loader": "^6.7.1", | ||
"html-webpack-plugin": "^5.5.0", | ||
"react": "^17.0.2", | ||
"react-dom": "^17.0.2", | ||
"style-loader": "^3.3.1", | ||
"typescript": "^4.7.4", | ||
"uuid": "^8.3.2", | ||
"webpack": "^5.68.0", | ||
"webpack-cli": "^4.9.2", | ||
"webpack-dev-server": "^4.9.3", | ||
"react-router-dom": "6" | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import React from 'react'; | ||
import { Route, Routes } from 'react-router-dom'; | ||
import BreadcrumbsContextProvider from '../../contexts/BreadcrumbsContext'; | ||
import DataContext, { initialContext as initialDataContext } from '../../contexts/DataContext'; | ||
import FiltersContextProvider from '../../contexts/FiltersContext'; | ||
import CardDetails from '../../pages/CardDetails/CardDetails'; | ||
import CardsList from '../../pages/CardsList/CardsList'; | ||
import Home from '../../pages/Home/Home'; | ||
import TransactionDetails from '../../pages/TransactionDetails/TransactionDetails'; | ||
import TransactionsList from '../../pages/TransactionsList/TransactionsList'; | ||
import _404 from '../../pages/_404/_404'; | ||
import Breadcrumbs from '../Breadcrumbs/Breadcrumbs'; | ||
|
||
const App = () => { | ||
return ( | ||
<DataContext.Provider value={initialDataContext}> | ||
<FiltersContextProvider> | ||
<BreadcrumbsContextProvider> | ||
<Breadcrumbs /> | ||
<Routes> | ||
<Route path="transactions" element={<TransactionsList />} /> | ||
<Route path="transactions/:transactionID" element={<TransactionDetails />} /> | ||
<Route path="transactions/:transactionID/:cardID" element={<CardDetails />} /> | ||
<Route path="cards" element={<CardsList />} /> | ||
<Route path="cards/:cardID" element={<CardDetails />} /> | ||
<Route path="cards/:cardID/transactions" element={<TransactionsList />} /> | ||
<Route path="cards/:cardID/transactions/:transactionID" element={<TransactionDetails />} /> | ||
<Route path="/" element={<Home />} /> | ||
<Route path="*" element={<_404 />} /> | ||
</Routes> | ||
</BreadcrumbsContextProvider> | ||
</FiltersContextProvider> | ||
</DataContext.Provider> | ||
) | ||
}; | ||
|
||
export default App; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
.list { | ||
padding: 20px 20px; | ||
margin: 0; | ||
display: flex; | ||
list-style: none; | ||
} | ||
|
||
.list li { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not too good to use specific selectors (like |
||
margin-right: 10px; | ||
position: relative; | ||
} | ||
|
||
.list li button { | ||
border: none; | ||
background-color: transparent; | ||
color: #959595; | ||
cursor: pointer; | ||
} | ||
|
||
.list li button.breadcrumbActive { | ||
color: white; | ||
cursor: default; | ||
} | ||
|
||
.list li:not(:last-child):before { | ||
content: ''; | ||
position: absolute; | ||
height: 5px; | ||
width: 5px; | ||
background: #27303c; | ||
border-radius: 100%; | ||
top: 50%; | ||
transform: translateY(-1px); | ||
right: -7px; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import React, { useContext } from 'react'; | ||
import { useNavigate } from 'react-router-dom'; | ||
import { BreadcrumbsContext } from '../../contexts/BreadcrumbsContext'; | ||
import styles from './Breadcrumbs.module.css'; | ||
|
||
const Breadcrumbs = () => { | ||
const { breadcrumbs } = useContext(BreadcrumbsContext); | ||
const navigate = useNavigate(); | ||
|
||
const onBreadcrumbClick = (url: string, index: number) => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
navigate(url); | ||
} | ||
|
||
return ( | ||
<nav> | ||
<ul className={styles.list}> | ||
{breadcrumbs.map(({ url, name }, index) => ( | ||
<li key={index}> | ||
<button className={index === breadcrumbs.length - 1 ? styles.breadcrumbActive : ''} onClick={() => onBreadcrumbClick(url, index)}>{name}</button> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For this libraries like "class names" can be used https://www.npmjs.com/package/classnames |
||
</li> | ||
))} | ||
</ul> | ||
</nav> | ||
); | ||
}; | ||
|
||
export default Breadcrumbs; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
.filterButton { | ||
padding: 10px 20px; | ||
background-color: #141921; | ||
border-radius: 5px; | ||
text-decoration: none; | ||
color: inherit; | ||
border: none; | ||
position: relative; | ||
} | ||
|
||
.filterButton:hover { | ||
cursor: pointer; | ||
transform: scale(1.01); | ||
background-color: #1d232e; | ||
} | ||
|
||
.filterButtonIndicate::before { | ||
content: ''; | ||
position: absolute; | ||
top: 5px; | ||
right: 7px; | ||
width: 5px; | ||
height: 5px; | ||
background-color: #b0104b; | ||
border-radius: 100%; | ||
} | ||
|
||
.filtersBlock { | ||
background-color: #202630; | ||
display: block; | ||
/* overflow: hidden; */ | ||
border-radius: 5px; | ||
/* animation: show-filters 0.5s; */ | ||
/* animation-fill-mode: forwards; */ | ||
} | ||
|
||
.filtersBlockContent { | ||
padding: 20px 20px; | ||
/* animation: show-filter-contnet 0.5s; */ | ||
/* opacity: 0; */ | ||
/* animation-delay: 0.2s; | ||
animation-fill-mode: forwards; */ | ||
} | ||
|
||
.filterBlockClosed { | ||
/* animation: hide-filters 0.5s; | ||
animation-fill-mode: forwards; */ | ||
display: none; | ||
} | ||
|
||
/* @keyframes show-filter-contnet { | ||
0% { | ||
opacity: 0; | ||
} | ||
100% { | ||
opacity: 1; | ||
} | ||
} | ||
|
||
@keyframes show-filters { | ||
0% { | ||
height: 0; | ||
} | ||
100% { | ||
height: 100%; | ||
} | ||
} | ||
|
||
@keyframes hide-filters { | ||
0% { | ||
height: 100%; | ||
} | ||
|
||
100% { | ||
height: 0; | ||
} | ||
} */ | ||
|
||
|
||
.title { | ||
margin: 0 0 20px 0; | ||
} | ||
|
||
.list { | ||
margin: 0 0 20px 0; | ||
padding: 0; | ||
list-style: none; | ||
display: grid; | ||
column-gap: 40px; | ||
row-gap: 10px; | ||
} | ||
|
||
.filter { | ||
display: grid; | ||
grid-auto-flow: column; | ||
column-gap: 10px; | ||
justify-content: flex-start; | ||
} | ||
|
||
.clearFilters { | ||
border: none; | ||
border-radius: 5px; | ||
padding: 5px 12px; | ||
background-color: #c6cfde; | ||
cursor: pointer; | ||
} | ||
|
||
.clearFilters:hover { | ||
background-color: #e6eaf1; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
import React, { useEffect, useRef, useState } from 'react'; | ||
import ReactDOM from 'react-dom'; | ||
import { AppliedFilter, Filter as FilterInterface, FilterName, FilterType } from '../../interfaces/Filter'; | ||
import styles from './Filter.module.css'; | ||
import FilterDate from './FilterDate/FilterDate'; | ||
import FilterRange from './FilterRange/FilterRange'; | ||
import FilterSelect from './FilterSelect/FilterSelect'; | ||
|
||
interface Props { | ||
filters: FilterInterface[]; | ||
intialAppliedFilters: AppliedFilter; | ||
onChange(value: string | { min: number, max: number }, name: string, type: FilterType): void; | ||
onClear(): void; | ||
} | ||
|
||
const Filter = ({ | ||
filters, | ||
intialAppliedFilters, | ||
onChange, | ||
onClear, | ||
}: Props) => { | ||
const [isOpen, setIsOpen] = useState(false); | ||
const filterContainerRef = useRef<HTMLElement>(null); | ||
|
||
useEffect(() => { | ||
filterContainerRef.current = document.getElementById('filters-block'); | ||
}, []); | ||
|
||
const onChangeSelect = (value: string, name: string, type: FilterType) => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. line: 29, 33, 37 - not required function mapping. |
||
onChange(value, name, type); | ||
}; | ||
|
||
const onRangeChange = (value: { min: number, max: number }, name: string, type: FilterType) => { | ||
onChange(value, name, type); | ||
}; | ||
|
||
const onDateChange = (value: string, name: string, type: FilterType) => { | ||
onChange(value, name, type); | ||
}; | ||
|
||
return ( | ||
<article> | ||
<button onClick={() => setIsOpen((isOpenPrev) => !isOpenPrev)} className={`${styles.filterButton} ${Object.keys(intialAppliedFilters).length ? styles.filterButtonIndicate : ''}`}>Filters</button> | ||
{filterContainerRef.current && ReactDOM.createPortal( | ||
<article className={`${styles.filtersBlock} ${!isOpen ? styles.filterBlockClosed : ''}`}> | ||
<div className={styles.filtersBlockContent}> | ||
<h4 className={styles.title}>Filters</h4> | ||
<ul className={styles.list}> | ||
{filters.map(({ label, name, options, from, to, type }) => { | ||
return ( | ||
<li className={styles.filter} key={label}> | ||
<label htmlFor={label}>{name}</label> | ||
{type === FilterType.SELECT_ONE && ( | ||
<FilterSelect initialValue={(intialAppliedFilters[label] || 'All') as string} onChange={(value) => onChangeSelect(value, label, FilterType.SELECT_ONE)} name={label} options={options} /> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. line: 54, 57 "magic numbers", What are |
||
)} | ||
{type === FilterType.DATE && ( | ||
<FilterDate initialValue={(intialAppliedFilters[label] || '') as string} onChange={(value) => onDateChange(value, label, FilterType.DATE)}/> | ||
)} | ||
{type === FilterType.RANGE && ( | ||
<FilterRange initialValue={intialAppliedFilters[label] as { min: number; max: number }} min={from} max={to} onChange={(value) => onRangeChange(value, label, FilterType.RANGE)}/> | ||
)} | ||
</li> | ||
) | ||
})} | ||
</ul> | ||
<button className={styles.clearFilters} onClick={onClear}>Clear filters</button> | ||
</div> | ||
</article>, | ||
filterContainerRef.current | ||
)} | ||
</article> | ||
); | ||
}; | ||
|
||
export default Filter; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
.datePicker { | ||
background-color: #29303d; | ||
color: white; | ||
border-radius: 5px; | ||
padding: 3px 10px; | ||
border: none; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To get rid of these hard-to-read and write paths ( ../../someComponent ) you can use aliases (@someComponent). They can be configured in the webpack.config and tsconfig.json for typing to work correctly