Skip to content

Commit 2af676a

Browse files
committed
fix: ensure fromNow exists on date before access
1 parent 3197854 commit 2af676a

File tree

3 files changed

+61
-10
lines changed

3 files changed

+61
-10
lines changed

package/src/components/ImageGallery/components/ImageGalleryHeader.tsx

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { useOverlayContext } from '../../../contexts/overlayContext/OverlayConte
1515
import { useTheme } from '../../../contexts/themeContext/ThemeContext';
1616
import {
1717
isDayOrMoment,
18+
TDateTimeParserOutput,
1819
useTranslationContext,
1920
} from '../../../contexts/translationContext/TranslationContext';
2021
import { Close } from '../../../icons';
@@ -104,16 +105,29 @@ export const ImageGalleryHeader = <Us extends UnknownType = DefaultUserType>(pro
104105
const parsedDate = photo ? tDateTimeParser(photo?.created_at) : null;
105106

106107
/**
107-
* .calendar is required on moment types, but in reality it
108-
* is unavailable on first render. We therefore check if it
109-
* is available and call it, otherwise we call .fromNow.
108+
* .calendar and .fromNow can be initialized after the first render,
109+
* and attempting to access them at that time will cause an error
110+
* to be thrown.
111+
*
112+
* This falls back to null if neither exist.
110113
*/
111-
const date =
112-
parsedDate && isDayOrMoment(parsedDate)
113-
? parsedDate.calendar
114-
? parsedDate.calendar()
115-
: parsedDate.fromNow()
116-
: null;
114+
const getDateObject = (date: TDateTimeParserOutput | null) => {
115+
if (date === null || !isDayOrMoment(date)) {
116+
return null;
117+
}
118+
119+
if (date.calendar) {
120+
return date.calendar();
121+
}
122+
123+
if (date.fromNow) {
124+
return date.fromNow();
125+
}
126+
127+
return null;
128+
};
129+
130+
const date = getDateObject(parsedDate);
117131

118132
const headerStyle = useAnimatedStyle<ViewStyle>(() => ({
119133
opacity: opacity.value,
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import React from 'react';
2+
3+
import type Animated from 'react-native-reanimated';
4+
5+
import { render } from '@testing-library/react-native';
6+
7+
import { ThemeProvider } from '../../../../contexts/themeContext/ThemeContext';
8+
import { ImageGalleryHeader } from '../ImageGalleryHeader';
9+
10+
it('doesnt fail if fromNow is not available on first render', () => {
11+
try {
12+
const { getAllByText } = render(
13+
<ThemeProvider>
14+
<ImageGalleryHeader
15+
opacity={1 as unknown as Animated.SharedValue<number>}
16+
photo={{
17+
id: 'id',
18+
uri: 'file:///bogus/uri/to/photo.jpg',
19+
}}
20+
visible={1 as unknown as Animated.SharedValue<number>}
21+
/>
22+
</ThemeProvider>,
23+
);
24+
25+
expect(getAllByText('Unknown User')).toBeTruthy();
26+
} catch (error: unknown) {
27+
if (error instanceof Error) {
28+
throw new Error(`Error encountered on first render of ImageGalleryHeader: ${error.message}`);
29+
}
30+
}
31+
});

package/src/components/Message/MessageSimple/utils/renderText.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,13 @@ export const renderText = <
252252
};
253253

254254
const list: ReactNodeOutput = (node, output, state) => (
255-
<ListOutput key={`list-${state.key}`} node={node} output={output} state={state} styles={styles} />
255+
<ListOutput
256+
key={`list-${state.key}`}
257+
node={node}
258+
output={output}
259+
state={state}
260+
styles={styles}
261+
/>
256262
);
257263

258264
const customRules = {

0 commit comments

Comments
 (0)