1
0
Fork 0
forked from gitea/nas

Refactor <Dropdown> into TypeScript (#34357)

Co-authored-by: Echo <ChaosExAnima@users.noreply.github.com>
This commit is contained in:
Eugen Rochko 2025-04-08 21:22:19 +02:00 committed by GitHub
parent b7c3235349
commit 22d33244ee
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
21 changed files with 846 additions and 654 deletions

View file

@ -1,32 +0,0 @@
import { connect } from 'react-redux';
import { openDropdownMenu, closeDropdownMenu } from 'mastodon/actions/dropdown_menu';
import { fetchHistory } from 'mastodon/actions/history';
import DropdownMenu from 'mastodon/components/dropdown_menu';
/**
*
* @param {import('mastodon/store').RootState} state
* @param {*} props
*/
const mapStateToProps = (state, { statusId }) => ({
openDropdownId: state.dropdownMenu.openId,
openedViaKeyboard: state.dropdownMenu.keyboard,
items: state.getIn(['history', statusId, 'items']),
loading: state.getIn(['history', statusId, 'loading']),
});
const mapDispatchToProps = (dispatch, { statusId }) => ({
onOpen (id, onItemClick, keyboard) {
dispatch(fetchHistory(statusId));
dispatch(openDropdownMenu({ id, keyboard }));
},
onClose (id) {
dispatch(closeDropdownMenu({ id }));
},
});
export default connect(mapStateToProps, mapDispatchToProps)(DropdownMenu);

View file

@ -1,77 +0,0 @@
import PropTypes from 'prop-types';
import { PureComponent } from 'react';
import { FormattedMessage, injectIntl } from 'react-intl';
import { connect } from 'react-redux';
import { openModal } from 'mastodon/actions/modal';
import { FormattedDateWrapper } from 'mastodon/components/formatted_date';
import InlineAccount from 'mastodon/components/inline_account';
import { RelativeTimestamp } from 'mastodon/components/relative_timestamp';
import DropdownMenu from './containers/dropdown_menu_container';
const mapDispatchToProps = (dispatch, { statusId }) => ({
onItemClick (index) {
dispatch(openModal({
modalType: 'COMPARE_HISTORY',
modalProps: { index, statusId },
}));
},
});
class EditedTimestamp extends PureComponent {
static propTypes = {
statusId: PropTypes.string.isRequired,
timestamp: PropTypes.string.isRequired,
intl: PropTypes.object.isRequired,
onItemClick: PropTypes.func.isRequired,
};
handleItemClick = (item, i) => {
const { onItemClick } = this.props;
onItemClick(i);
};
renderHeader = items => {
return (
<FormattedMessage id='status.edited_x_times' defaultMessage='Edited {count, plural, one {# time} other {# times}}' values={{ count: items.size - 1 }} />
);
};
renderItem = (item, index, { onClick, onKeyPress }) => {
const formattedDate = <RelativeTimestamp timestamp={item.get('created_at')} short={false} />;
const formattedName = <InlineAccount accountId={item.get('account')} />;
const label = item.get('original') ? (
<FormattedMessage id='status.history.created' defaultMessage='{name} created {date}' values={{ name: formattedName, date: formattedDate }} />
) : (
<FormattedMessage id='status.history.edited' defaultMessage='{name} edited {date}' values={{ name: formattedName, date: formattedDate }} />
);
return (
<li className='dropdown-menu__item edited-timestamp__history__item' key={item.get('created_at')}>
<button data-index={index} onClick={onClick} onKeyPress={onKeyPress}>{label}</button>
</li>
);
};
render () {
const { timestamp, statusId } = this.props;
return (
<DropdownMenu statusId={statusId} renderItem={this.renderItem} scrollable renderHeader={this.renderHeader} onItemClick={this.handleItemClick}>
<button className='dropdown-menu__text-button'>
<FormattedMessage id='status.edited' defaultMessage='Edited {date}' values={{ date: <FormattedDateWrapper className='animated-number' value={timestamp} month='short' day='2-digit' hour='2-digit' minute='2-digit' /> }} />
</button>
</DropdownMenu>
);
}
}
export default connect(null, mapDispatchToProps)(injectIntl(EditedTimestamp));

View file

@ -0,0 +1,140 @@
import { useCallback } from 'react';
import { FormattedMessage } from 'react-intl';
import type { Map as ImmutableMap, List as ImmutableList } from 'immutable';
import { fetchHistory } from 'mastodon/actions/history';
import { openModal } from 'mastodon/actions/modal';
import { Dropdown } from 'mastodon/components/dropdown_menu';
import { FormattedDateWrapper } from 'mastodon/components/formatted_date';
import InlineAccount from 'mastodon/components/inline_account';
import { RelativeTimestamp } from 'mastodon/components/relative_timestamp';
import { useAppDispatch, useAppSelector } from 'mastodon/store';
type HistoryItem = ImmutableMap<string, unknown>;
export const EditedTimestamp: React.FC<{
statusId: string;
timestamp: string;
}> = ({ statusId, timestamp }) => {
const dispatch = useAppDispatch();
const items = useAppSelector(
(state) =>
(
state.history.getIn([statusId, 'items']) as
| ImmutableList<unknown>
| undefined
)?.toArray() as HistoryItem[],
);
const loading = useAppSelector(
(state) => state.history.getIn([statusId, 'loading']) as boolean,
);
const handleOpen = useCallback(() => {
dispatch(fetchHistory(statusId));
}, [dispatch, statusId]);
const handleItemClick = useCallback(
(_item: HistoryItem, i: number) => {
dispatch(
openModal({
modalType: 'COMPARE_HISTORY',
modalProps: { index: i, statusId },
}),
);
},
[dispatch, statusId],
);
const renderHeader = useCallback((items: HistoryItem[]) => {
return (
<FormattedMessage
id='status.edited_x_times'
defaultMessage='Edited {count, plural, one {# time} other {# times}}'
values={{ count: items.length - 1 }}
/>
);
}, []);
const renderItem = useCallback(
(
item: HistoryItem,
index: number,
{
onClick,
onKeyUp,
}: {
onClick: React.MouseEventHandler;
onKeyUp: React.KeyboardEventHandler;
},
) => {
const formattedDate = (
<RelativeTimestamp
timestamp={item.get('created_at') as string}
short={false}
/>
);
const formattedName = (
<InlineAccount accountId={item.get('account') as string} />
);
const label = (item.get('original') as boolean) ? (
<FormattedMessage
id='status.history.created'
defaultMessage='{name} created {date}'
values={{ name: formattedName, date: formattedDate }}
/>
) : (
<FormattedMessage
id='status.history.edited'
defaultMessage='{name} edited {date}'
values={{ name: formattedName, date: formattedDate }}
/>
);
return (
<li
className='dropdown-menu__item edited-timestamp__history__item'
key={item.get('created_at') as string}
>
<button data-index={index} onClick={onClick} onKeyUp={onKeyUp}>
{label}
</button>
</li>
);
},
[],
);
return (
<Dropdown<HistoryItem>
items={items}
loading={loading}
renderItem={renderItem}
scrollable
renderHeader={renderHeader}
onOpen={handleOpen}
onItemClick={handleItemClick}
>
<button className='dropdown-menu__text-button'>
<FormattedMessage
id='status.edited'
defaultMessage='Edited {date}'
values={{
date: (
<FormattedDateWrapper
className='animated-number'
value={timestamp}
month='short'
day='2-digit'
hour='2-digit'
minute='2-digit'
/>
),
}}
/>
</button>
</Dropdown>
);
};