Skip to content

Commit 66907e8

Browse files
committed
Implemented Transaction list parsing from CSV
* Using react-dropzone for file choosing * Implemented Transactions component * Fixed date parsing with locale data Signed-off-by: Eugen Stan <[email protected]>
1 parent 1b5f335 commit 66907e8

File tree

7 files changed

+380
-154
lines changed

7 files changed

+380
-154
lines changed

package-lock.json

Lines changed: 28 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,12 @@
88
"@testing-library/jest-dom": "^4.2.4",
99
"@testing-library/react": "^9.5.0",
1010
"@testing-library/user-event": "^7.2.1",
11+
"date-fns": "^2.12.0",
1112
"lodash": "^4.17.15",
12-
"moment": "^2.24.0",
1313
"papaparse": "^5.2.0",
1414
"react": "^16.13.1",
1515
"react-dom": "^16.13.1",
16+
"react-dropzone": "^10.2.2",
1617
"react-scripts": "3.4.1",
1718
"styled-components": "^5.0.1"
1819
},
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import React, { useCallback } from "react";
2+
3+
import { useDropzone } from "react-dropzone";
4+
5+
import styled from "styled-components";
6+
import Papa from "papaparse";
7+
8+
import { processCsv } from "../ing-parser";
9+
10+
const DropZone = styled.div`
11+
align-items: center;
12+
padding: 20px;
13+
border-width: 2px;
14+
border-radius: 2px;
15+
border-color: #eeeeee;
16+
border-style: dashed;
17+
background-color: #fafafa;
18+
color: #bdbdbd;
19+
outline: none;
20+
transition: border 0.24s ease-in-out;
21+
`;
22+
23+
function TransactionFileImport(props) {
24+
const { setTransactions } = props;
25+
26+
const onDrop = useCallback(
27+
(acceptedFiles) => {
28+
acceptedFiles.forEach((file) => {
29+
Papa.parse(file, {
30+
complete: (results, file) => {
31+
console.log(`Processed CSV file ${file.name}`);
32+
const { data } = results;
33+
const txns = processCsv(data);
34+
setTransactions(txns);
35+
},
36+
error: (error, file) => {
37+
console.log(`Error processing ${file.name} - ${error}`);
38+
alert(`Error processing ${file.name} - ${error}`);
39+
},
40+
});
41+
});
42+
},
43+
[setTransactions]
44+
);
45+
46+
const { acceptedFiles, getRootProps, getInputProps } = useDropzone({
47+
onDrop,
48+
});
49+
50+
const files = acceptedFiles.map((file) => (
51+
<li key={file.path}>
52+
{file.path} - {file.size} bytes
53+
</li>
54+
));
55+
56+
return (
57+
<section className="container">
58+
<DropZone {...getRootProps({ className: "dropzone" })}>
59+
<input {...getInputProps()} />
60+
<p>Drag 'n' drop CSV files here, or click to select files</p>
61+
</DropZone>
62+
<aside>
63+
<h4>Files</h4>
64+
<ul>{files}</ul>
65+
</aside>
66+
</section>
67+
);
68+
}
69+
70+
71+
export default TransactionFileImport;

src/components/Transactions.jsx

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
import React from "react";
2+
import styled from "styled-components";
3+
4+
import Transaction from "../transaction";
5+
6+
const Container = styled.div`
7+
margin: 8px;
8+
border: 1px solid lightgray;
9+
border-radius: 2px;
10+
height: 600px;
11+
overflow: scroll;
12+
overflow-x: hidden;
13+
14+
display: flex;
15+
flex-direction: column;
16+
`;
17+
const Title = styled.h3`
18+
padding: 8px;
19+
`;
20+
const Items = styled.div`
21+
padding: 8px;
22+
`;
23+
const Filter = styled.div`
24+
padding: 8px;
25+
`;
26+
27+
function Transactions(props) {
28+
const { transactions = [] } = props;
29+
30+
return (
31+
<Container>
32+
<Title>
33+
<span>{transactions.length}</span> Transactions
34+
</Title>
35+
<Filter>
36+
<form>
37+
<div className="row">
38+
<div className="col-md-12">
39+
<div className="input-group input-group-sm mb-3">
40+
<div className="input-group-prepend">
41+
<button
42+
className="btn btn-outline-secondary dropdown-toggle"
43+
type="button"
44+
data-toggle="dropdown"
45+
aria-haspopup="true"
46+
aria-expanded="false"
47+
>
48+
Source Account
49+
</button>
50+
<div className="dropdown-menu">acounts...</div>
51+
</div>
52+
<input
53+
type="text"
54+
className="form-control"
55+
aria-label="Text input with dropdown button"
56+
></input>
57+
</div>
58+
</div>
59+
<div className="col-md-6">
60+
<div className="input-group input-group-sm mb-3">
61+
<div className="input-group-prepend">
62+
<button className="btn btn-outline-success" type="submit">
63+
Search
64+
</button>
65+
</div>
66+
<input
67+
className="form-control mr-sm-2"
68+
type="search"
69+
placeholder="Search"
70+
aria-label="Search"
71+
/>
72+
</div>
73+
</div>
74+
<div className="col-md-6">
75+
<div className="btn-group btn-group-sm">
76+
<button type="button" className="btn btn-outline-secondary">
77+
All transactions
78+
</button>
79+
<button
80+
type="button"
81+
className="btn btn-outline-secondary dropdown-toggle dropdown-toggle-split"
82+
id="dropdownMenuReference"
83+
data-toggle="dropdown"
84+
aria-haspopup="true"
85+
aria-expanded="false"
86+
data-reference="parent"
87+
>
88+
<span className="sr-only">Toggle Dropdown</span>
89+
</button>
90+
<div
91+
className="dropdown-menu"
92+
aria-labelledby="dropdownMenuReference"
93+
>
94+
<a className="dropdown-item" href="1">
95+
Expences
96+
</a>
97+
<a className="dropdown-item" href="2">
98+
Incomes
99+
</a>
100+
</div>
101+
</div>
102+
</div>
103+
</div>
104+
</form>
105+
</Filter>
106+
<Items>
107+
{transactions.map((transaction) => (
108+
<Transaction transaction={transaction} />
109+
))}
110+
</Items>
111+
</Container>
112+
);
113+
}
114+
115+
export default Transactions;

0 commit comments

Comments
 (0)