|
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