|
1 | | -import PropTypes from 'prop-types'; |
2 | | -import React from 'react'; |
3 | | -import { connect, useDispatch } from 'react-redux'; |
4 | | -import { bindActionCreators } from 'redux'; |
5 | | -import { Link } from 'react-router-dom'; |
| 1 | +import React, { useEffect } from 'react'; |
| 2 | +import { useDispatch, useSelector } from 'react-redux'; |
6 | 3 | import { Helmet } from 'react-helmet'; |
7 | | -import prettyBytes from 'pretty-bytes'; |
8 | | -import { useTranslation, withTranslation } from 'react-i18next'; |
9 | | -import MenuItem from '../../../components/Dropdown/MenuItem'; |
10 | | -import TableDropdown from '../../../components/Dropdown/TableDropdown'; |
11 | | - |
| 4 | +import { useTranslation } from 'react-i18next'; |
| 5 | +import AssetListRow from './AssetListRow'; |
12 | 6 | import Loader from '../../App/components/loader'; |
13 | | -import { deleteAssetRequest } from '../actions/assets'; |
14 | 7 | import * as AssetActions from '../actions/assets'; |
15 | 8 |
|
16 | | -const AssetMenu = ({ item: asset }) => { |
| 9 | +const AssetList = () => { |
17 | 10 | const { t } = useTranslation(); |
18 | | - |
19 | 11 | const dispatch = useDispatch(); |
| 12 | + const { username, assetList, loading } = useSelector((state) => ({ |
| 13 | + username: state.user.username, |
| 14 | + assetList: state.assets.list, |
| 15 | + loading: state.loading |
| 16 | + })); |
20 | 17 |
|
21 | | - const handleAssetDelete = () => { |
22 | | - const { key, name } = asset; |
23 | | - if (window.confirm(t('Common.DeleteConfirmation', { name }))) { |
24 | | - dispatch(deleteAssetRequest(key)); |
25 | | - } |
26 | | - }; |
27 | | - |
28 | | - return ( |
29 | | - <TableDropdown aria-label={t('AssetList.ToggleOpenCloseARIA')}> |
30 | | - <MenuItem onClick={handleAssetDelete}>{t('AssetList.Delete')}</MenuItem> |
31 | | - <MenuItem href={asset.url} target="_blank"> |
32 | | - {t('AssetList.OpenNewTab')} |
33 | | - </MenuItem> |
34 | | - </TableDropdown> |
35 | | - ); |
36 | | -}; |
37 | | - |
38 | | -AssetMenu.propTypes = { |
39 | | - item: PropTypes.shape({ |
40 | | - key: PropTypes.string.isRequired, |
41 | | - url: PropTypes.string.isRequired, |
42 | | - name: PropTypes.string.isRequired |
43 | | - }).isRequired |
44 | | -}; |
45 | | - |
46 | | -const AssetListRowBase = ({ asset, username }) => ( |
47 | | - <tr className="asset-table__row" key={asset.key}> |
48 | | - <th scope="row"> |
49 | | - <a href={asset.url} target="_blank" rel="noopener noreferrer"> |
50 | | - {asset.name} |
51 | | - </a> |
52 | | - </th> |
53 | | - <td>{prettyBytes(asset.size)}</td> |
54 | | - <td> |
55 | | - {asset.sketchId && ( |
56 | | - <Link to={`/${username}/sketches/${asset.sketchId}`}> |
57 | | - {asset.sketchName} |
58 | | - </Link> |
59 | | - )} |
60 | | - </td> |
61 | | - <td className="asset-table__dropdown-column"> |
62 | | - <AssetMenu item={asset} /> |
63 | | - </td> |
64 | | - </tr> |
65 | | -); |
66 | | - |
67 | | -AssetListRowBase.propTypes = { |
68 | | - asset: PropTypes.shape({ |
69 | | - key: PropTypes.string.isRequired, |
70 | | - url: PropTypes.string.isRequired, |
71 | | - sketchId: PropTypes.string, |
72 | | - sketchName: PropTypes.string, |
73 | | - name: PropTypes.string.isRequired, |
74 | | - size: PropTypes.number.isRequired |
75 | | - }).isRequired, |
76 | | - username: PropTypes.string.isRequired |
77 | | -}; |
78 | | - |
79 | | -function mapStateToPropsAssetListRow(state) { |
80 | | - return { |
81 | | - username: state.user.username |
82 | | - }; |
83 | | -} |
84 | | - |
85 | | -function mapDispatchToPropsAssetListRow(dispatch) { |
86 | | - return bindActionCreators(AssetActions, dispatch); |
87 | | -} |
88 | | - |
89 | | -const AssetListRow = connect( |
90 | | - mapStateToPropsAssetListRow, |
91 | | - mapDispatchToPropsAssetListRow |
92 | | -)(AssetListRowBase); |
93 | | - |
94 | | -class AssetList extends React.Component { |
95 | | - constructor(props) { |
96 | | - super(props); |
97 | | - this.props.getAssets(); |
98 | | - } |
99 | | - |
100 | | - getAssetsTitle() { |
101 | | - return this.props.t('AssetList.Title'); |
102 | | - } |
| 18 | + useEffect(() => { |
| 19 | + dispatch(AssetActions.getAssets()); |
| 20 | + }, []); |
103 | 21 |
|
104 | | - hasAssets() { |
105 | | - return !this.props.loading && this.props.assetList.length > 0; |
106 | | - } |
| 22 | + const hasAssets = () => !loading && assetList.length > 0; |
107 | 23 |
|
108 | | - renderLoader() { |
109 | | - if (this.props.loading) return <Loader />; |
110 | | - return null; |
111 | | - } |
| 24 | + const renderLoader = () => (loading ? <Loader /> : null); |
112 | 25 |
|
113 | | - renderEmptyTable() { |
114 | | - if (!this.props.loading && this.props.assetList.length === 0) { |
| 26 | + const renderEmptyTable = () => { |
| 27 | + if (!loading && assetList.length === 0) { |
115 | 28 | return ( |
116 | | - <p className="asset-table__empty"> |
117 | | - {this.props.t('AssetList.NoUploadedAssets')} |
118 | | - </p> |
| 29 | + <p className="asset-table__empty">{t('AssetList.NoUploadedAssets')}</p> |
119 | 30 | ); |
120 | 31 | } |
121 | 32 | return null; |
122 | | - } |
123 | | - |
124 | | - render() { |
125 | | - const { assetList, t } = this.props; |
126 | | - return ( |
127 | | - <article className="asset-table-container"> |
128 | | - <Helmet> |
129 | | - <title>{this.getAssetsTitle()}</title> |
130 | | - </Helmet> |
131 | | - {this.renderLoader()} |
132 | | - {this.renderEmptyTable()} |
133 | | - {this.hasAssets() && ( |
134 | | - <table className="asset-table"> |
135 | | - <thead> |
136 | | - <tr> |
137 | | - <th>{t('AssetList.HeaderName')}</th> |
138 | | - <th>{t('AssetList.HeaderSize')}</th> |
139 | | - <th>{t('AssetList.HeaderSketch')}</th> |
140 | | - <th scope="col"></th> |
141 | | - </tr> |
142 | | - </thead> |
143 | | - <tbody> |
144 | | - {assetList.map((asset) => ( |
145 | | - <AssetListRow asset={asset} key={asset.key} t={t} /> |
146 | | - ))} |
147 | | - </tbody> |
148 | | - </table> |
149 | | - )} |
150 | | - </article> |
151 | | - ); |
152 | | - } |
153 | | -} |
154 | | - |
155 | | -AssetList.propTypes = { |
156 | | - user: PropTypes.shape({ |
157 | | - username: PropTypes.string |
158 | | - }).isRequired, |
159 | | - assetList: PropTypes.arrayOf( |
160 | | - PropTypes.shape({ |
161 | | - key: PropTypes.string.isRequired, |
162 | | - name: PropTypes.string.isRequired, |
163 | | - url: PropTypes.string.isRequired, |
164 | | - sketchName: PropTypes.string, |
165 | | - sketchId: PropTypes.string |
166 | | - }) |
167 | | - ).isRequired, |
168 | | - getAssets: PropTypes.func.isRequired, |
169 | | - loading: PropTypes.bool.isRequired, |
170 | | - t: PropTypes.func.isRequired |
171 | | -}; |
172 | | - |
173 | | -function mapStateToProps(state) { |
174 | | - return { |
175 | | - user: state.user, |
176 | | - assetList: state.assets.list, |
177 | | - loading: state.loading |
178 | 33 | }; |
179 | | -} |
180 | 34 |
|
181 | | -function mapDispatchToProps(dispatch) { |
182 | | - return bindActionCreators(Object.assign({}, AssetActions), dispatch); |
183 | | -} |
| 35 | + return ( |
| 36 | + <article className="asset-table-container"> |
| 37 | + <Helmet> |
| 38 | + <title>{t('AssetList.Title')}</title> |
| 39 | + </Helmet> |
| 40 | + {renderLoader()} |
| 41 | + {renderEmptyTable()} |
| 42 | + {hasAssets() && ( |
| 43 | + <table className="asset-table"> |
| 44 | + <thead> |
| 45 | + <tr> |
| 46 | + <th>{t('AssetList.HeaderName')}</th> |
| 47 | + <th>{t('AssetList.HeaderSize')}</th> |
| 48 | + <th>{t('AssetList.HeaderSketch')}</th> |
| 49 | + <th scope="col"></th> |
| 50 | + </tr> |
| 51 | + </thead> |
| 52 | + <tbody> |
| 53 | + {assetList.map((asset) => ( |
| 54 | + <AssetListRow asset={asset} key={asset.key} username={username} /> |
| 55 | + ))} |
| 56 | + </tbody> |
| 57 | + </table> |
| 58 | + )} |
| 59 | + </article> |
| 60 | + ); |
| 61 | +}; |
184 | 62 |
|
185 | | -export default withTranslation()( |
186 | | - connect(mapStateToProps, mapDispatchToProps)(AssetList) |
187 | | -); |
| 63 | +export default AssetList; |
0 commit comments