diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 259c0fc3c786..1fa7a5e90532 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -1322,6 +1322,11 @@ const ROUTES = { getRoute: (action: IOUAction, iouType: IOUType, transactionID: string | undefined, reportID: string | undefined, reportActionID?: string) => `${action as string}/${iouType as string}/hours/${transactionID}/${reportID}${reportActionID ? `/${reportActionID}` : ''}` as const, }, + MONEY_REQUEST_STEP_HOURS_EDIT: { + route: ':action/:iouType/hours-edit/:transactionID/:reportID/:reportActionID?', + getRoute: (action: IOUAction, iouType: IOUType, transactionID: string | undefined, reportID: string | undefined, reportActionID?: string) => + `${action as string}/${iouType as string}/hours-edit/${transactionID}/${reportID}${reportActionID ? `/${reportActionID}` : ''}` as const, + }, DISTANCE_REQUEST_CREATE: { route: ':action/:iouType/start/:transactionID/:reportID/distance-new/:backToReport?', getRoute: (action: IOUAction, iouType: IOUType, transactionID: string, reportID: string, backToReport?: string) => diff --git a/src/SCREENS.ts b/src/SCREENS.ts index 9744c56eac72..05639da43c40 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -335,6 +335,7 @@ const SCREENS = { RECEIPT_PREVIEW: 'Money_Request_Receipt_preview', STEP_TIME_RATE: 'Money_Request_Step_Time_Rate', STEP_HOURS: 'Money_Request_Step_Hours', + STEP_HOURS_EDIT: 'Money_Request_Step_Hours_Edit', }, TRANSACTION_DUPLICATE: { diff --git a/src/components/MoneyRequestConfirmationListFooter.tsx b/src/components/MoneyRequestConfirmationListFooter.tsx index 6fcceb76361a..40602eea1269 100644 --- a/src/components/MoneyRequestConfirmationListFooter.tsx +++ b/src/components/MoneyRequestConfirmationListFooter.tsx @@ -624,7 +624,7 @@ function MoneyRequestConfirmationListFooter({ if (!transactionID) { return; } - Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_HOURS.getRoute(action, iouType, transactionID, reportID, reportActionID)); + Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_HOURS_EDIT.getRoute(action, iouType, transactionID, reportID, reportActionID)); }} disabled={didConfirm} interactive={!isReadOnly} diff --git a/src/languages/pl.ts b/src/languages/pl.ts index f92c16c60000..5ca64d9b2971 100644 --- a/src/languages/pl.ts +++ b/src/languages/pl.ts @@ -500,7 +500,7 @@ const translations: TranslationDeepObject = { role: 'Rola', currency: 'Waluta', groupCurrency: 'Waluta grupy', - rate: 'Oceń', + rate: 'Stawka', emptyLHN: { title: 'Juhu! Wszystko nadrobione.', subtitleText1: 'Znajdź czat za pomocą', diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx index 7bdfeca882ef..24a0bd920d25 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx @@ -188,6 +188,7 @@ const MoneyRequestModalStackNavigator = createModalStackNavigator require('../../../../pages/SetDefaultWorkspacePage').default, [SCREENS.MONEY_REQUEST.STEP_TIME_RATE]: () => require('../../../../pages/iou/request/step/IOURequestStepTimeRate').default, [SCREENS.MONEY_REQUEST.STEP_HOURS]: () => require('../../../../pages/iou/request/step/IOURequestStepHours').default, + [SCREENS.MONEY_REQUEST.STEP_HOURS_EDIT]: () => require('../../../../pages/iou/request/step/IOURequestStepHours').default, }); const TravelModalStackNavigator = createModalStackNavigator({ diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts index b074d45f234a..cde68cfe329d 100644 --- a/src/libs/Navigation/linkingConfig/config.ts +++ b/src/libs/Navigation/linkingConfig/config.ts @@ -1524,6 +1524,7 @@ const config: LinkingOptions['config'] = { [SCREENS.MONEY_REQUEST.STEP_SUBRATE_EDIT]: ROUTES.MONEY_REQUEST_STEP_SUBRATE_EDIT.route, [SCREENS.MONEY_REQUEST.STEP_TIME_RATE]: ROUTES.MONEY_REQUEST_STEP_TIME_RATE.route, [SCREENS.MONEY_REQUEST.STEP_HOURS]: ROUTES.MONEY_REQUEST_STEP_HOURS.route, + [SCREENS.MONEY_REQUEST.STEP_HOURS_EDIT]: ROUTES.MONEY_REQUEST_STEP_HOURS_EDIT.route, [SCREENS.IOU_SEND.ENABLE_PAYMENTS]: ROUTES.IOU_SEND_ENABLE_PAYMENTS, [SCREENS.IOU_SEND.ADD_BANK_ACCOUNT]: ROUTES.IOU_SEND_ADD_BANK_ACCOUNT, [SCREENS.IOU_SEND.ADD_DEBIT_CARD]: ROUTES.IOU_SEND_ADD_DEBIT_CARD, diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index 3a6f8cec8c1e..4d502cd55e51 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -1958,6 +1958,13 @@ type MoneyRequestNavigatorParamList = { reportID: string; reportActionID: string; }; + [SCREENS.MONEY_REQUEST.STEP_HOURS_EDIT]: { + action: IOUAction; + iouType: Exclude; + transactionID: string; + reportID: string; + reportActionID: string; + }; }; type WorkspaceConfirmationNavigatorParamList = { diff --git a/src/libs/PolicyUtils.ts b/src/libs/PolicyUtils.ts index b2bee250eb7c..f6e587978cf9 100644 --- a/src/libs/PolicyUtils.ts +++ b/src/libs/PolicyUtils.ts @@ -107,6 +107,10 @@ function getActivePoliciesWithExpenseChatAndPerDiemEnabledAndHasRates(policies: }); } +function getActivePoliciesWithExpenseChatAndTimeEnabled(policies: OnyxCollection | null, currentUserLogin: string | undefined): Policy[] { + return getActivePoliciesWithExpenseChat(policies, currentUserLogin).filter(isTimeTrackingEnabled); +} + /** * Checks if the current user is an admin of the policy. */ @@ -1853,6 +1857,7 @@ export { isDefaultTagName, isTimeTrackingEnabled, getDefaultTimeTrackingRate, + getActivePoliciesWithExpenseChatAndTimeEnabled, }; export type {MemberEmailsToAccountIDs}; diff --git a/src/pages/iou/request/IOURequestStartPage.tsx b/src/pages/iou/request/IOURequestStartPage.tsx index fb6356974cd4..a9499551414a 100644 --- a/src/pages/iou/request/IOURequestStartPage.tsx +++ b/src/pages/iou/request/IOURequestStartPage.tsx @@ -30,6 +30,7 @@ import {getIsUserSubmittedExpenseOrScannedReceipt} from '@libs/OptionsListUtils' import Performance from '@libs/Performance'; import { getActivePoliciesWithExpenseChatAndPerDiemEnabledAndHasRates, + getActivePoliciesWithExpenseChatAndTimeEnabled, getPerDiemCustomUnit, hasOnlyPersonalPolicies as hasOnlyPersonalPoliciesUtil, isTimeTrackingEnabled, @@ -51,6 +52,7 @@ import IOURequestStepDistance from './step/IOURequestStepDistance'; import IOURequestStepHours from './step/IOURequestStepHours'; import IOURequestStepPerDiemWorkspace from './step/IOURequestStepPerDiemWorkspace'; import IOURequestStepScan from './step/IOURequestStepScan'; +import IOURequestStepTimeWorkspace from './step/IOURequestStepTimeWorkspace'; import type {WithWritableReportOrNotFoundProps} from './step/withWritableReportOrNotFound'; type IOURequestStartPageProps = WithWritableReportOrNotFoundProps & { @@ -126,6 +128,10 @@ function IOURequestStartPage({ () => getActivePoliciesWithExpenseChatAndPerDiemEnabledAndHasRates(allPolicies, currentUserPersonalDetails.login), [allPolicies, currentUserPersonalDetails.login], ); + const policiesWithTimeEnabled = useMemo( + () => getActivePoliciesWithExpenseChatAndTimeEnabled(allPolicies, currentUserPersonalDetails.login), + [allPolicies, currentUserPersonalDetails.login], + ); const doesPerDiemPolicyExist = policiesWithPerDiemEnabledAndHasRates.length > 0; const moreThanOnePerDiemExist = policiesWithPerDiemEnabledAndHasRates.length > 1; const hasCurrentPolicyPerDiemEnabled = !!policy?.arePerDiemRatesEnabled; @@ -262,7 +268,10 @@ function IOURequestStartPage({ }, }, ); - const shouldShowTimeOption = isBetaEnabled(CONST.BETAS.TIME_TRACKING) && iouType === CONST.IOU.TYPE.SUBMIT && !isFromGlobalCreate && hasCurrentPolicyTimeTrackingEnabled; + const shouldShowTimeOption = + isBetaEnabled(CONST.BETAS.TIME_TRACKING) && + (iouType === CONST.IOU.TYPE.SUBMIT || iouType === CONST.IOU.TYPE.CREATE) && + ((!isFromGlobalCreate && hasCurrentPolicyTimeTrackingEnabled) || (isFromGlobalCreate && !!policiesWithTimeEnabled.length)); const onBackButtonPress = () => { navigateBack(); @@ -380,10 +389,18 @@ function IOURequestStartPage({ {() => ( - + {isFromGlobalCreate && policiesWithTimeEnabled.length > 1 ? ( + + ) : ( + + )} )} diff --git a/src/pages/iou/request/step/BaseRequestStepWorkspace.tsx b/src/pages/iou/request/step/BaseRequestStepWorkspace.tsx new file mode 100644 index 000000000000..fbb74d2aa9bb --- /dev/null +++ b/src/pages/iou/request/step/BaseRequestStepWorkspace.tsx @@ -0,0 +1,106 @@ +import React from 'react'; +import {View} from 'react-native'; +import type {OnyxCollection, OnyxEntry} from 'react-native-onyx'; +import SearchBar from '@components/SearchBar'; +import SelectionList from '@components/SelectionList'; +import type {ListItem} from '@components/SelectionList/ListItem/types'; +import UserListItem from '@components/SelectionList/ListItem/UserListItem'; +import Text from '@components/Text'; +import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; +import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; +import useLocalize from '@hooks/useLocalize'; +import useOnyx from '@hooks/useOnyx'; +import useSearchResults from '@hooks/useSearchResults'; +import useThemeStyles from '@hooks/useThemeStyles'; +import {sortWorkspacesBySelected} from '@libs/PolicyUtils'; +import {getDefaultWorkspaceAvatar} from '@libs/ReportUtils'; +import tokenizedSearch from '@libs/tokenizedSearch'; +import CONST from '@src/CONST'; +import ONYXKEYS from '@src/ONYXKEYS'; +import type SCREENS from '@src/SCREENS'; +import type {Policy} from '@src/types/onyx'; +import type {WithFullTransactionOrNotFoundProps} from './withFullTransactionOrNotFound'; +import withFullTransactionOrNotFound from './withFullTransactionOrNotFound'; + +type WorkspaceListItem = ListItem & { + value: string; +}; + +type BaseRequestStepWorkspaceProps = WithFullTransactionOrNotFoundProps & { + /** Function returning available workspaces for the list. */ + getPolicies: (allPolicies: OnyxCollection, currentUserLogin: string | undefined) => Policy[]; + + /** Function to run after selecting a workspace. */ + onSelectWorkspace: (policy: OnyxEntry) => void; +}; + +function BaseRequestStepWorkspace({transaction, getPolicies, onSelectWorkspace}: BaseRequestStepWorkspaceProps) { + const icons = useMemoizedLazyExpensifyIcons(['FallbackWorkspaceAvatar']); + const styles = useThemeStyles(); + const {translate, localeCompare} = useLocalize(); + + const {login: currentUserLogin} = useCurrentUserPersonalDetails(); + const [allPolicies] = useOnyx(ONYXKEYS.COLLECTION.POLICY, {canBeMissing: true}); + const selectedWorkspace = transaction?.participants?.[0]; + const availableWorkspaces = getPolicies(allPolicies, currentUserLogin); + const workspaceOptions: WorkspaceListItem[] = availableWorkspaces + .sort((policy1, policy2) => + sortWorkspacesBySelected( + {policyID: policy1.id, name: policy1.name}, + {policyID: policy2.id, name: policy2.name}, + selectedWorkspace?.policyID ? [selectedWorkspace?.policyID] : [], + localeCompare, + ), + ) + .map((policy) => ({ + text: policy.name, + value: policy.id, + keyForList: policy.id, + icons: [ + { + id: policy.id, + source: policy?.avatarURL ? policy.avatarURL : getDefaultWorkspaceAvatar(policy.name), + fallbackIcon: icons.FallbackWorkspaceAvatar, + name: policy.name, + type: CONST.ICON_TYPE_WORKSPACE, + }, + ], + isSelected: selectedWorkspace?.policyID === policy.id, + })); + + const filterWorkspace = (workspaceOption: WorkspaceListItem, searchInput: string) => { + const results = tokenizedSearch([workspaceOption], searchInput, (option) => [option.text ?? '']); + return results.length > 0; + }; + const sortWorkspaces = (data: WorkspaceListItem[]) => data.sort((a, b) => localeCompare(a.text ?? '', b?.text ?? '')); + const [inputValue, setInputValue, filteredWorkspaceOptions] = useSearchResults(workspaceOptions, filterWorkspace, sortWorkspaces); + + const selectWorkspace = (item: WorkspaceListItem) => onSelectWorkspace(allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${item.value}`]); + + return ( + <> + {workspaceOptions.length > CONST.SEARCH_ITEM_LIMIT ? ( + 0 && filteredWorkspaceOptions.length === 0} + /> + ) : ( + + {translate('iou.chooseWorkspace')} + + )} + + + ); +} + +export default withFullTransactionOrNotFound(BaseRequestStepWorkspace); diff --git a/src/pages/iou/request/step/IOURequestStepHours.tsx b/src/pages/iou/request/step/IOURequestStepHours.tsx index 1a25f4b28779..df9a527a9f2b 100644 --- a/src/pages/iou/request/step/IOURequestStepHours.tsx +++ b/src/pages/iou/request/step/IOURequestStepHours.tsx @@ -10,10 +10,12 @@ import useOnyx from '@hooks/useOnyx'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useShowNotFoundPageInIOUStep from '@hooks/useShowNotFoundPageInIOUStep'; import useThemeStyles from '@hooks/useThemeStyles'; +import {setTransactionReport} from '@libs/actions/Transaction'; import {canUseTouchScreen as canUseTouchScreenUtil} from '@libs/DeviceCapabilities'; import {shouldUseTransactionDraft} from '@libs/IOUUtils'; import Navigation from '@libs/Navigation/Navigation'; import {getDefaultTimeTrackingRate} from '@libs/PolicyUtils'; +import {getPolicyExpenseChat} from '@libs/ReportUtils'; import {computeTimeAmount, formatTimeMerchant} from '@libs/TimeTrackingUtils'; import variables from '@styles/variables'; import {setMoneyRequestAmount, setMoneyRequestMerchant, setMoneyRequestParticipantsFromReport, setMoneyRequestTimeCount, setMoneyRequestTimeRate} from '@userActions/IOU'; @@ -27,8 +29,12 @@ import withFullTransactionOrNotFound from './withFullTransactionOrNotFound'; import type {WithWritableReportOrNotFoundProps} from './withWritableReportOrNotFound'; import withWritableReportOrNotFound from './withWritableReportOrNotFound'; -type IOURequestStepHoursProps = WithWritableReportOrNotFoundProps & - WithFullTransactionOrNotFoundProps; +type IOURequestStepHoursProps = WithWritableReportOrNotFoundProps< + typeof SCREENS.MONEY_REQUEST.CREATE | typeof SCREENS.MONEY_REQUEST.STEP_HOURS | typeof SCREENS.MONEY_REQUEST.STEP_HOURS_EDIT +> & + WithFullTransactionOrNotFoundProps & { + explicitPolicyID?: string; + }; function IOURequestStepHours({ report, @@ -37,9 +43,11 @@ function IOURequestStepHours({ name: routeName, }, transaction, + explicitPolicyID, }: IOURequestStepHoursProps) { - const isEditingConfirmation = routeName === SCREENS.MONEY_REQUEST.STEP_HOURS; - const policyID = report?.policyID; + const isEditingConfirmation = routeName === SCREENS.MONEY_REQUEST.STEP_HOURS_EDIT; + const isEmbeddedInStartPage = routeName === SCREENS.MONEY_REQUEST.CREATE; + const policyID = explicitPolicyID ?? report?.policyID; const isTransactionDraft = shouldUseTransactionDraft(action); const [selectedTab] = useOnyx(`${ONYXKEYS.COLLECTION.SELECTED_TAB}${CONST.TAB.IOU_REQUEST_TYPE}`, {canBeMissing: true}); const {accountID} = useCurrentUserPersonalDetails(); @@ -96,18 +104,36 @@ function IOURequestStepHours({ navigateBack(); return; } + setMoneyRequestTimeRate(transactionID, rate, isTransactionDraft); - setMoneyRequestParticipantsFromReport(transactionID, report, accountID).then(() => - Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(CONST.IOU.ACTION.CREATE, iouType, transactionID, reportID)), - ); + + if (isEmbeddedInStartPage) { + if (explicitPolicyID) { + const policyExpenseChat = getPolicyExpenseChat(accountID, policyID); + if (!policyExpenseChat) { + console.error(`Couldn't find policy expense chat for policyID: ${policyID}`); + return; + } + + setTransactionReport(transactionID, {reportID: policyExpenseChat.reportID}, isTransactionDraft); + setMoneyRequestParticipantsFromReport(transactionID, policyExpenseChat, accountID); + + return Navigation.setNavigationActionToMicrotaskQueue(() => + Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(CONST.IOU.ACTION.CREATE, iouType, transactionID, policyExpenseChat.reportID)), + ); + } + setMoneyRequestParticipantsFromReport(transactionID, report, accountID); + } + + Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(CONST.IOU.ACTION.CREATE, iouType, transactionID, reportID)); }; return ( @@ -146,9 +172,4 @@ function IOURequestStepHours({ ); } -// eslint-disable-next-line rulesdir/no-negated-variables -const IOURequestStepHoursWithWritableReportOrNotFound = withWritableReportOrNotFound(IOURequestStepHours); -// eslint-disable-next-line rulesdir/no-negated-variables -const IOURequestStepHoursWithFullTransactionOrNotFound = withFullTransactionOrNotFound(IOURequestStepHoursWithWritableReportOrNotFound); - -export default IOURequestStepHoursWithFullTransactionOrNotFound; +export default withFullTransactionOrNotFound(withWritableReportOrNotFound(IOURequestStepHours)); diff --git a/src/pages/iou/request/step/IOURequestStepPerDiemWorkspace.tsx b/src/pages/iou/request/step/IOURequestStepPerDiemWorkspace.tsx index 0f4657873648..d1f298404f95 100644 --- a/src/pages/iou/request/step/IOURequestStepPerDiemWorkspace.tsx +++ b/src/pages/iou/request/step/IOURequestStepPerDiemWorkspace.tsx @@ -1,138 +1,50 @@ -import React, {useCallback, useMemo} from 'react'; -import {View} from 'react-native'; -import SearchBar from '@components/SearchBar'; -import SelectionList from '@components/SelectionList'; -import type {ListItem} from '@components/SelectionList/ListItem/types'; -import UserListItem from '@components/SelectionList/ListItem/UserListItem'; -import Text from '@components/Text'; +import React from 'react'; import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; -import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; -import useLocalize from '@hooks/useLocalize'; -import useOnyx from '@hooks/useOnyx'; -import useSearchResults from '@hooks/useSearchResults'; -import useThemeStyles from '@hooks/useThemeStyles'; import Navigation from '@libs/Navigation/Navigation'; -import {getActivePoliciesWithExpenseChatAndPerDiemEnabled, getPerDiemCustomUnit, sortWorkspacesBySelected} from '@libs/PolicyUtils'; -import {getDefaultWorkspaceAvatar, getPolicyExpenseChat} from '@libs/ReportUtils'; -import tokenizedSearch from '@libs/tokenizedSearch'; +import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types'; +import type {MoneyRequestNavigatorParamList} from '@libs/Navigation/types'; +import {getActivePoliciesWithExpenseChatAndPerDiemEnabled, getPerDiemCustomUnit} from '@libs/PolicyUtils'; +import {getPolicyExpenseChat} from '@libs/ReportUtils'; import {setCustomUnitID, setMoneyRequestCategory, setMoneyRequestParticipants} from '@userActions/IOU'; import CONST from '@src/CONST'; -import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; -import withFullTransactionOrNotFound from './withFullTransactionOrNotFound'; -import type {WithFullTransactionOrNotFoundProps} from './withFullTransactionOrNotFound'; -import withWritableReportOrNotFound from './withWritableReportOrNotFound'; -import type {WithWritableReportOrNotFoundProps} from './withWritableReportOrNotFound'; +import BaseRequestStepWorkspace from './BaseRequestStepWorkspace'; -type WorkspaceListItem = ListItem & { - value: string; -}; +type IOURequestStepPerDiemWorkspaceProps = PlatformStackScreenProps; -type IOURequestStepPerDiemWorkspaceProps = WithWritableReportOrNotFoundProps & WithFullTransactionOrNotFoundProps; +function IOURequestStepPerDiemWorkspace({route, navigation}: IOURequestStepPerDiemWorkspaceProps) { + const { + params: {action, iouType, transactionID}, + } = route; + const {accountID} = useCurrentUserPersonalDetails(); -function IOURequestStepPerDiemWorkspace({ - route: { - params: {transactionID, action, iouType}, - }, - transaction, -}: IOURequestStepPerDiemWorkspaceProps) { - const icons = useMemoizedLazyExpensifyIcons(['FallbackWorkspaceAvatar']); - const styles = useThemeStyles(); - const {translate, localeCompare} = useLocalize(); - const {login: currentUserLogin, accountID} = useCurrentUserPersonalDetails(); - const [allPolicies] = useOnyx(ONYXKEYS.COLLECTION.POLICY, {canBeMissing: true}); - - const selectedWorkspace = useMemo(() => transaction?.participants?.[0], [transaction]); - - const workspaceOptions: WorkspaceListItem[] = useMemo(() => { - const availableWorkspaces = getActivePoliciesWithExpenseChatAndPerDiemEnabled(allPolicies, currentUserLogin); - - return availableWorkspaces - .sort((policy1, policy2) => - sortWorkspacesBySelected( - {policyID: policy1.id, name: policy1.name}, - {policyID: policy2.id, name: policy2.name}, - selectedWorkspace?.policyID ? [selectedWorkspace?.policyID] : [], - localeCompare, - ), - ) - .map((policy) => ({ - text: policy.name, - value: policy.id, - keyForList: policy.id, - icons: [ + return ( + { + const policyExpenseReportID = getPolicyExpenseChat(accountID, policy?.id)?.reportID; + if (!policyExpenseReportID) { + return; + } + const perDiemUnit = getPerDiemCustomUnit(policy); + setMoneyRequestParticipants(transactionID, [ { - id: policy.id, - source: policy?.avatarURL ? policy.avatarURL : getDefaultWorkspaceAvatar(policy.name), - fallbackIcon: icons.FallbackWorkspaceAvatar, - name: policy.name, - type: CONST.ICON_TYPE_WORKSPACE, + selected: true, + accountID: 0, + isPolicyExpenseChat: true, + reportID: policyExpenseReportID, + policyID: policy?.id, }, - ], - isSelected: selectedWorkspace?.policyID === policy.id, - })); - }, [allPolicies, currentUserLogin, selectedWorkspace?.policyID, localeCompare, icons.FallbackWorkspaceAvatar]); - - const filterWorkspace = useCallback((workspaceOption: WorkspaceListItem, searchInput: string) => { - const results = tokenizedSearch([workspaceOption], searchInput, (option) => [option.text ?? '']); - return results.length > 0; - }, []); - - const sortWorkspaces = useCallback( - (data: WorkspaceListItem[]) => { - return data.sort((a, b) => localeCompare(a.text ?? '', b?.text ?? '')); - }, - [localeCompare], - ); - - const [inputValue, setInputValue, filteredWorkspaceOptions] = useSearchResults(workspaceOptions, filterWorkspace, sortWorkspaces); - - const selectWorkspace = (item: WorkspaceListItem) => { - const policyExpenseReportID = getPolicyExpenseChat(accountID, item.value)?.reportID; - if (!policyExpenseReportID) { - return; - } - const selectedPolicy = allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${item.value}`]; - const perDiemUnit = getPerDiemCustomUnit(selectedPolicy); - setMoneyRequestParticipants(transactionID, [ - { - selected: true, - accountID: 0, - isPolicyExpenseChat: true, - reportID: policyExpenseReportID, - policyID: item.value, - }, - ]); - setCustomUnitID(transactionID, perDiemUnit?.customUnitID ?? CONST.CUSTOM_UNITS.FAKE_P2P_ID); - setMoneyRequestCategory(transactionID, perDiemUnit?.defaultCategory ?? '', undefined); - Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_DESTINATION.getRoute(action, iouType, transactionID, policyExpenseReportID)); - }; - - return ( - <> - {workspaceOptions.length > CONST.SEARCH_ITEM_LIMIT ? ( - 0 && filteredWorkspaceOptions.length === 0} - /> - ) : ( - - {translate('iou.chooseWorkspace')} - - )} - - + ]); + setCustomUnitID(transactionID, perDiemUnit?.customUnitID ?? CONST.CUSTOM_UNITS.FAKE_P2P_ID); + setMoneyRequestCategory(transactionID, perDiemUnit?.defaultCategory ?? '', undefined); + Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_DESTINATION.getRoute(action, iouType, transactionID, policyExpenseReportID)); + }} + /> ); } -export default withWritableReportOrNotFound(withFullTransactionOrNotFound(IOURequestStepPerDiemWorkspace)); +export default IOURequestStepPerDiemWorkspace; diff --git a/src/pages/iou/request/step/IOURequestStepTimeWorkspace.tsx b/src/pages/iou/request/step/IOURequestStepTimeWorkspace.tsx new file mode 100644 index 000000000000..4d726c798ab7 --- /dev/null +++ b/src/pages/iou/request/step/IOURequestStepTimeWorkspace.tsx @@ -0,0 +1,51 @@ +import React from 'react'; +import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; +import {setTransactionReport} from '@libs/actions/Transaction'; +import {shouldUseTransactionDraft} from '@libs/IOUUtils'; +import Navigation from '@libs/Navigation/Navigation'; +import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types'; +import type {MoneyRequestNavigatorParamList} from '@libs/Navigation/types'; +import {getActivePoliciesWithExpenseChatAndTimeEnabled, getDefaultTimeTrackingRate} from '@libs/PolicyUtils'; +import {getPolicyExpenseChat} from '@libs/ReportUtils'; +import {setMoneyRequestParticipantsFromReport, setMoneyRequestTimeRate} from '@userActions/IOU'; +import ROUTES from '@src/ROUTES'; +import type SCREENS from '@src/SCREENS'; +import BaseRequestStepWorkspace from './BaseRequestStepWorkspace'; + +type IOURequestStepTimeWorkspaceProps = PlatformStackScreenProps; + +function IOURequestStepTimeWorkspace({route, navigation}: IOURequestStepTimeWorkspaceProps) { + const { + params: {action, iouType, transactionID}, + } = route; + + const {accountID} = useCurrentUserPersonalDetails(); + const isTransactionDraft = shouldUseTransactionDraft(action); + + return ( + { + const policyExpenseChat = getPolicyExpenseChat(accountID, policy?.id); + if (!policyExpenseChat) { + console.error(`Couldn't find policy expense chat for policyID: ${policy?.id}`); + return; + } + + setTransactionReport(transactionID, {reportID: policyExpenseChat.reportID}, isTransactionDraft); + setMoneyRequestParticipantsFromReport(transactionID, policyExpenseChat, accountID); + + const defaultRate = policy ? getDefaultTimeTrackingRate(policy) : undefined; + if (defaultRate) { + setMoneyRequestTimeRate(transactionID, defaultRate, isTransactionDraft); + } + + Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_HOURS.getRoute(action, iouType, transactionID, policyExpenseChat.reportID)); + }} + /> + ); +} + +export default IOURequestStepTimeWorkspace; diff --git a/src/pages/iou/request/step/withFullTransactionOrNotFound.tsx b/src/pages/iou/request/step/withFullTransactionOrNotFound.tsx index 1344153a0ae2..4e5057b3307f 100644 --- a/src/pages/iou/request/step/withFullTransactionOrNotFound.tsx +++ b/src/pages/iou/request/step/withFullTransactionOrNotFound.tsx @@ -53,7 +53,8 @@ type MoneyRequestRouteName = | typeof SCREENS.MONEY_REQUEST.STEP_DISTANCE_MANUAL | typeof SCREENS.MONEY_REQUEST.STEP_DISTANCE_ODOMETER | typeof SCREENS.MONEY_REQUEST.STEP_TIME_RATE - | typeof SCREENS.MONEY_REQUEST.STEP_HOURS; + | typeof SCREENS.MONEY_REQUEST.STEP_HOURS + | typeof SCREENS.MONEY_REQUEST.STEP_HOURS_EDIT; type WithFullTransactionOrNotFoundProps = WithFullTransactionOrNotFoundOnyxProps & PlatformStackScreenProps; diff --git a/src/pages/iou/request/step/withWritableReportOrNotFound.tsx b/src/pages/iou/request/step/withWritableReportOrNotFound.tsx index 2c5c19a1ca84..7deb78ef5fcf 100644 --- a/src/pages/iou/request/step/withWritableReportOrNotFound.tsx +++ b/src/pages/iou/request/step/withWritableReportOrNotFound.tsx @@ -57,7 +57,8 @@ type MoneyRequestRouteName = | typeof SCREENS.MONEY_REQUEST.STEP_DISTANCE_ODOMETER | typeof SCREENS.MONEY_REQUEST.STEP_DISTANCE_MANUAL | typeof SCREENS.MONEY_REQUEST.STEP_TIME_RATE - | typeof SCREENS.MONEY_REQUEST.STEP_HOURS; + | typeof SCREENS.MONEY_REQUEST.STEP_HOURS + | typeof SCREENS.MONEY_REQUEST.STEP_HOURS_EDIT; type WithWritableReportOrNotFoundProps = WithWritableReportOrNotFoundOnyxProps & PlatformStackScreenProps;