Skip to content

Commit

Permalink
[#204] 노트 목록 UI 개선 기초작업
Browse files Browse the repository at this point in the history
  • Loading branch information
akh9804 committed Apr 22, 2021
1 parent 2cc0186 commit cd34708
Show file tree
Hide file tree
Showing 5 changed files with 223 additions and 12 deletions.
3 changes: 2 additions & 1 deletion src/frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@
"@types/react-redux": "^7.1.9",
"@types/react-router-dom": "^5.1.6",
"@types/styled-components": "^5.1.4",
"jest-environment-jsdom-sixteen": "^1.0.3"
"jest-environment-jsdom-sixteen": "^1.0.3",
"prettier": "^2.2.1"
},
"scripts": {
"start": "craco start",
Expand Down
87 changes: 87 additions & 0 deletions src/frontend/src/component/main/NoteList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import React from 'react';
import { Link } from 'react-router-dom';
import { Button, List, Popover, Typography } from 'antd';
import { MoreOutlined } from '@ant-design/icons';
import moment from 'moment';
import styled from 'styled-components';
import * as Color from '../../constants/colors';
import * as Type from '../../types';
import routes from '../../routes';
import StockTransaction from './StockTransaction';

interface NoteListProps {
loading: boolean;
notes: Array<Type.Note>;
onClickUpdateNoteButton: (noteId: number) => () => void;
onDeleteNote: (noteId: number) => () => void;
filterStockTransactions: (note: Type.Note) => Array<Array<Type.StockTransaction>>;
}

const Container = styled.div`
background-color: ${Color.WHITE};
box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.1);
padding: 20px;
`;

const Title = styled(Typography.Title)`
color: ${Color.BLUE_2};
margin-bottom: 30px !important;
`;

const MoreButton = styled(MoreOutlined)`
font-size: 20px;
`;

const SmallButton = styled(Button)`
padding: 4px 5px;
`;

const StockTransactionButton = styled(Button)`
margin-right: 10px;
`;

const NoteList: React.VFC<NoteListProps> = ({
loading,
notes,
onClickUpdateNoteButton,
onDeleteNote,
filterStockTransactions,
}) => {
return (
<Container>
<Title level={3}>투자노트 목록</Title>
<List
loading={loading}
itemLayout="horizontal"
dataSource={notes}
renderItem={(note) => (
<List.Item>
<List.Item.Meta
title={<Link to={routes.note.detail(note.id)}>{note.title}</Link>}
description={moment(note.investmentDate).format('YYYY년 MM월 DD일')}
/>
<StockTransaction stockTransactions={note.stockTransactions} />
<Popover
placement="topRight"
trigger="click"
content={
<div>
<SmallButton type="link" onClick={onClickUpdateNoteButton(note.id)}>
수정
</SmallButton>
<SmallButton type="link" onClick={onDeleteNote(note.id)}>
삭제
</SmallButton>
</div>
}
>
<MoreButton />
</Popover>
</List.Item>
)}
/>
</Container>
);
};

export default NoteList;
89 changes: 89 additions & 0 deletions src/frontend/src/component/main/StockTransaction.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import React, { useCallback, useState } from 'react';
import styled from 'styled-components';
import { Button, Modal, Table } from 'antd';
import * as TransactionType from '../../constants/transactionType';
import * as Type from '../../types';
import { addCommaToNumber } from '../../lib/number';

interface StockTransactionProps {
stockTransactions: Array<Type.StockTransaction>;
}

interface StockTransactionModalProps {
isModalVisible: boolean;
stockTransactions: Array<Type.StockTransaction>;
}

const StockTransactionButton = styled(Button)`
margin-right: 10px;
`;

const columns = [
{
title: '종목명',
dataIndex: 'companyName',
key: 'companyName',
},
{
title: '거래량(주)',
dataIndex: 'quantity',
key: 'quantity',
},
{
title: '1주당 가격(원)',
dataIndex: 'tradedPrice',
key: 'tradedPrice',
},
{
title: '총 거래가(원)',
dataIndex: 'totalPrice',
key: 'totalPrice',
},
];

const StockTransaction: React.VFC<StockTransactionProps> = ({ stockTransactions }) => {
const transactionTypes: Array<Type.TransactionType> = [TransactionType.BUY, TransactionType.SELL];

return (
<div>
{transactionTypes.map((type) => {
const filteredStockTransactions = stockTransactions.filter((s) => s.transactionType === type);

if (filteredStockTransactions.length === 0) {
return null;
}
return (
<>
<StockTransactionButton
danger={type === TransactionType.SELL}
onClick={() =>
Modal.info({
title: type === TransactionType.BUY ? '매수내역' : '매도내역',
content: (
<Table
columns={columns}
dataSource={filteredStockTransactions.map((s, idx) => ({
key: idx,
companyName: s.stockDetail.companyName,
quantity: addCommaToNumber(s.quantity),
tradedPrice: addCommaToNumber(s.tradedPrice),
totalPrice: addCommaToNumber(s.quantity * s.tradedPrice),
}))}
/>
),
onOk() {},
width: 900,
})
}
>
{type === TransactionType.BUY ? '매수 ' : '매도 '}
{filteredStockTransactions.length}
</StockTransactionButton>
</>
);
})}
</div>
);
};

export default StockTransaction;
51 changes: 40 additions & 11 deletions src/frontend/src/container/note/NoteListContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,55 @@ import React, { useCallback, useEffect } from 'react';
import { useAppDispatch, useNoteAction, useNoteState } from '../../hooks';
import history from '../../lib/history';
import routes from '../../routes';
import NoteList from '../../component/note/NoteList';
import * as Type from '../../types';
import * as TransactionType from '../../constants/transactionType';
import NoteList from '../../component/main/NoteList';

const NoteListContainer = () => {
const dispatch = useAppDispatch();
const { notes } = useNoteState();
const noteActions = useNoteAction();
const { notes, loading } = useNoteState();
const noteAction = useNoteAction();

const getMyNotes = useCallback(() => {
dispatch(noteActions.getNotesRequest({ page: 0, size: 10 }));
}, [dispatch, noteActions]);
const onClickUpdateNoteButton = useCallback(
(noteId: number) => () => {
history.push(routes.note.update(noteId));
},
[]
);

const onClickMoreInfoButton = useCallback((noteId: number) => {
history.push(routes.note.detail(noteId));
const onDeleteNote = useCallback(
(noteId: number) => () => {
if (window.confirm('정말 삭제하시겠습니까?')) {
dispatch(noteAction.deleteNoteRequest(noteId));
}
},
[dispatch, noteAction]
);

const filterStockTransactions = useCallback((note: Type.Note) => {
const buyType: Array<Type.StockTransaction> = [];
const sellType: Array<Type.StockTransaction> = [];

note.stockTransactions.forEach((s) =>
s.transactionType === TransactionType.BUY ? buyType.push(s) : sellType.push(s)
);

return [buyType, sellType];
}, []);

useEffect(() => {
getMyNotes();
}, [getMyNotes]);
dispatch(noteAction.getNotesRequest({ page: 0, size: 10 }));
}, [dispatch, noteAction]);

return <NoteList notes={notes} onClickMoreInfoButton={onClickMoreInfoButton} />;
return (
<NoteList
loading={loading.getNotes}
notes={notes}
onClickUpdateNoteButton={onClickUpdateNoteButton}
onDeleteNote={onDeleteNote}
filterStockTransactions={filterStockTransactions}
/>
);
};

export default NoteListContainer;
5 changes: 5 additions & 0 deletions src/frontend/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -9100,6 +9100,11 @@ prepend-http@^1.0.0:
resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc"
integrity sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=

prettier@^2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.2.1.tgz#795a1a78dd52f073da0cd42b21f9c91381923ff5"
integrity sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q==

pretty-bytes@^5.1.0:
version "5.3.0"
resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.3.0.tgz#f2849e27db79fb4d6cfe24764fc4134f165989f2"
Expand Down

0 comments on commit cd34708

Please sign in to comment.