diff --git a/src/components/EReceipt.tsx b/src/components/EReceipt.tsx index 183d88ba1c6a..40f5d242d005 100644 --- a/src/components/EReceipt.tsx +++ b/src/components/EReceipt.tsx @@ -105,3 +105,4 @@ export default withOnyx({ key: ({transactionID}) => `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, }, })(EReceipt); +export type {EReceiptProps, EReceiptOnyxProps}; diff --git a/src/components/EReceiptThumbnail.tsx b/src/components/EReceiptThumbnail.tsx index f5f9b5fc5f06..023dcc16e696 100644 --- a/src/components/EReceiptThumbnail.tsx +++ b/src/components/EReceiptThumbnail.tsx @@ -114,3 +114,4 @@ export default withOnyx({ key: ({transactionID}) => `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, }, })(EReceiptThumbnail); +export type {EReceiptThumbnailProps, EReceiptThumbnailOnyxProps}; diff --git a/src/components/ReportActionItem/ReportActionItemImages.tsx b/src/components/ReportActionItem/ReportActionItemImages.tsx index 74ecc1a2adbd..ffc12957dcb4 100644 --- a/src/components/ReportActionItem/ReportActionItemImages.tsx +++ b/src/components/ReportActionItem/ReportActionItemImages.tsx @@ -109,3 +109,4 @@ function ReportActionItemImages({images, size, total, isHovered = false}: Report ReportActionItemImages.displayName = 'ReportActionItemImages'; export default ReportActionItemImages; +export type {ReportActionItemImagesProps}; diff --git a/src/stories/EReceipt.stories.js b/src/stories/EReceipt.stories.tsx similarity index 81% rename from src/stories/EReceipt.stories.js rename to src/stories/EReceipt.stories.tsx index d4f2b58cb213..f652c08df6f6 100644 --- a/src/stories/EReceipt.stories.js +++ b/src/stories/EReceipt.stories.tsx @@ -1,8 +1,13 @@ -/* eslint-disable rulesdir/prefer-actions-set-data */ +/* eslint-disable @typescript-eslint/naming-convention, rulesdir/prefer-actions-set-data */ +import type {ComponentMeta, ComponentStory} from '@storybook/react'; import React from 'react'; import Onyx from 'react-native-onyx'; +import type {EReceiptOnyxProps, EReceiptProps} from '@components/EReceipt'; import EReceipt from '@components/EReceipt'; import ONYXKEYS from '@src/ONYXKEYS'; +import type CollectionDataSet from '@src/types/utils/CollectionDataSet'; + +type EReceiptStory = ComponentStory; const transactionData = { [`${ONYXKEYS.COLLECTION.TRANSACTION}FAKE_1`]: { @@ -146,7 +151,7 @@ const transactionData = { created: '2023-01-11 13:46:20', hasEReceipt: true, }, -}; +} as CollectionDataSet; Onyx.mergeCollection(ONYXKEYS.COLLECTION.TRANSACTION, transactionData); Onyx.merge('cardList', { @@ -159,92 +164,92 @@ Onyx.merge('cardList', { * * https://storybook.js.org/docs/react/writing-stories/introduction#component-story-format */ -const story = { +const story: ComponentMeta = { title: 'Components/EReceipt', component: EReceipt, }; -function Template(args) { +function Template(props: Omit) { // eslint-disable-next-line react/jsx-props-no-spreading - return ; + return ; } -const Default = Template.bind({}); +const Default: EReceiptStory = Template.bind({}); Default.args = { transactionID: 'FAKE_1', }; -const Airlines = Template.bind({}); +const Airlines: EReceiptStory = Template.bind({}); Airlines.args = { transactionID: 'FAKE_2', }; -const Commuter = Template.bind({}); +const Commuter: EReceiptStory = Template.bind({}); Commuter.args = { transactionID: 'FAKE_3', }; -const Gas = Template.bind({}); +const Gas: EReceiptStory = Template.bind({}); Gas.args = { transactionID: 'FAKE_4', }; -const Goods = Template.bind({}); +const Goods: EReceiptStory = Template.bind({}); Goods.args = { transactionID: 'FAKE_5', }; -const Groceries = Template.bind({}); +const Groceries: EReceiptStory = Template.bind({}); Groceries.args = { transactionID: 'FAKE_6', }; -const Hotel = Template.bind({}); +const Hotel: EReceiptStory = Template.bind({}); Hotel.args = { transactionID: 'FAKE_7', }; -const Mail = Template.bind({}); +const Mail: EReceiptStory = Template.bind({}); Mail.args = { transactionID: 'FAKE_8', }; -const Meals = Template.bind({}); +const Meals: EReceiptStory = Template.bind({}); Meals.args = { transactionID: 'FAKE_9', }; -const Rental = Template.bind({}); +const Rental: EReceiptStory = Template.bind({}); Rental.args = { transactionID: 'FAKE_10', }; -const Services = Template.bind({}); +const Services: EReceiptStory = Template.bind({}); Services.args = { transactionID: 'FAKE_11', }; -const Taxi = Template.bind({}); +const Taxi: EReceiptStory = Template.bind({}); Taxi.args = { transactionID: 'FAKE_12', }; -const Miscellaneous = Template.bind({}); +const Miscellaneous: EReceiptStory = Template.bind({}); Miscellaneous.args = { transactionID: 'FAKE_13', }; -const Utilities = Template.bind({}); +const Utilities: EReceiptStory = Template.bind({}); Utilities.args = { transactionID: 'FAKE_14', }; -const invalidMCC = Template.bind({}); +const invalidMCC: EReceiptStory = Template.bind({}); invalidMCC.args = { transactionID: 'FAKE_15', }; -const veryLong = Template.bind({}); +const veryLong: EReceiptStory = Template.bind({}); veryLong.args = { transactionID: 'FAKE_16', }; diff --git a/src/stories/EReceiptThumbail.stories.js b/src/stories/EReceiptThumbail.stories.tsx similarity index 62% rename from src/stories/EReceiptThumbail.stories.js rename to src/stories/EReceiptThumbail.stories.tsx index bea32fb0213c..1feb811e57c8 100644 --- a/src/stories/EReceiptThumbail.stories.js +++ b/src/stories/EReceiptThumbail.stories.tsx @@ -1,52 +1,56 @@ /* eslint-disable react/jsx-props-no-spreading */ +import type {ComponentMeta, ComponentStory} from '@storybook/react'; import React from 'react'; import {View} from 'react-native'; +import type {EReceiptThumbnailOnyxProps, EReceiptThumbnailProps} from '@components/EReceiptThumbnail'; import EReceiptThumbnail from '@components/EReceiptThumbnail'; +type EReceiptThumbnailStory = ComponentStory; + /** * We use the Component Story Format for writing stories. Follow the docs here: * * https://storybook.js.org/docs/react/writing-stories/introduction#component-story-format */ -const story = { +const story: ComponentMeta = { title: 'Components/EReceiptThumbnail', component: EReceiptThumbnail, }; -function Template(args) { +function Template(props: Omit) { return ( @@ -54,77 +58,77 @@ function Template(args) { ); } -const Default = Template.bind({}); +const Default: EReceiptThumbnailStory = Template.bind({}); Default.args = { transactionID: 'FAKE_1', }; -const Airlines = Template.bind({}); +const Airlines: EReceiptThumbnailStory = Template.bind({}); Airlines.args = { transactionID: 'FAKE_2', }; -const Commuter = Template.bind({}); +const Commuter: EReceiptThumbnailStory = Template.bind({}); Commuter.args = { transactionID: 'FAKE_3', }; -const Gas = Template.bind({}); +const Gas: EReceiptThumbnailStory = Template.bind({}); Gas.args = { transactionID: 'FAKE_4', }; -const Goods = Template.bind({}); +const Goods: EReceiptThumbnailStory = Template.bind({}); Goods.args = { transactionID: 'FAKE_5', }; -const Groceries = Template.bind({}); +const Groceries: EReceiptThumbnailStory = Template.bind({}); Groceries.args = { transactionID: 'FAKE_6', }; -const Hotel = Template.bind({}); +const Hotel: EReceiptThumbnailStory = Template.bind({}); Hotel.args = { transactionID: 'FAKE_7', }; -const Mail = Template.bind({}); +const Mail: EReceiptThumbnailStory = Template.bind({}); Mail.args = { transactionID: 'FAKE_8', }; -const Meals = Template.bind({}); +const Meals: EReceiptThumbnailStory = Template.bind({}); Meals.args = { transactionID: 'FAKE_9', }; -const Rental = Template.bind({}); +const Rental: EReceiptThumbnailStory = Template.bind({}); Rental.args = { transactionID: 'FAKE_10', }; -const Services = Template.bind({}); +const Services: EReceiptThumbnailStory = Template.bind({}); Services.args = { transactionID: 'FAKE_11', }; -const Taxi = Template.bind({}); +const Taxi: EReceiptThumbnailStory = Template.bind({}); Taxi.args = { transactionID: 'FAKE_12', }; -const Miscellaneous = Template.bind({}); +const Miscellaneous: EReceiptThumbnailStory = Template.bind({}); Miscellaneous.args = { transactionID: 'FAKE_13', }; -const Utilities = Template.bind({}); +const Utilities: EReceiptThumbnailStory = Template.bind({}); Utilities.args = { transactionID: 'FAKE_14', }; -const invalidMCC = Template.bind({}); +const invalidMCC: EReceiptThumbnailStory = Template.bind({}); invalidMCC.args = { transactionID: 'FAKE_15', }; diff --git a/src/stories/ReportActionItemImages.stories.js b/src/stories/ReportActionItemImages.stories.tsx similarity index 84% rename from src/stories/ReportActionItemImages.stories.js rename to src/stories/ReportActionItemImages.stories.tsx index fe86f50f7e34..810b3e18aaf3 100644 --- a/src/stories/ReportActionItemImages.stories.js +++ b/src/stories/ReportActionItemImages.stories.tsx @@ -1,18 +1,22 @@ +import type {ComponentMeta, ComponentStory} from '@storybook/react'; import React from 'react'; import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeedback'; +import type {ReportActionItemImagesProps} from '@components/ReportActionItem/ReportActionItemImages'; import ReportActionItemImages from '@components/ReportActionItem/ReportActionItemImages'; +type ReportActionItemImagesStory = ComponentStory; + /** * We use the Component Story Format for writing stories. Follow the docs here: * * https://storybook.js.org/docs/react/writing-stories/introduction#component-story-format */ -const story = { +const story: ComponentMeta = { title: 'Components/ReportActionItemImages', component: ReportActionItemImages, }; -function Template(args) { +function Template(props: ReportActionItemImagesProps) { return ( ( )} @@ -31,14 +35,14 @@ function Template(args) { // Arguments can be passed to the component by binding // See: https://storybook.js.org/docs/react/writing-stories/introduction#using-args -const Default = Template.bind({}); +const Default: ReportActionItemImagesStory = Template.bind({}); Default.args = { images: [{image: 'https://c02.purpledshub.com/uploads/sites/41/2021/05/sleeping-cat-27126ee.jpg', thumbnail: ''}], size: 1, total: 1, }; -const DisplayEReceipt = Template.bind({}); +const DisplayEReceipt: ReportActionItemImagesStory = Template.bind({}); DisplayEReceipt.args = { images: [ { @@ -53,6 +57,8 @@ DisplayEReceipt.args = { mccGroup: 'Commuter', created: '2023-07-24 13:46:20', hasEReceipt: true, + comment: {}, + reportID: 'REPORT_1', }, }, ], @@ -60,7 +66,7 @@ DisplayEReceipt.args = { total: 1, }; -const DisplayMultipleEReceipts = Template.bind({}); +const DisplayMultipleEReceipts: ReportActionItemImagesStory = Template.bind({}); DisplayMultipleEReceipts.args = { images: [ { @@ -75,6 +81,8 @@ DisplayMultipleEReceipts.args = { mccGroup: 'Commuter', created: '2023-07-24 13:46:20', hasEReceipt: true, + comment: {}, + reportID: 'REPORT_1', }, }, { @@ -89,6 +97,8 @@ DisplayMultipleEReceipts.args = { mccGroup: 'Goods', created: '2022-03-21 13:46:20', hasEReceipt: true, + comment: {}, + reportID: 'REPORT_2', }, }, { @@ -103,6 +113,8 @@ DisplayMultipleEReceipts.args = { mccGroup: 'Airlines', created: '2023-07-24 13:46:20', hasEReceipt: true, + comment: {}, + reportID: 'REPORT_3', }, }, ], @@ -110,7 +122,7 @@ DisplayMultipleEReceipts.args = { total: 3, }; -const TwoImages = Template.bind({}); +const TwoImages: ReportActionItemImagesStory = Template.bind({}); TwoImages.args = { images: [ { @@ -126,7 +138,7 @@ TwoImages.args = { total: 2, }; -const ThreeImages = Template.bind({}); +const ThreeImages: ReportActionItemImagesStory = Template.bind({}); ThreeImages.args = { images: [ { @@ -146,7 +158,7 @@ ThreeImages.args = { total: 3, }; -const FourImages = Template.bind({}); +const FourImages: ReportActionItemImagesStory = Template.bind({}); FourImages.args = { images: [ { @@ -170,7 +182,7 @@ FourImages.args = { total: 4, }; -const ThreePlusTwoImages = Template.bind({}); +const ThreePlusTwoImages: ReportActionItemImagesStory = Template.bind({}); ThreePlusTwoImages.args = { images: [ { @@ -190,7 +202,7 @@ ThreePlusTwoImages.args = { total: 5, }; -const ThreePlusTenImages = Template.bind({}); +const ThreePlusTenImages: ReportActionItemImagesStory = Template.bind({}); ThreePlusTenImages.args = { images: [ { diff --git a/src/stories/SelectionList.stories.js b/src/stories/SelectionList.stories.tsx similarity index 63% rename from src/stories/SelectionList.stories.js rename to src/stories/SelectionList.stories.tsx index 6c289097552b..aeef37589761 100644 --- a/src/stories/SelectionList.stories.js +++ b/src/stories/SelectionList.stories.tsx @@ -1,18 +1,22 @@ +import type {ComponentMeta} from '@storybook/react'; import React, {useMemo, useState} from 'react'; -import _ from 'underscore'; import Badge from '@components/Badge'; import SelectionList from '@components/SelectionList'; import RadioListItem from '@components/SelectionList/RadioListItem'; +import type {BaseSelectionListProps, ListItem} from '@components/SelectionList/types'; +import withNavigationFallback from '@components/withNavigationFallback'; // eslint-disable-next-line no-restricted-imports import {defaultStyles} from '@styles/index'; import CONST from '@src/CONST'; +const SelectionListWithNavigation = withNavigationFallback(SelectionList); + /** * We use the Component Story Format for writing stories. Follow the docs here: * * https://storybook.js.org/docs/react/writing-stories/introduction#component-story-format */ -const story = { +const story: ComponentMeta = { title: 'Components/SelectionList', component: SelectionList, }; @@ -62,32 +66,32 @@ const SECTIONS = [ }, ]; -function Default(args) { +function Default(props: BaseSelectionListProps) { const [selectedIndex, setSelectedIndex] = useState(1); - const sections = _.map(args.sections, (section) => { - const data = _.map(section.data, (item, index) => { - const isSelected = selectedIndex === index + section.indexOffset; + const sections = props.sections.map((section) => { + const data = section.data.map((item, index) => { + const isSelected = selectedIndex === index + (section?.indexOffset ?? 0); return {...item, isSelected}; }); return {...section, data}; }); - const onSelectRow = (item) => { - _.forEach(sections, (section) => { - const newSelectedIndex = _.findIndex(section.data, (option) => option.keyForList === item.keyForList); + const onSelectRow = (item: ListItem) => { + sections.forEach((section) => { + const newSelectedIndex = section.data.findIndex((option) => option.keyForList === item.keyForList); if (newSelectedIndex >= 0) { - setSelectedIndex(newSelectedIndex + section.indexOffset); + setSelectedIndex(newSelectedIndex + (section?.indexOffset ?? 0)); } }); }; return ( - ) { const [searchText, setSearchText] = useState(''); const [selectedIndex, setSelectedIndex] = useState(1); - const sections = _.map(args.sections, (section) => { - const data = _.reduce( - section.data, - (memo, item, index) => { - if (!item.text.toLowerCase().includes(searchText.trim().toLowerCase())) { - return memo; - } - - const isSelected = selectedIndex === index + section.indexOffset; - memo.push({...item, isSelected}); + const sections = props.sections.map((section) => { + const data = section.data.reduce((memo, item, index) => { + if (!item.text.toLowerCase().includes(searchText.trim().toLowerCase())) { return memo; - }, - [], - ); + } + + const isSelected = selectedIndex === index + (section?.indexOffset ?? 0); + memo.push({...item, isSelected}); + return memo; + }, []); return {...section, data}; }); - const onSelectRow = (item) => { - _.forEach(sections, (section) => { - const newSelectedIndex = _.findIndex(section.data, (option) => option.keyForList === item.keyForList); + const onSelectRow = (item: ListItem) => { + sections.forEach((section) => { + const newSelectedIndex = section.data.findIndex((option) => option.keyForList === item.keyForList); if (newSelectedIndex >= 0) { - setSelectedIndex(newSelectedIndex + section.indexOffset); + setSelectedIndex(newSelectedIndex + (section?.indexOffset ?? 0)); } }); }; return ( - {}, }; -function WithHeaderMessage(props) { +function WithHeaderMessage(props: BaseSelectionListProps) { return ( ) { const [selectedIndex, setSelectedIndex] = useState(1); - const sections = _.map(args.sections, (section) => { - const data = _.map(section.data, (item, index) => { - const isSelected = selectedIndex === index + section.indexOffset; + const sections = props.sections.map((section) => { + const data = section.data.map((item, index) => { + const isSelected = selectedIndex === index + (section?.indexOffset ?? 0); return { ...item, @@ -189,21 +189,22 @@ function WithAlternateText(args) { return {...section, data}; }); - const onSelectRow = (item) => { - _.forEach(sections, (section) => { - const newSelectedIndex = _.findIndex(section.data, (option) => option.keyForList === item.keyForList); + const onSelectRow = (item: ListItem) => { + sections.forEach((section) => { + const newSelectedIndex = section.data.findIndex((option) => option.keyForList === item.keyForList); if (newSelectedIndex >= 0) { - setSelectedIndex(newSelectedIndex + section.indexOffset); + setSelectedIndex(newSelectedIndex + (section?.indexOffset ?? 0)); } }); }; return ( - ); } @@ -212,23 +213,23 @@ WithAlternateText.args = { ...Default.args, }; -function MultipleSelection(args) { +function MultipleSelection(props: BaseSelectionListProps) { const [selectedIds, setSelectedIds] = useState(['option-1', 'option-2']); const memo = useMemo(() => { - const allIds = []; + const allIds: string[] = []; - const sections = _.map(args.sections, (section) => { - const data = _.map(section.data, (item, index) => { + const sections = props.sections.map((section) => { + const data = section.data.map((item, index) => { allIds.push(item.keyForList); - const isSelected = _.contains(selectedIds, item.keyForList); - const isAdmin = index + section.indexOffset === 0; + const isSelected = selectedIds.includes(item.keyForList); + const isAdmin = index + (section?.indexOffset ?? 0) === 0; return { ...item, isSelected, alternateText: `${item.keyForList}@email.com`, - accountID: item.keyForList, + accountID: Number(item.keyForList), login: item.text, rightElement: isAdmin && ( { - const newSelectedIds = _.contains(selectedIds, item.keyForList) ? _.without(selectedIds, item.keyForList) : [...selectedIds, item.keyForList]; + const onSelectRow = (item: ListItem) => { + const newSelectedIds = selectedIds.includes(item.keyForList) ? selectedIds.filter((id) => id !== item.keyForList) : [...selectedIds, item.keyForList]; setSelectedIds(newSelectedIds); }; @@ -260,9 +261,9 @@ function MultipleSelection(args) { }; return ( - {}, }; -function WithSectionHeader(args) { +function WithSectionHeader(props: BaseSelectionListProps) { const [selectedIds, setSelectedIds] = useState(['option-1', 'option-2']); const memo = useMemo(() => { - const allIds = []; + const allIds: string[] = []; - const sections = _.map(args.sections, (section, sectionIndex) => { - const data = _.map(section.data, (item, itemIndex) => { + const sections = props.sections.map((section, sectionIndex) => { + const data = section.data.map((item, itemIndex) => { allIds.push(item.keyForList); - const isSelected = _.contains(selectedIds, item.keyForList); - const isAdmin = itemIndex + section.indexOffset === 0; + const isSelected = selectedIds.includes(item.keyForList); + const isAdmin = itemIndex + (section?.indexOffset ?? 0) === 0; return { ...item, isSelected, alternateText: `${item.keyForList}@email.com`, - accountID: item.keyForList, + accountID: Number(item.keyForList), login: item.text, rightElement: isAdmin && ( { - const newSelectedIds = _.contains(selectedIds, item.keyForList) ? _.without(selectedIds, item.keyForList) : [...selectedIds, item.keyForList]; + const onSelectRow = (item: ListItem) => { + const newSelectedIds = selectedIds.includes(item.keyForList) ? selectedIds.filter((id) => id !== item.keyForList) : [...selectedIds, item.keyForList]; setSelectedIds(newSelectedIds); }; @@ -325,9 +326,9 @@ function WithSectionHeader(args) { }; return ( - ) { const [selectedIds, setSelectedIds] = useState(['option-1', 'option-2']); const memo = useMemo(() => { - const allIds = []; + const allIds: string[] = []; - const sections = _.map(args.sections, (section, sectionIndex) => { - const data = _.map(section.data, (item, itemIndex) => { + const sections = props.sections.map((section, sectionIndex) => { + const data = section.data.map((item, itemIndex) => { allIds.push(item.keyForList); - const isSelected = _.contains(selectedIds, item.keyForList); - const isAdmin = itemIndex + section.indexOffset === 0; + const isSelected = selectedIds.includes(item.keyForList); + const isAdmin = itemIndex + (section.indexOffset ?? 0) === 0; return { ...item, isSelected, alternateText: `${item.keyForList}@email.com`, - accountID: item.keyForList, + accountID: Number(item.keyForList), login: item.text, rightElement: isAdmin && ( { - const newSelectedIds = _.contains(selectedIds, item.keyForList) ? _.without(selectedIds, item.keyForList) : [...selectedIds, item.keyForList]; + const onSelectRow = (item: ListItem) => { + const newSelectedIds = selectedIds.includes(item.keyForList) ? selectedIds.filter((id) => id !== item.keyForList) : [...selectedIds, item.keyForList]; setSelectedIds(newSelectedIds); }; @@ -388,9 +389,9 @@ function WithConfirmButton(args) { }; return ( -