Merge branch 'relative-timestamp-tsx' into 'develop'

RelativeTimestamp: convert to TSX

See merge request soapbox-pub/soapbox-fe!1762
environments/review-develop-3zknud/deployments/884
Alex Gleason 2 years ago
commit 1876af9be7

@ -8,7 +8,7 @@ import { useAppSelector, useOnScreen } from 'soapbox/hooks';
import { getAcct } from 'soapbox/utils/accounts'; import { getAcct } from 'soapbox/utils/accounts';
import { displayFqn } from 'soapbox/utils/state'; import { displayFqn } from 'soapbox/utils/state';
import RelativeTimestamp from './relative_timestamp'; import RelativeTimestamp from './relative-timestamp';
import { Avatar, Emoji, HStack, Icon, IconButton, Stack, Text } from './ui'; import { Avatar, Emoji, HStack, Icon, IconButton, Stack, Text } from './ui';
import type { Account as AccountEntity } from 'soapbox/types/entities'; import type { Account as AccountEntity } from 'soapbox/types/entities';
@ -54,7 +54,7 @@ interface IAccount {
id?: string, id?: string,
onActionClick?: (account: any) => void, onActionClick?: (account: any) => void,
showProfileHoverCard?: boolean, showProfileHoverCard?: boolean,
timestamp?: string | Date, timestamp?: string,
timestampUrl?: string, timestampUrl?: string,
futureTimestamp?: boolean, futureTimestamp?: boolean,
withAccountNote?: boolean, withAccountNote?: boolean,

@ -6,7 +6,7 @@ import { useSoapboxConfig } from 'soapbox/hooks';
import { getAcct } from '../utils/accounts'; import { getAcct } from '../utils/accounts';
import Icon from './icon'; import Icon from './icon';
import RelativeTimestamp from './relative_timestamp'; import RelativeTimestamp from './relative-timestamp';
import VerificationBadge from './verification_badge'; import VerificationBadge from './verification_badge';
import type { Account } from 'soapbox/types/entities'; import type { Account } from 'soapbox/types/entities';

@ -4,7 +4,7 @@ import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
import { fetchPoll, vote } from 'soapbox/actions/polls'; import { fetchPoll, vote } from 'soapbox/actions/polls';
import { useAppDispatch } from 'soapbox/hooks'; import { useAppDispatch } from 'soapbox/hooks';
import RelativeTimestamp from '../relative_timestamp'; import RelativeTimestamp from '../relative-timestamp';
import { Button, HStack, Stack, Text, Tooltip } from '../ui'; import { Button, HStack, Stack, Text, Tooltip } from '../ui';
import type { Selected } from './poll'; import type { Selected } from './poll';

@ -1,8 +1,7 @@
import PropTypes from 'prop-types';
import React from 'react'; import React from 'react';
import { injectIntl, defineMessages } from 'react-intl'; import { injectIntl, defineMessages, IntlShape, FormatDateOptions } from 'react-intl';
import { Text } from './ui'; import Text, { IText } from './ui/text/text';
const messages = defineMessages({ const messages = defineMessages({
just_now: { id: 'relative_time.just_now', defaultMessage: 'now' }, just_now: { id: 'relative_time.just_now', defaultMessage: 'now' },
@ -17,7 +16,7 @@ const messages = defineMessages({
days_remaining: { id: 'time_remaining.days', defaultMessage: '{number, plural, one {# day} other {# days}} left' }, days_remaining: { id: 'time_remaining.days', defaultMessage: '{number, plural, one {# day} other {# days}} left' },
}); });
const dateFormatOptions = { const dateFormatOptions: FormatDateOptions = {
hour12: false, hour12: false,
year: 'numeric', year: 'numeric',
month: 'short', month: 'short',
@ -26,7 +25,7 @@ const dateFormatOptions = {
minute: '2-digit', minute: '2-digit',
}; };
const shortDateFormatOptions = { const shortDateFormatOptions: FormatDateOptions = {
month: 'short', month: 'short',
day: 'numeric', day: 'numeric',
}; };
@ -38,7 +37,7 @@ const DAY = 1000 * 60 * 60 * 24;
const MAX_DELAY = 2147483647; const MAX_DELAY = 2147483647;
const selectUnits = delta => { const selectUnits = (delta: number) => {
const absDelta = Math.abs(delta); const absDelta = Math.abs(delta);
if (absDelta < MINUTE) { if (absDelta < MINUTE) {
@ -52,7 +51,7 @@ const selectUnits = delta => {
return 'day'; return 'day';
}; };
const getUnitDelay = units => { const getUnitDelay = (units: string) => {
switch (units) { switch (units) {
case 'second': case 'second':
return SECOND; return SECOND;
@ -67,7 +66,7 @@ const getUnitDelay = units => {
} }
}; };
export const timeAgoString = (intl, date, now, year) => { export const timeAgoString = (intl: IntlShape, date: Date, now: number, year: number) => {
const delta = now - date.getTime(); const delta = now - date.getTime();
let relativeTime; let relativeTime;
@ -93,7 +92,7 @@ export const timeAgoString = (intl, date, now, year) => {
return relativeTime; return relativeTime;
}; };
const timeRemainingString = (intl, date, now) => { const timeRemainingString = (intl: IntlShape, date: Date, now: number) => {
const delta = date.getTime() - now; const delta = date.getTime() - now;
let relativeTime; let relativeTime;
@ -113,16 +112,21 @@ const timeRemainingString = (intl, date, now) => {
return relativeTime; return relativeTime;
}; };
export default @injectIntl interface RelativeTimestampProps extends IText {
class RelativeTimestamp extends React.Component { intl: IntlShape,
timestamp: string,
year?: number,
futureDate?: boolean,
}
static propTypes = { interface RelativeTimestampState {
intl: PropTypes.object.isRequired, now: number,
timestamp: PropTypes.string.isRequired, }
year: PropTypes.number.isRequired,
theme: PropTypes.string, /** Displays a timestamp compared to the current time, eg "1m" for one minute ago. */
futureDate: PropTypes.bool, class RelativeTimestamp extends React.Component<RelativeTimestampProps, RelativeTimestampState> {
};
_timer: NodeJS.Timeout | undefined;
state = { state = {
now: Date.now(), now: Date.now(),
@ -130,10 +134,10 @@ class RelativeTimestamp extends React.Component {
static defaultProps = { static defaultProps = {
year: (new Date()).getFullYear(), year: (new Date()).getFullYear(),
theme: 'inherit', theme: 'inherit' as const,
}; };
shouldComponentUpdate(nextProps, nextState) { shouldComponentUpdate(nextProps: RelativeTimestampProps, nextState: RelativeTimestampState) {
// As of right now the locale doesn't change without a new page load, // As of right now the locale doesn't change without a new page load,
// but we might as well check in case that ever changes. // but we might as well check in case that ever changes.
return this.props.timestamp !== nextProps.timestamp || return this.props.timestamp !== nextProps.timestamp ||
@ -141,14 +145,14 @@ class RelativeTimestamp extends React.Component {
this.state.now !== nextState.now; this.state.now !== nextState.now;
} }
UNSAFE_componentWillReceiveProps(prevProps) { UNSAFE_componentWillReceiveProps(prevProps: RelativeTimestampProps) {
if (this.props.timestamp !== prevProps.timestamp) { if (this.props.timestamp !== prevProps.timestamp) {
this.setState({ now: Date.now() }); this.setState({ now: Date.now() });
} }
} }
componentDidMount() { componentDidMount() {
this._scheduleNextUpdate(this.props, this.state); this._scheduleNextUpdate();
} }
UNSAFE_componentWillUpdate() { UNSAFE_componentWillUpdate() {
@ -156,11 +160,15 @@ class RelativeTimestamp extends React.Component {
} }
componentWillUnmount() { componentWillUnmount() {
clearTimeout(this._timer); if (this._timer) {
clearTimeout(this._timer);
}
} }
_scheduleNextUpdate() { _scheduleNextUpdate() {
clearTimeout(this._timer); if (this._timer) {
clearTimeout(this._timer);
}
const { timestamp } = this.props; const { timestamp } = this.props;
const delta = (new Date(timestamp)).getTime() - this.state.now; const delta = (new Date(timestamp)).getTime() - this.state.now;
@ -177,8 +185,8 @@ class RelativeTimestamp extends React.Component {
render() { render() {
const { timestamp, intl, year, futureDate, theme, ...textProps } = this.props; const { timestamp, intl, year, futureDate, theme, ...textProps } = this.props;
const date = new Date(timestamp); const date = new Date(timestamp);
const relativeTime = futureDate ? timeRemainingString(intl, date, this.state.now) : timeAgoString(intl, date, this.state.now, year); const relativeTime = futureDate ? timeRemainingString(intl, date, this.state.now) : timeAgoString(intl, date, this.state.now, year!);
return ( return (
<Text {...textProps} theme={theme} tag='time' title={intl.formatDate(date, dateFormatOptions)}> <Text {...textProps} theme={theme} tag='time' title={intl.formatDate(date, dateFormatOptions)}>
@ -188,3 +196,5 @@ class RelativeTimestamp extends React.Component {
} }
} }
export default injectIntl(RelativeTimestamp);

@ -84,7 +84,9 @@ interface IText extends Pick<React.HTMLAttributes<HTMLParagraphElement>, 'danger
/** Whether to truncate the text if its container is too small. */ /** Whether to truncate the text if its container is too small. */
truncate?: boolean, truncate?: boolean,
/** Font weight of the text. */ /** Font weight of the text. */
weight?: Weights weight?: Weights,
/** Tooltip title. */
title?: string,
} }
/** UI-friendly text container with dark mode support. */ /** UI-friendly text container with dark mode support. */
@ -133,4 +135,7 @@ const Text: React.FC<IText> = React.forwardRef(
}, },
); );
export default Text; export {
Text as default,
IText,
};

@ -6,7 +6,7 @@ import { getSettings } from 'soapbox/actions/settings';
import Avatar from 'soapbox/components/avatar'; import Avatar from 'soapbox/components/avatar';
import DisplayName from 'soapbox/components/display-name'; import DisplayName from 'soapbox/components/display-name';
import Permalink from 'soapbox/components/permalink'; import Permalink from 'soapbox/components/permalink';
import RelativeTimestamp from 'soapbox/components/relative_timestamp'; import RelativeTimestamp from 'soapbox/components/relative-timestamp';
import { Text } from 'soapbox/components/ui'; import { Text } from 'soapbox/components/ui';
import ActionButton from 'soapbox/features/ui/components/action-button'; import ActionButton from 'soapbox/features/ui/components/action-button';
import { useAppSelector } from 'soapbox/hooks'; import { useAppSelector } from 'soapbox/hooks';

@ -21,7 +21,6 @@ describe('normalizePoll()', () => {
expect(ImmutableRecord.isRecord(result)).toBe(true); expect(ImmutableRecord.isRecord(result)).toBe(true);
expect(ImmutableRecord.isRecord(result.options.get(0))).toBe(true); expect(ImmutableRecord.isRecord(result.options.get(0))).toBe(true);
expect(result.toJS()).toMatchObject(expected); expect(result.toJS()).toMatchObject(expected);
expect(result.expires_at instanceof Date).toBe(true);
}); });
it('normalizes a Pleroma logged-out poll', () => { it('normalizes a Pleroma logged-out poll', () => {

@ -164,7 +164,6 @@ describe('normalizeStatus()', () => {
expect(ImmutableRecord.isRecord(poll)).toBe(true); expect(ImmutableRecord.isRecord(poll)).toBe(true);
expect(ImmutableRecord.isRecord(poll.options.get(0))).toBe(true); expect(ImmutableRecord.isRecord(poll.options.get(0))).toBe(true);
expect(poll.toJS()).toMatchObject(expected); expect(poll.toJS()).toMatchObject(expected);
expect(poll.expires_at instanceof Date).toBe(true);
}); });
it('normalizes a Pleroma logged-out poll', () => { it('normalizes a Pleroma logged-out poll', () => {

@ -26,7 +26,7 @@ export const AccountRecord = ImmutableRecord({
avatar_static: '', avatar_static: '',
birthday: '', birthday: '',
bot: false, bot: false,
created_at: new Date(), created_at: '',
discoverable: false, discoverable: false,
display_name: '', display_name: '',
emojis: ImmutableList<Emoji>(), emojis: ImmutableList<Emoji>(),
@ -38,7 +38,7 @@ export const AccountRecord = ImmutableRecord({
header: '', header: '',
header_static: '', header_static: '',
id: '', id: '',
last_status_at: new Date(), last_status_at: '',
location: '', location: '',
locked: false, locked: false,
moved: null as EmbeddedEntity<any>, moved: null as EmbeddedEntity<any>,

@ -21,7 +21,7 @@ import type { Emoji, PollOption } from 'soapbox/types/entities';
export const PollRecord = ImmutableRecord({ export const PollRecord = ImmutableRecord({
emojis: ImmutableList<Emoji>(), emojis: ImmutableList<Emoji>(),
expired: false, expired: false,
expires_at: new Date(), expires_at: '',
id: '', id: '',
multiple: false, multiple: false,
options: ImmutableList<PollOption>(), options: ImmutableList<PollOption>(),

@ -28,8 +28,8 @@ export const StatusRecord = ImmutableRecord({
bookmarked: false, bookmarked: false,
card: null as Card | null, card: null as Card | null,
content: '', content: '',
created_at: new Date(), created_at: '',
edited_at: null as Date | null, edited_at: null as string | null,
emojis: ImmutableList<Emoji>(), emojis: ImmutableList<Emoji>(),
favourited: false, favourited: false,
favourites_count: 0, favourites_count: 0,

Loading…
Cancel
Save