feat: Switch FormattedDate component to Intl.DateTimeFormat (#8276)
* feat: Switch FormattedDate component to Intl.DateTimeFormat * feat: Revert stylistic only changes * Add tests * Take code review into account * Fix tests by forcing timezone * Use constant formats in DateSeparator to avoid uneeded rerenders * Add UserTimezone tests
This commit is contained in:
parent
f2198137aa
commit
0c587ab427
7 changed files with 944 additions and 35 deletions
|
|
@ -8,7 +8,7 @@ import {Text, type TextStyle} from 'react-native';
|
|||
import {of as of$} from 'rxjs';
|
||||
import {switchMap} from 'rxjs/operators';
|
||||
|
||||
import FormattedDate from '@components/formatted_date';
|
||||
import FormattedDate, {type FormattedDateFormat} from '@components/formatted_date';
|
||||
import FormattedText from '@components/formatted_text';
|
||||
import FormattedTime from '@components/formatted_time';
|
||||
import {getDisplayNamePreferenceAsBool} from '@helpers/api/preference';
|
||||
|
|
@ -43,6 +43,12 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => {
|
|||
};
|
||||
});
|
||||
|
||||
const DATE_FORMATS = {
|
||||
withinWeek: {weekday: 'long'},
|
||||
withinYear: {month: 'short', day: 'numeric'},
|
||||
afterYear: {dateStyle: 'medium'},
|
||||
} satisfies Record<string, FormattedDateFormat>;
|
||||
|
||||
const CustomStatusExpiry = ({currentUser, isMilitaryTime, showPrefix, showTimeCompulsory, showToday, testID = '', textStyles = {}, theme, time, withinBrackets}: Props) => {
|
||||
const userTimezone = getUserTimezoneProps(currentUser);
|
||||
const timezone = userTimezone.useAutomaticTimezone ? userTimezone.automaticTimezone : userTimezone.manualTimezone;
|
||||
|
|
@ -72,11 +78,11 @@ const CustomStatusExpiry = ({currentUser, isMilitaryTime, showPrefix, showTimeCo
|
|||
/>
|
||||
);
|
||||
} else if (expiryMomentTime.isAfter(tomorrowEndTime)) {
|
||||
let format = 'dddd';
|
||||
let format: FormattedDateFormat = DATE_FORMATS.withinWeek;
|
||||
if (expiryMomentTime.isAfter(plusSixDaysEndTime) && isCurrentYear) {
|
||||
format = 'MMM DD';
|
||||
format = DATE_FORMATS.withinYear;
|
||||
} else if (!isCurrentYear) {
|
||||
format = 'MMM DD, YYYY';
|
||||
format = DATE_FORMATS.afterYear;
|
||||
}
|
||||
|
||||
dateComponent = (
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
import React from 'react';
|
||||
import {Text, TouchableOpacity, View} from 'react-native';
|
||||
|
||||
import FormattedDate from '@components/formatted_date';
|
||||
import FormattedDate, {type FormattedDateFormat} from '@components/formatted_date';
|
||||
import {useTheme} from '@context/theme';
|
||||
import {getFormattedFileSize} from '@utils/file';
|
||||
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
||||
|
|
@ -14,10 +14,15 @@ type FileInfoProps = {
|
|||
disabled?: boolean;
|
||||
file: FileInfo;
|
||||
showDate: boolean;
|
||||
channelName?: string ;
|
||||
channelName?: string;
|
||||
onPress: () => void;
|
||||
}
|
||||
const FORMAT = ' • MMM DD HH:MM A';
|
||||
};
|
||||
const FORMAT: FormattedDateFormat = {
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
hour: 'numeric',
|
||||
minute: 'numeric',
|
||||
};
|
||||
|
||||
const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => {
|
||||
return {
|
||||
|
|
@ -91,13 +96,16 @@ const FileInfo = ({disabled, file, channelName, showDate, onPress}: FileInfoProp
|
|||
<Text style={style.infoText}>
|
||||
{`${getFormattedFileSize(file.size)}`}
|
||||
</Text>
|
||||
{showDate &&
|
||||
<FormattedDate
|
||||
style={style.infoText}
|
||||
format={FORMAT}
|
||||
value={file.create_at as number}
|
||||
/>
|
||||
}
|
||||
{showDate && file.create_at != null && (
|
||||
<>
|
||||
{' • '}
|
||||
<FormattedDate
|
||||
style={style.infoText}
|
||||
format={FORMAT}
|
||||
value={file.create_at}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
import React from 'react';
|
||||
import {View, Text} from 'react-native';
|
||||
|
||||
import FormattedDate from '@components/formatted_date';
|
||||
import FormattedDate, {type FormattedDateFormat} from '@components/formatted_date';
|
||||
import {useTheme} from '@context/theme';
|
||||
import {getFormattedFileSize} from '@utils/file';
|
||||
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
||||
|
|
@ -11,7 +11,13 @@ import {typography} from '@utils/typography';
|
|||
|
||||
import Icon, {ICON_SIZE} from './icon';
|
||||
|
||||
const format = 'MMM DD YYYY HH:MM A';
|
||||
const FORMAT: FormattedDateFormat = {
|
||||
year: 'numeric',
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
hour: 'numeric',
|
||||
minute: 'numeric',
|
||||
};
|
||||
|
||||
const HEADER_MARGIN = 8;
|
||||
const FILE_ICON_MARGIN = 8;
|
||||
|
|
@ -78,7 +84,7 @@ const Header = ({fileInfo}: Props) => {
|
|||
<Text style={style.infoText}>{`${size} • `}</Text>
|
||||
<FormattedDate
|
||||
style={style.date}
|
||||
format={format}
|
||||
format={FORMAT}
|
||||
value={fileInfo.create_at as number}
|
||||
/>
|
||||
</View>
|
||||
|
|
|
|||
799
app/components/formatted_date/__snapshots__/index.test.tsx.snap
Normal file
799
app/components/formatted_date/__snapshots__/index.test.tsx.snap
Normal file
|
|
@ -0,0 +1,799 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'bg' locale and '{"dateStyle": "medium"}' format 1`] = `
|
||||
<Text>
|
||||
26.10.2024 г.
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'bg' locale and '{"day": "numeric", "hour": "numeric", "minute": "numeric", "month": "short", "year": "numeric"}' format 1`] = `
|
||||
<Text>
|
||||
26.10.2024 г., 10:01 ч.
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'bg' locale and '{"day": "numeric", "hour": "numeric", "minute": "numeric", "month": "short"}' format 1`] = `
|
||||
<Text>
|
||||
26.10, 10:01 ч.
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'bg' locale and '{"day": "numeric", "month": "short"}' format 1`] = `
|
||||
<Text>
|
||||
26.10
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'bg' locale and '{"weekday": "long"}' format 1`] = `
|
||||
<Text>
|
||||
събота
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'bg' locale and 'undefined' format 1`] = `
|
||||
<Text>
|
||||
26.10.2024 г.
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'de' locale and '{"dateStyle": "medium"}' format 1`] = `
|
||||
<Text>
|
||||
26.10.2024
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'de' locale and '{"day": "numeric", "hour": "numeric", "minute": "numeric", "month": "short", "year": "numeric"}' format 1`] = `
|
||||
<Text>
|
||||
26. Okt. 2024, 10:01
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'de' locale and '{"day": "numeric", "hour": "numeric", "minute": "numeric", "month": "short"}' format 1`] = `
|
||||
<Text>
|
||||
26. Okt., 10:01
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'de' locale and '{"day": "numeric", "month": "short"}' format 1`] = `
|
||||
<Text>
|
||||
26. Okt.
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'de' locale and '{"weekday": "long"}' format 1`] = `
|
||||
<Text>
|
||||
Samstag
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'de' locale and 'undefined' format 1`] = `
|
||||
<Text>
|
||||
26.10.2024
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'en' locale and '{"dateStyle": "medium"}' format 1`] = `
|
||||
<Text>
|
||||
Oct 26, 2024
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'en' locale and '{"day": "numeric", "hour": "numeric", "minute": "numeric", "month": "short", "year": "numeric"}' format 1`] = `
|
||||
<Text>
|
||||
Oct 26, 2024, 10:01 AM
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'en' locale and '{"day": "numeric", "hour": "numeric", "minute": "numeric", "month": "short"}' format 1`] = `
|
||||
<Text>
|
||||
Oct 26, 10:01 AM
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'en' locale and '{"day": "numeric", "month": "short"}' format 1`] = `
|
||||
<Text>
|
||||
Oct 26
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'en' locale and '{"weekday": "long"}' format 1`] = `
|
||||
<Text>
|
||||
Saturday
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'en' locale and 'undefined' format 1`] = `
|
||||
<Text>
|
||||
Oct 26, 2024
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'en-AU' locale and '{"dateStyle": "medium"}' format 1`] = `
|
||||
<Text>
|
||||
26 Oct 2024
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'en-AU' locale and '{"day": "numeric", "hour": "numeric", "minute": "numeric", "month": "short", "year": "numeric"}' format 1`] = `
|
||||
<Text>
|
||||
26 Oct 2024, 10:01 am
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'en-AU' locale and '{"day": "numeric", "hour": "numeric", "minute": "numeric", "month": "short"}' format 1`] = `
|
||||
<Text>
|
||||
26 Oct, 10:01 am
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'en-AU' locale and '{"day": "numeric", "month": "short"}' format 1`] = `
|
||||
<Text>
|
||||
26 Oct
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'en-AU' locale and '{"weekday": "long"}' format 1`] = `
|
||||
<Text>
|
||||
Saturday
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'en-AU' locale and 'undefined' format 1`] = `
|
||||
<Text>
|
||||
26 Oct 2024
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'es' locale and '{"dateStyle": "medium"}' format 1`] = `
|
||||
<Text>
|
||||
26 oct 2024
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'es' locale and '{"day": "numeric", "hour": "numeric", "minute": "numeric", "month": "short", "year": "numeric"}' format 1`] = `
|
||||
<Text>
|
||||
26 oct 2024, 10:01
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'es' locale and '{"day": "numeric", "hour": "numeric", "minute": "numeric", "month": "short"}' format 1`] = `
|
||||
<Text>
|
||||
26 oct, 10:01
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'es' locale and '{"day": "numeric", "month": "short"}' format 1`] = `
|
||||
<Text>
|
||||
26 oct
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'es' locale and '{"weekday": "long"}' format 1`] = `
|
||||
<Text>
|
||||
sábado
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'es' locale and 'undefined' format 1`] = `
|
||||
<Text>
|
||||
26 oct 2024
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'fa' locale and '{"dateStyle": "medium"}' format 1`] = `
|
||||
<Text>
|
||||
۵ آبان ۱۴۰۳
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'fa' locale and '{"day": "numeric", "hour": "numeric", "minute": "numeric", "month": "short", "year": "numeric"}' format 1`] = `
|
||||
<Text>
|
||||
۵ آبان ۱۴۰۳، ۱۰:۰۱
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'fa' locale and '{"day": "numeric", "hour": "numeric", "minute": "numeric", "month": "short"}' format 1`] = `
|
||||
<Text>
|
||||
۵ آبان، ۱۰:۰۱
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'fa' locale and '{"day": "numeric", "month": "short"}' format 1`] = `
|
||||
<Text>
|
||||
۵ آبان
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'fa' locale and '{"weekday": "long"}' format 1`] = `
|
||||
<Text>
|
||||
شنبه
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'fa' locale and 'undefined' format 1`] = `
|
||||
<Text>
|
||||
۵ آبان ۱۴۰۳
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'fr' locale and '{"dateStyle": "medium"}' format 1`] = `
|
||||
<Text>
|
||||
26 oct. 2024
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'fr' locale and '{"day": "numeric", "hour": "numeric", "minute": "numeric", "month": "short", "year": "numeric"}' format 1`] = `
|
||||
<Text>
|
||||
26 oct. 2024, 10:01
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'fr' locale and '{"day": "numeric", "hour": "numeric", "minute": "numeric", "month": "short"}' format 1`] = `
|
||||
<Text>
|
||||
26 oct., 10:01
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'fr' locale and '{"day": "numeric", "month": "short"}' format 1`] = `
|
||||
<Text>
|
||||
26 oct.
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'fr' locale and '{"weekday": "long"}' format 1`] = `
|
||||
<Text>
|
||||
samedi
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'fr' locale and 'undefined' format 1`] = `
|
||||
<Text>
|
||||
26 oct. 2024
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'hu' locale and '{"dateStyle": "medium"}' format 1`] = `
|
||||
<Text>
|
||||
2024. okt. 26.
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'hu' locale and '{"day": "numeric", "hour": "numeric", "minute": "numeric", "month": "short", "year": "numeric"}' format 1`] = `
|
||||
<Text>
|
||||
2024. okt. 26. 10:01
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'hu' locale and '{"day": "numeric", "hour": "numeric", "minute": "numeric", "month": "short"}' format 1`] = `
|
||||
<Text>
|
||||
okt. 26. 10:01
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'hu' locale and '{"day": "numeric", "month": "short"}' format 1`] = `
|
||||
<Text>
|
||||
okt. 26.
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'hu' locale and '{"weekday": "long"}' format 1`] = `
|
||||
<Text>
|
||||
szombat
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'hu' locale and 'undefined' format 1`] = `
|
||||
<Text>
|
||||
2024. okt. 26.
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'it' locale and '{"dateStyle": "medium"}' format 1`] = `
|
||||
<Text>
|
||||
26 ott 2024
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'it' locale and '{"day": "numeric", "hour": "numeric", "minute": "numeric", "month": "short", "year": "numeric"}' format 1`] = `
|
||||
<Text>
|
||||
26 ott 2024, 10:01
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'it' locale and '{"day": "numeric", "hour": "numeric", "minute": "numeric", "month": "short"}' format 1`] = `
|
||||
<Text>
|
||||
26 ott, 10:01
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'it' locale and '{"day": "numeric", "month": "short"}' format 1`] = `
|
||||
<Text>
|
||||
26 ott
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'it' locale and '{"weekday": "long"}' format 1`] = `
|
||||
<Text>
|
||||
sabato
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'it' locale and 'undefined' format 1`] = `
|
||||
<Text>
|
||||
26 ott 2024
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'ja' locale and '{"dateStyle": "medium"}' format 1`] = `
|
||||
<Text>
|
||||
2024/10/26
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'ja' locale and '{"day": "numeric", "hour": "numeric", "minute": "numeric", "month": "short", "year": "numeric"}' format 1`] = `
|
||||
<Text>
|
||||
2024年10月26日 10:01
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'ja' locale and '{"day": "numeric", "hour": "numeric", "minute": "numeric", "month": "short"}' format 1`] = `
|
||||
<Text>
|
||||
10月26日 10:01
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'ja' locale and '{"day": "numeric", "month": "short"}' format 1`] = `
|
||||
<Text>
|
||||
10月26日
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'ja' locale and '{"weekday": "long"}' format 1`] = `
|
||||
<Text>
|
||||
土曜日
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'ja' locale and 'undefined' format 1`] = `
|
||||
<Text>
|
||||
2024/10/26
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'ko' locale and '{"dateStyle": "medium"}' format 1`] = `
|
||||
<Text>
|
||||
2024. 10. 26.
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'ko' locale and '{"day": "numeric", "hour": "numeric", "minute": "numeric", "month": "short", "year": "numeric"}' format 1`] = `
|
||||
<Text>
|
||||
2024년 10월 26일 오전 10:01
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'ko' locale and '{"day": "numeric", "hour": "numeric", "minute": "numeric", "month": "short"}' format 1`] = `
|
||||
<Text>
|
||||
10월 26일 오전 10:01
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'ko' locale and '{"day": "numeric", "month": "short"}' format 1`] = `
|
||||
<Text>
|
||||
10월 26일
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'ko' locale and '{"weekday": "long"}' format 1`] = `
|
||||
<Text>
|
||||
토요일
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'ko' locale and 'undefined' format 1`] = `
|
||||
<Text>
|
||||
2024. 10. 26.
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'nl' locale and '{"dateStyle": "medium"}' format 1`] = `
|
||||
<Text>
|
||||
26 okt 2024
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'nl' locale and '{"day": "numeric", "hour": "numeric", "minute": "numeric", "month": "short", "year": "numeric"}' format 1`] = `
|
||||
<Text>
|
||||
26 okt 2024, 10:01
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'nl' locale and '{"day": "numeric", "hour": "numeric", "minute": "numeric", "month": "short"}' format 1`] = `
|
||||
<Text>
|
||||
26 okt, 10:01
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'nl' locale and '{"day": "numeric", "month": "short"}' format 1`] = `
|
||||
<Text>
|
||||
26 okt
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'nl' locale and '{"weekday": "long"}' format 1`] = `
|
||||
<Text>
|
||||
zaterdag
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'nl' locale and 'undefined' format 1`] = `
|
||||
<Text>
|
||||
26 okt 2024
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'pl' locale and '{"dateStyle": "medium"}' format 1`] = `
|
||||
<Text>
|
||||
26 paź 2024
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'pl' locale and '{"day": "numeric", "hour": "numeric", "minute": "numeric", "month": "short", "year": "numeric"}' format 1`] = `
|
||||
<Text>
|
||||
26 paź 2024, 10:01
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'pl' locale and '{"day": "numeric", "hour": "numeric", "minute": "numeric", "month": "short"}' format 1`] = `
|
||||
<Text>
|
||||
26 paź, 10:01
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'pl' locale and '{"day": "numeric", "month": "short"}' format 1`] = `
|
||||
<Text>
|
||||
26 paź
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'pl' locale and '{"weekday": "long"}' format 1`] = `
|
||||
<Text>
|
||||
sobota
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'pl' locale and 'undefined' format 1`] = `
|
||||
<Text>
|
||||
26 paź 2024
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'pt-BR' locale and '{"dateStyle": "medium"}' format 1`] = `
|
||||
<Text>
|
||||
26 de out. de 2024
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'pt-BR' locale and '{"day": "numeric", "hour": "numeric", "minute": "numeric", "month": "short", "year": "numeric"}' format 1`] = `
|
||||
<Text>
|
||||
26 de out. de 2024, 10:01
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'pt-BR' locale and '{"day": "numeric", "hour": "numeric", "minute": "numeric", "month": "short"}' format 1`] = `
|
||||
<Text>
|
||||
26 de out., 10:01
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'pt-BR' locale and '{"day": "numeric", "month": "short"}' format 1`] = `
|
||||
<Text>
|
||||
26 de out.
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'pt-BR' locale and '{"weekday": "long"}' format 1`] = `
|
||||
<Text>
|
||||
sábado
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'pt-BR' locale and 'undefined' format 1`] = `
|
||||
<Text>
|
||||
26 de out. de 2024
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'ro' locale and '{"dateStyle": "medium"}' format 1`] = `
|
||||
<Text>
|
||||
26 oct. 2024
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'ro' locale and '{"day": "numeric", "hour": "numeric", "minute": "numeric", "month": "short", "year": "numeric"}' format 1`] = `
|
||||
<Text>
|
||||
26 oct. 2024, 10:01
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'ro' locale and '{"day": "numeric", "hour": "numeric", "minute": "numeric", "month": "short"}' format 1`] = `
|
||||
<Text>
|
||||
26 oct., 10:01
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'ro' locale and '{"day": "numeric", "month": "short"}' format 1`] = `
|
||||
<Text>
|
||||
26 oct.
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'ro' locale and '{"weekday": "long"}' format 1`] = `
|
||||
<Text>
|
||||
sâmbătă
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'ro' locale and 'undefined' format 1`] = `
|
||||
<Text>
|
||||
26 oct. 2024
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'ru' locale and '{"dateStyle": "medium"}' format 1`] = `
|
||||
<Text>
|
||||
26 окт. 2024 г.
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'ru' locale and '{"day": "numeric", "hour": "numeric", "minute": "numeric", "month": "short", "year": "numeric"}' format 1`] = `
|
||||
<Text>
|
||||
26 окт. 2024 г., 10:01
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'ru' locale and '{"day": "numeric", "hour": "numeric", "minute": "numeric", "month": "short"}' format 1`] = `
|
||||
<Text>
|
||||
26 окт., 10:01
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'ru' locale and '{"day": "numeric", "month": "short"}' format 1`] = `
|
||||
<Text>
|
||||
26 окт.
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'ru' locale and '{"weekday": "long"}' format 1`] = `
|
||||
<Text>
|
||||
суббота
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'ru' locale and 'undefined' format 1`] = `
|
||||
<Text>
|
||||
26 окт. 2024 г.
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'sv' locale and '{"dateStyle": "medium"}' format 1`] = `
|
||||
<Text>
|
||||
26 okt. 2024
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'sv' locale and '{"day": "numeric", "hour": "numeric", "minute": "numeric", "month": "short", "year": "numeric"}' format 1`] = `
|
||||
<Text>
|
||||
26 okt. 2024 10:01
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'sv' locale and '{"day": "numeric", "hour": "numeric", "minute": "numeric", "month": "short"}' format 1`] = `
|
||||
<Text>
|
||||
26 okt. 10:01
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'sv' locale and '{"day": "numeric", "month": "short"}' format 1`] = `
|
||||
<Text>
|
||||
26 okt.
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'sv' locale and '{"weekday": "long"}' format 1`] = `
|
||||
<Text>
|
||||
lördag
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'sv' locale and 'undefined' format 1`] = `
|
||||
<Text>
|
||||
26 okt. 2024
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'tr' locale and '{"dateStyle": "medium"}' format 1`] = `
|
||||
<Text>
|
||||
26 Eki 2024
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'tr' locale and '{"day": "numeric", "hour": "numeric", "minute": "numeric", "month": "short", "year": "numeric"}' format 1`] = `
|
||||
<Text>
|
||||
26 Eki 2024 10:01
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'tr' locale and '{"day": "numeric", "hour": "numeric", "minute": "numeric", "month": "short"}' format 1`] = `
|
||||
<Text>
|
||||
26 Eki 10:01
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'tr' locale and '{"day": "numeric", "month": "short"}' format 1`] = `
|
||||
<Text>
|
||||
26 Eki
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'tr' locale and '{"weekday": "long"}' format 1`] = `
|
||||
<Text>
|
||||
Cumartesi
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'tr' locale and 'undefined' format 1`] = `
|
||||
<Text>
|
||||
26 Eki 2024
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'uk' locale and '{"dateStyle": "medium"}' format 1`] = `
|
||||
<Text>
|
||||
26 жовт. 2024 р.
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'uk' locale and '{"day": "numeric", "hour": "numeric", "minute": "numeric", "month": "short", "year": "numeric"}' format 1`] = `
|
||||
<Text>
|
||||
26 жовт. 2024 р., 10:01
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'uk' locale and '{"day": "numeric", "hour": "numeric", "minute": "numeric", "month": "short"}' format 1`] = `
|
||||
<Text>
|
||||
26 жовт., 10:01
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'uk' locale and '{"day": "numeric", "month": "short"}' format 1`] = `
|
||||
<Text>
|
||||
26 жовт.
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'uk' locale and '{"weekday": "long"}' format 1`] = `
|
||||
<Text>
|
||||
субота
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'uk' locale and 'undefined' format 1`] = `
|
||||
<Text>
|
||||
26 жовт. 2024 р.
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'vi' locale and '{"dateStyle": "medium"}' format 1`] = `
|
||||
<Text>
|
||||
26 thg 10, 2024
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'vi' locale and '{"day": "numeric", "hour": "numeric", "minute": "numeric", "month": "short", "year": "numeric"}' format 1`] = `
|
||||
<Text>
|
||||
10:01 26 thg 10, 2024
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'vi' locale and '{"day": "numeric", "hour": "numeric", "minute": "numeric", "month": "short"}' format 1`] = `
|
||||
<Text>
|
||||
10:01 26 thg 10
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'vi' locale and '{"day": "numeric", "month": "short"}' format 1`] = `
|
||||
<Text>
|
||||
26 thg 10
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'vi' locale and '{"weekday": "long"}' format 1`] = `
|
||||
<Text>
|
||||
Thứ Bảy
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'vi' locale and 'undefined' format 1`] = `
|
||||
<Text>
|
||||
26 thg 10, 2024
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'zh-CN' locale and '{"dateStyle": "medium"}' format 1`] = `
|
||||
<Text>
|
||||
2024年10月26日
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'zh-CN' locale and '{"day": "numeric", "hour": "numeric", "minute": "numeric", "month": "short", "year": "numeric"}' format 1`] = `
|
||||
<Text>
|
||||
2024年10月26日 10:01
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'zh-CN' locale and '{"day": "numeric", "hour": "numeric", "minute": "numeric", "month": "short"}' format 1`] = `
|
||||
<Text>
|
||||
10月26日 10:01
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'zh-CN' locale and '{"day": "numeric", "month": "short"}' format 1`] = `
|
||||
<Text>
|
||||
10月26日
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'zh-CN' locale and '{"weekday": "long"}' format 1`] = `
|
||||
<Text>
|
||||
星期六
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'zh-CN' locale and 'undefined' format 1`] = `
|
||||
<Text>
|
||||
2024年10月26日
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'zh-TW' locale and '{"dateStyle": "medium"}' format 1`] = `
|
||||
<Text>
|
||||
2024年10月26日
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'zh-TW' locale and '{"day": "numeric", "hour": "numeric", "minute": "numeric", "month": "short", "year": "numeric"}' format 1`] = `
|
||||
<Text>
|
||||
2024年10月26日 上午10:01
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'zh-TW' locale and '{"day": "numeric", "hour": "numeric", "minute": "numeric", "month": "short"}' format 1`] = `
|
||||
<Text>
|
||||
10月26日 上午10:01
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'zh-TW' locale and '{"day": "numeric", "month": "short"}' format 1`] = `
|
||||
<Text>
|
||||
10月26日
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'zh-TW' locale and '{"weekday": "long"}' format 1`] = `
|
||||
<Text>
|
||||
星期六
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should match snapshot for 'zh-TW' locale and 'undefined' format 1`] = `
|
||||
<Text>
|
||||
2024年10月26日
|
||||
</Text>
|
||||
`;
|
||||
|
||||
exports[`<FormattedDate/> should render with a manual user time 1`] = `
|
||||
<Text>
|
||||
Oct 26, 2024
|
||||
</Text>
|
||||
`;
|
||||
79
app/components/formatted_date/index.test.tsx
Normal file
79
app/components/formatted_date/index.test.tsx
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import {renderWithIntl} from '@test/intl-test-helper';
|
||||
|
||||
import locales from '../../i18n/languages';
|
||||
|
||||
import FormattedDate, {type FormattedDateFormat} from './index';
|
||||
|
||||
const DATE = new Date('2024-10-26T10:01:04.653Z');
|
||||
const FORMATS = [
|
||||
undefined,
|
||||
{weekday: 'long'},
|
||||
{dateStyle: 'medium'},
|
||||
{month: 'short', day: 'numeric'},
|
||||
{
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
hour: 'numeric',
|
||||
minute: 'numeric',
|
||||
},
|
||||
{
|
||||
year: 'numeric',
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
hour: 'numeric',
|
||||
minute: 'numeric',
|
||||
},
|
||||
] satisfies Array<FormattedDateFormat | undefined>;
|
||||
|
||||
const TEST_MATRIX = Object.keys(locales).
|
||||
map((locale) => FORMATS.map<[string, FormattedDateFormat | undefined]>((format) => [locale, format])).
|
||||
flat(1);
|
||||
|
||||
describe('<FormattedDate/>', () => {
|
||||
it.each(TEST_MATRIX)("should match snapshot for '%s' locale and '%p' format", (locale, format) => {
|
||||
const wrapper = renderWithIntl(
|
||||
<FormattedDate
|
||||
format={format}
|
||||
value={DATE}
|
||||
timezone='UTC'
|
||||
/>,
|
||||
{locale},
|
||||
);
|
||||
expect(wrapper.toJSON()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should render with a manual user time', () => {
|
||||
const wrapper = renderWithIntl(
|
||||
<FormattedDate
|
||||
value={DATE}
|
||||
timezone={{
|
||||
automaticTimezone: '',
|
||||
manualTimezone: 'Indian/Mauritius',
|
||||
useAutomaticTimezone: '',
|
||||
}}
|
||||
/>,
|
||||
);
|
||||
expect(wrapper.toJSON()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should render with an automatic user time', () => {
|
||||
const wrapper = renderWithIntl(
|
||||
<FormattedDate
|
||||
value={DATE}
|
||||
timezone={{
|
||||
automaticTimezone: 'Indian/Mauritius',
|
||||
manualTimezone: '',
|
||||
useAutomaticTimezone: 'true',
|
||||
}}
|
||||
/>,
|
||||
);
|
||||
|
||||
// Just check that the component render as automatic timezone is environment dependant
|
||||
expect(wrapper.toJSON()).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
|
@ -1,34 +1,40 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import moment from 'moment';
|
||||
import mtz from 'moment-timezone';
|
||||
import React from 'react';
|
||||
import {useIntl} from 'react-intl';
|
||||
import {Text, type TextProps} from 'react-native';
|
||||
|
||||
import {getLocaleFromLanguage} from '@i18n';
|
||||
export type FormattedDateFormat = Exclude<Intl.DateTimeFormatOptions, 'timeZone'>;
|
||||
|
||||
type FormattedDateProps = TextProps & {
|
||||
format?: string;
|
||||
format?: FormattedDateFormat;
|
||||
timezone?: string | UserTimezone | null;
|
||||
value: number | string | Date;
|
||||
}
|
||||
|
||||
const FormattedDate = ({format = 'MMM DD, YYYY', timezone, value, ...props}: FormattedDateProps) => {
|
||||
const DEFAULT_FORMAT: FormattedDateFormat = {dateStyle: 'medium'};
|
||||
|
||||
const FormattedDate = ({
|
||||
format = DEFAULT_FORMAT,
|
||||
timezone,
|
||||
value,
|
||||
...props
|
||||
}: FormattedDateProps) => {
|
||||
const {locale} = useIntl();
|
||||
moment.locale(getLocaleFromLanguage(locale).toLowerCase());
|
||||
let formattedDate = mtz(value).format(format);
|
||||
if (timezone) {
|
||||
let zone: string;
|
||||
if (typeof timezone === 'object') {
|
||||
zone = timezone.useAutomaticTimezone ? timezone.automaticTimezone : timezone.manualTimezone;
|
||||
} else {
|
||||
zone = timezone;
|
||||
}
|
||||
formattedDate = mtz.tz(value, zone).format(format);
|
||||
|
||||
let timeZone: string | undefined;
|
||||
if (timezone && typeof timezone === 'object') {
|
||||
timeZone = timezone.useAutomaticTimezone ? timezone.automaticTimezone : timezone.manualTimezone;
|
||||
} else {
|
||||
timeZone = timezone ?? undefined;
|
||||
}
|
||||
|
||||
const formattedDate = new Intl.DateTimeFormat(locale, {
|
||||
...format,
|
||||
timeZone,
|
||||
}).format(new Date(value));
|
||||
|
||||
return <Text {...props}>{formattedDate}</Text>;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
import React from 'react';
|
||||
import {type StyleProp, View, type ViewStyle} from 'react-native';
|
||||
|
||||
import FormattedDate from '@components/formatted_date';
|
||||
import FormattedDate, {type FormattedDateFormat} from '@components/formatted_date';
|
||||
import FormattedText from '@components/formatted_text';
|
||||
import {useTheme} from '@context/theme';
|
||||
import {isSameYear, isToday, isYesterday} from '@utils/datetime';
|
||||
|
|
@ -38,6 +38,11 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => {
|
|||
};
|
||||
});
|
||||
|
||||
const DATE_FORMATS = {
|
||||
withinYear: {month: 'short', day: 'numeric'},
|
||||
afterYear: {dateStyle: 'medium'},
|
||||
} satisfies Record<string, FormattedDateFormat>;
|
||||
|
||||
const RecentDate = (props: DateSeparatorProps) => {
|
||||
const {date, ...otherProps} = props;
|
||||
const when = new Date(date);
|
||||
|
|
@ -60,7 +65,7 @@ const RecentDate = (props: DateSeparatorProps) => {
|
|||
);
|
||||
}
|
||||
|
||||
const format = isSameYear(when, new Date()) ? 'MMM DD' : 'MMM DD, YYYY';
|
||||
const format: FormattedDateFormat = isSameYear(when, new Date()) ? DATE_FORMATS.withinYear : DATE_FORMATS.afterYear;
|
||||
|
||||
return (
|
||||
<FormattedDate
|
||||
|
|
|
|||
Loading…
Reference in a new issue