Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TS migration] Migrate AttachmentCarousel to typescript #36658

Merged
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
a9315c4
migrate AttachmentView
SzymczakJ Feb 15, 2024
0f696ce
migrate AttachmentCarousel
SzymczakJ Feb 15, 2024
de7619a
migrate attachmentCarousel
SzymczakJ Feb 16, 2024
4146104
Merge branch 'main' into @szymczak/AttachmentCarousel
SzymczakJ Feb 16, 2024
e8ab36f
fix merge bugs
SzymczakJ Feb 16, 2024
b46b1c0
clean up code
SzymczakJ Feb 16, 2024
ca34bcc
Merge branch 'main' into @szymczak/AttachmentCarousel
SzymczakJ Feb 26, 2024
b51d1c9
fix AttachmentView memo
SzymczakJ Feb 26, 2024
e6d06bf
fix PR comments
SzymczakJ Feb 26, 2024
eba12a9
Merge branch 'main' into @szymczak/AttachmentCarousel
SzymczakJ Feb 26, 2024
d60d76b
fix ts errors
SzymczakJ Feb 27, 2024
5a29704
Merge branch 'main' into @szymczak/AttachmentCarousel
SzymczakJ Feb 27, 2024
7560f8b
fix AttachmentView crash
SzymczakJ Feb 27, 2024
adbfc65
Merge branch 'main' into @szymczak/AttachmentCarousel
SzymczakJ Feb 28, 2024
ca76ff6
fix lint error
SzymczakJ Feb 28, 2024
f188c8c
merge main
SzymczakJ Mar 11, 2024
7a9853a
fix type errors
SzymczakJ Mar 11, 2024
a8b03df
fix lint
SzymczakJ Mar 11, 2024
b7ad3e2
fix comments
SzymczakJ Mar 13, 2024
f51a489
fix comments
SzymczakJ Mar 13, 2024
d69d776
Merge branch 'main' into @szymczak/AttachmentCarousel
SzymczakJ Mar 14, 2024
8c8ddf3
fix pr comments
SzymczakJ Mar 14, 2024
d746b6c
fix pr comments
SzymczakJ Mar 14, 2024
1f71572
fix PR comments
SzymczakJ Mar 15, 2024
eaef7fb
fix pr comments
SzymczakJ Mar 18, 2024
8629609
fix pr comments
SzymczakJ Mar 18, 2024
7c9015b
fix Pr commments
SzymczakJ Mar 19, 2024
7805777
fix PR comments
SzymczakJ Mar 19, 2024
8a5c9c5
fix type error
SzymczakJ Mar 19, 2024
efbdf5c
fix pr comments
SzymczakJ Mar 20, 2024
b8d4a61
fix type errors
SzymczakJ Mar 20, 2024
b63dcdc
Merge branch 'main' into @szymczak/AttachmentCarousel
SzymczakJ Mar 21, 2024
ad79213
Merge branch 'main' into @szymczak/AttachmentCarousel
SzymczakJ Mar 21, 2024
40a3688
Merge branch 'main' into @szymczak/AttachmentCarousel
SzymczakJ Mar 24, 2024
0844b82
fi pr comments
SzymczakJ Mar 24, 2024
f5a6712
Merge branch 'main' into @szymczak/AttachmentCarousel
SzymczakJ Mar 25, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/CONST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -437,7 +437,7 @@ const CONST = {
},
},
ARROW_LEFT: {
descriptionKey: null,
descriptionKey: 'arrowLeft',
shortcutKey: 'ArrowLeft',
SzymczakJ marked this conversation as resolved.
Show resolved Hide resolved
modifiers: [],
trigger: {
Expand All @@ -447,7 +447,7 @@ const CONST = {
},
},
ARROW_RIGHT: {
descriptionKey: null,
descriptionKey: 'arrowRight',
shortcutKey: 'ArrowRight',
modifiers: [],
trigger: {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,15 @@
import PropTypes from 'prop-types';
import React from 'react';
import type {StyleProp, ViewStyle} from 'react-native';
import {PixelRatio, View} from 'react-native';
import useThemeStyles from '@hooks/useThemeStyles';
import useWindowDimensions from '@hooks/useWindowDimensions';

const propTypes = {
type AttachmentCarouselCellRendererProps = {
/** Cell Container styles */
style: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.object), PropTypes.object]),
style?: StyleProp<ViewStyle>;
};

const defaultProps = {
style: [],
};

function AttachmentCarouselCellRenderer(props) {
function AttachmentCarouselCellRenderer(props: AttachmentCarouselCellRendererProps) {
const styles = useThemeStyles();
const {windowWidth, isSmallScreenWidth} = useWindowDimensions();
const modalStyles = styles.centeredModalStyles(isSmallScreenWidth, true);
Expand All @@ -28,8 +24,6 @@ function AttachmentCarouselCellRenderer(props) {
);
}

AttachmentCarouselCellRenderer.propTypes = propTypes;
AttachmentCarouselCellRenderer.defaultProps = defaultProps;
AttachmentCarouselCellRenderer.displayName = 'AttachmentCarouselCellRenderer';

export default React.memo(AttachmentCarouselCellRenderer);
Original file line number Diff line number Diff line change
@@ -1,25 +1,18 @@
import lodashGet from 'lodash/get';
import PropTypes from 'prop-types';
import {useEffect} from 'react';
import KeyboardShortcut from '@libs/KeyboardShortcut';
import CONST from '@src/CONST';

const propTypes = {
type CarouselActionsProps = {
/** Callback to cycle through attachments */
onCycleThroughAttachments: PropTypes.func.isRequired,
onCycleThroughAttachments: (deltaSlide: number) => void;
};

function CarouselActions({onCycleThroughAttachments}) {
function CarouselActions({onCycleThroughAttachments}: CarouselActionsProps) {
useEffect(() => {
const shortcutLeftConfig = CONST.KEYBOARD_SHORTCUTS.ARROW_LEFT;
const unsubscribeLeftKey = KeyboardShortcut.subscribe(
shortcutLeftConfig.shortcutKey,
(e) => {
if (lodashGet(e, 'target.blur')) {
// prevents focus from highlighting around the modal
e.target.blur();
}

() => {
onCycleThroughAttachments(-1);
SzymczakJ marked this conversation as resolved.
Show resolved Hide resolved
},
shortcutLeftConfig.descriptionKey,
Expand All @@ -29,12 +22,7 @@ function CarouselActions({onCycleThroughAttachments}) {
const shortcutRightConfig = CONST.KEYBOARD_SHORTCUTS.ARROW_RIGHT;
const unsubscribeRightKey = KeyboardShortcut.subscribe(
shortcutRightConfig.shortcutKey,
(e) => {
if (lodashGet(e, 'target.blur')) {
// prevents focus from highlighting around the modal
e.target.blur();
}

() => {
SzymczakJ marked this conversation as resolved.
Show resolved Hide resolved
onCycleThroughAttachments(1);
},
shortcutRightConfig.descriptionKey,
Expand All @@ -50,6 +38,4 @@ function CarouselActions({onCycleThroughAttachments}) {
return null;
}

CarouselActions.propTypes = propTypes;

export default CarouselActions;
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import PropTypes from 'prop-types';
import React from 'react';
import {View} from 'react-native';
import _ from 'underscore';
import * as AttachmentCarouselViewPropTypes from '@components/Attachments/propTypes';
import type {Attachment} from '@components/Attachments/types';
import Button from '@components/Button';
import * as Expensicons from '@components/Icon/Expensicons';
import Tooltip from '@components/Tooltip';
Expand All @@ -11,36 +9,32 @@ import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
import useWindowDimensions from '@hooks/useWindowDimensions';

const propTypes = {
type CarouselButtonsProps = {
/** Where the arrows should be visible */
shouldShowArrows: PropTypes.bool.isRequired,
shouldShowArrows: boolean;

/** The current page index */
page: PropTypes.number.isRequired,
page: number;

/** The attachments from the carousel */
attachments: AttachmentCarouselViewPropTypes.attachmentsPropType.isRequired,
attachments: Attachment[];

/** Callback to go one page back */
onBack: PropTypes.func.isRequired,
onBack: () => void;

/** Callback to go one page forward */
onForward: PropTypes.func.isRequired,
onForward: () => void;

autoHideArrow: PropTypes.func,
cancelAutoHideArrow: PropTypes.func,
};
autoHideArrow?: () => void;

SzymczakJ marked this conversation as resolved.
Show resolved Hide resolved
const defaultProps = {
autoHideArrow: () => {},
cancelAutoHideArrow: () => {},
cancelAutoHideArrow?: () => void;
};
SzymczakJ marked this conversation as resolved.
Show resolved Hide resolved

function CarouselButtons({page, attachments, shouldShowArrows, onBack, onForward, cancelAutoHideArrow, autoHideArrow}) {
function CarouselButtons({page, attachments, shouldShowArrows, onBack, onForward, cancelAutoHideArrow, autoHideArrow}: CarouselButtonsProps) {
const theme = useTheme();
const styles = useThemeStyles();
const isBackDisabled = page === 0;
const isForwardDisabled = page === _.size(attachments) - 1;

const isForwardDisabled = page === attachments.length - 1;
const {translate} = useLocalize();
const {isSmallScreenWidth} = useWindowDimensions();

Expand Down Expand Up @@ -82,8 +76,6 @@ function CarouselButtons({page, attachments, shouldShowArrows, onBack, onForward
) : null;
}

CarouselButtons.propTypes = propTypes;
CarouselButtons.defaultProps = defaultProps;
CarouselButtons.displayName = 'CarouselButtons';

export default CarouselButtons;
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import PropTypes from 'prop-types';
import React, {useContext, useState} from 'react';
import type {StyleProp, ViewStyle} from 'react-native';
import {View} from 'react-native';
import AttachmentView from '@components/Attachments/AttachmentView';
import * as AttachmentsPropTypes from '@components/Attachments/propTypes';
import type {Attachment} from '@components/Attachments/types';
import Button from '@components/Button';
import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeedback';
import SafeAreaConsumer from '@components/SafeAreaConsumer';
Expand All @@ -12,55 +12,31 @@ import useThemeStyles from '@hooks/useThemeStyles';
import ReportAttachmentsContext from '@pages/home/report/ReportAttachmentsContext';
import CONST from '@src/CONST';

const propTypes = {
type CarouselItemProps = {
/** Attachment required information such as the source and file name */
item: PropTypes.shape({
/** Report action ID of the attachment */
reportActionID: PropTypes.string,
item: Attachment;

/** Whether source URL requires authentication */
isAuthTokenRequired: PropTypes.bool,
/** Whether there is only one element in the attachment carousel */
isSingleItem: boolean;

/** URL to full-sized attachment or SVG function */
source: AttachmentsPropTypes.attachmentSourcePropType.isRequired,
/** The index of the carousel item */
index?: number;

/** Additional information about the attachment file */
file: PropTypes.shape({
/** File name of the attachment */
name: PropTypes.string.isRequired,
}).isRequired,

/** Whether the attachment has been flagged */
hasBeenFlagged: PropTypes.bool,

/** The id of the transaction related to the attachment */
transactionID: PropTypes.string,

duration: PropTypes.number,
}).isRequired,
/** The index of the currently active carousel item */
activeIndex?: number;

/** onPress callback */
onPress: PropTypes.func,

isModalHovered: PropTypes.bool,

/** Whether the attachment is currently being viewed in the carousel */
isFocused: PropTypes.bool.isRequired,
};

const defaultProps = {
onPress: undefined,
isModalHovered: false,
onPress?: () => void;
};

function CarouselItem({item, onPress, isFocused, isModalHovered}) {
function CarouselItem({item, index, activeIndex, isSingleItem, onPress}: CarouselItemProps) {
const styles = useThemeStyles();
const {translate} = useLocalize();
const {isAttachmentHidden} = useContext(ReportAttachmentsContext);
// eslint-disable-next-line es/no-nullish-coalescing-operators
const [isHidden, setIsHidden] = useState(() => isAttachmentHidden(item.reportActionID) ?? item.hasBeenFlagged);
SzymczakJ marked this conversation as resolved.
Show resolved Hide resolved
const [isHidden, setIsHidden] = useState(() => (item.reportActionID ? isAttachmentHidden(item.reportActionID) : item.hasBeenFlagged));

const renderButton = (style) => (
const renderButton = (style: StyleProp<ViewStyle>) => (
<Button
small
style={style}
Expand All @@ -87,7 +63,7 @@ function CarouselItem({item, onPress, isFocused, isModalHovered}) {
style={[styles.attachmentRevealButtonContainer]}
onPress={onPress}
accessibilityRole={CONST.ACCESSIBILITY_ROLE.IMAGEBUTTON}
accessibilityLabel={item.file.name || translate('attachmentView.unknownFilename')}
accessibilityLabel={item.file?.name ?? translate('attachmentView.unknownFilename')}
>
SzymczakJ marked this conversation as resolved.
Show resolved Hide resolved
{children}
</PressableWithoutFeedback>
Expand All @@ -103,11 +79,12 @@ function CarouselItem({item, onPress, isFocused, isModalHovered}) {
source={item.source}
file={item.file}
isAuthTokenRequired={item.isAuthTokenRequired}
isUsedInCarousel
isSingleCarouselItem={isSingleItem}
SzymczakJ marked this conversation as resolved.
Show resolved Hide resolved
carouselItemIndex={index}
carouselActiveItemIndex={activeIndex}
onPress={onPress}
transactionID={item.transactionID}
isHovered={isModalHovered}
isFocused={isFocused}
optionalVideoDuration={item.duration}
transactionID={item.transactionID ?? ''}
/>
</View>

Expand All @@ -120,8 +97,6 @@ function CarouselItem({item, onPress, isFocused, isModalHovered}) {
);
}

CarouselItem.propTypes = propTypes;
CarouselItem.defaultProps = defaultProps;
CarouselItem.displayName = 'CarouselItem';

export default CarouselItem;
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import type {ForwardedRef} from 'react';
import type React from 'react';
import {createContext} from 'react';
import type PagerView from 'react-native-pager-view';
import type {SharedValue} from 'react-native-reanimated';

/** The pager items array is used within the pager to render and navigate between the images */
type AttachmentCarouselPagerItems = {
/** The source of the image is used to identify each attachment/page in the pager */
source: string;
source: string | number | React.FC;

/** The index of the pager item determines the order of the images in the pager */
index: number;
Expand Down
24 changes: 12 additions & 12 deletions src/components/Attachments/AttachmentCarousel/Pager/index.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import type {ForwardedRef} from 'react';
import React, {useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState} from 'react';
import type {NativeSyntheticEvent} from 'react-native';
import {View} from 'react-native';
import type {NativeViewGestureHandlerProps} from 'react-native-gesture-handler';
import {createNativeWrapper} from 'react-native-gesture-handler';
import type {PagerViewProps} from 'react-native-pager-view';
import PagerView from 'react-native-pager-view';
import Animated, {useAnimatedProps, useSharedValue} from 'react-native-reanimated';
import CarouselItem from '@components/Attachments/AttachmentCarousel/CarouselItem';
import type {Attachment} from '@components/Attachments/types';
import useThemeStyles from '@hooks/useThemeStyles';
import AttachmentCarouselPagerContext from './AttachmentCarouselPagerContext';
import usePageScrollHandler from './usePageScrollHandler';
Expand All @@ -20,22 +22,21 @@ type AttachmentCarouselPagerHandle = {
setPage: (selectedPage: number) => void;
};

type Attachment = {
source: string;
};

type AttachmentCarouselPagerProps = {
/** The attachments to be rendered in the pager. */
items: Attachment[];

/** The source (URL) of the currently active attachment. */
activeSource: string;

/** The index of the initial page to be rendered. */
initialPage: number;

/** A callback to be called when the page is changed. */
onPageSelected: () => void;
onPageSelected: (
event: NativeSyntheticEvent<
Readonly<{
position: number;
}>
>,
) => void;

/**
* A callback that can be used to toggle the attachment carousel arrows, when the scale of the image changes.
Expand All @@ -44,7 +45,7 @@ type AttachmentCarouselPagerProps = {
onRequestToggleArrows: (showArrows?: boolean) => void;
};

function AttachmentCarouselPager({items, activeSource, initialPage, onPageSelected, onRequestToggleArrows}: AttachmentCarouselPagerProps, ref: ForwardedRef<AttachmentCarouselPagerHandle>) {
function AttachmentCarouselPager({items, initialPage, onPageSelected, onRequestToggleArrows}: AttachmentCarouselPagerProps, ref: ForwardedRef<AttachmentCarouselPagerHandle>) {
const styles = useThemeStyles();
const pagerRef = useRef<PagerView>(null);

Expand Down Expand Up @@ -139,15 +140,13 @@ function AttachmentCarouselPager({items, activeSource, initialPage, onPageSelect

const carouselItems = items.map((item, index) => (
<View
key={item.source}
key={item.source as string}
SzymczakJ marked this conversation as resolved.
Show resolved Hide resolved
style={styles.flex1}
>
<CarouselItem
// @ts-expect-error TODO: Remove this once AttachmentView (https://github.com/Expensify/App/issues/25150) is migrated to TypeScript.
item={item}
isSingleItem={items.length === 1}
index={index}
isFocused={index === activePageIndex && activeSource === item.source}
/>
</View>
));
Expand All @@ -172,3 +171,4 @@ function AttachmentCarouselPager({items, activeSource, initialPage, onPageSelect
AttachmentCarouselPager.displayName = 'AttachmentCarouselPager';

export default React.forwardRef(AttachmentCarouselPager);
export type {AttachmentCarouselPagerHandle};
Loading
Loading