11import { emailSelector } from '@selectors/Session' ;
22import React , { useCallback , useMemo , useRef , useState } from 'react' ;
33import { View } from 'react-native' ;
4- import type { OnyxCollection } from 'react-native-onyx' ;
4+ import type { OnyxCollection , OnyxEntry } from 'react-native-onyx' ;
55import Button from '@components/Button' ;
6+ import { ModalActions } from '@components/Modal/Global/ModalContext' ;
67import type { PopoverMenuItem } from '@components/PopoverMenu' ;
78import PopoverMenu from '@components/PopoverMenu' ;
9+ import useConfirmModal from '@hooks/useConfirmModal' ;
10+ import useCreateEmptyReportConfirmation from '@hooks/useCreateEmptyReportConfirmation' ;
11+ import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails' ;
12+ import useHasEmptyReportsForPolicy from '@hooks/useHasEmptyReportsForPolicy' ;
813import { useMemoizedLazyExpensifyIcons } from '@hooks/useLazyAsset' ;
914import useLocalize from '@hooks/useLocalize' ;
1015import useOnyx from '@hooks/useOnyx' ;
16+ import usePermissions from '@hooks/usePermissions' ;
17+ import usePolicyForMovingExpenses from '@hooks/usePolicyForMovingExpenses' ;
1118import usePopoverPosition from '@hooks/usePopoverPosition' ;
1219import useThemeStyles from '@hooks/useThemeStyles' ;
1320import { startDistanceRequest , startMoneyRequest } from '@libs/actions/IOU' ;
21+ import { openOldDotLink } from '@libs/actions/Link' ;
22+ import { createNewReport } from '@libs/actions/Report' ;
1423import getIconForAction from '@libs/getIconForAction' ;
1524import interceptAnonymousUser from '@libs/interceptAnonymousUser' ;
25+ import isSearchTopmostFullScreenRoute from '@libs/Navigation/helpers/isSearchTopmostFullScreenRoute' ;
1626import Navigation from '@libs/Navigation/Navigation' ;
17- import { generateReportID } from '@libs/ReportUtils' ;
27+ import { areAllGroupPoliciesExpenseChatDisabled , getDefaultChatEnabledPolicy } from '@libs/PolicyUtils' ;
28+ import { generateReportID , hasViolations as hasViolationsReportUtils } from '@libs/ReportUtils' ;
29+ import { shouldRestrictUserBillableActions } from '@libs/SubscriptionUtils' ;
1830import CONST from '@src/CONST' ;
1931import ONYXKEYS from '@src/ONYXKEYS' ;
2032import ROUTES from '@src/ROUTES' ;
21- import { groupPaidPoliciesWithExpenseChatEnabledSelector , shouldRedirectToExpensifyClassicSelector } from '@src/selectors/Policy' ;
33+ import { groupPaidPoliciesWithExpenseChatEnabledSelector } from '@src/selectors/Policy' ;
2234import type * as OnyxTypes from '@src/types/onyx' ;
2335
2436function SearchFiltersBarCreateButton ( ) {
@@ -31,11 +43,80 @@ function SearchFiltersBarCreateButton() {
3143 const [ createMenuPosition , setCreateMenuPosition ] = useState < { horizontal : number ; vertical : number } > ( { horizontal : 0 , vertical : 0 } ) ;
3244 const { calculatePopoverPosition} = usePopoverPosition ( ) ;
3345
46+ const [ session ] = useOnyx ( ONYXKEYS . SESSION ) ;
3447 const [ email ] = useOnyx ( ONYXKEYS . SESSION , { selector : emailSelector } ) ;
48+ const [ allBetas ] = useOnyx ( ONYXKEYS . BETAS ) ;
49+ const [ allPolicies ] = useOnyx ( ONYXKEYS . COLLECTION . POLICY ) ;
50+ const [ transactionViolations ] = useOnyx ( ONYXKEYS . COLLECTION . TRANSACTION_VIOLATIONS ) ;
3551 const groupPaidPoliciesWithChatEnabledSelector = useCallback ( ( policies : OnyxCollection < OnyxTypes . Policy > ) => groupPaidPoliciesWithExpenseChatEnabledSelector ( policies , email ) , [ email ] ) ;
3652 const [ groupPoliciesWithChatEnabled = CONST . EMPTY_ARRAY ] = useOnyx ( ONYXKEYS . COLLECTION . POLICY , { selector : groupPaidPoliciesWithChatEnabledSelector } , [ email ] ) ;
37- const [ shouldRedirectToExpensifyClassic = false ] = useOnyx ( ONYXKEYS . COLLECTION . POLICY , { selector : shouldRedirectToExpensifyClassicSelector } ) ;
38- const shouldShowCreateReportOption = shouldRedirectToExpensifyClassic || groupPoliciesWithChatEnabled . length > 0 ;
53+ const currentUserPersonalDetails = useCurrentUserPersonalDetails ( ) ;
54+ const { isBetaEnabled} = usePermissions ( ) ;
55+ const isASAPSubmitBetaEnabled = isBetaEnabled ( CONST . BETAS . ASAP_SUBMIT ) ;
56+ const hasViolations = hasViolationsReportUtils ( undefined , transactionViolations , session ?. accountID ?? CONST . DEFAULT_NUMBER_ID , session ?. email ?? '' ) ;
57+ const [ activePolicyID ] = useOnyx ( ONYXKEYS . NVP_ACTIVE_POLICY_ID ) ;
58+ const [ activePolicy ] = useOnyx ( `${ ONYXKEYS . COLLECTION . POLICY } ${ activePolicyID } ` ) ;
59+ const { policyForMovingExpensesID, shouldSelectPolicy} = usePolicyForMovingExpenses ( ) ;
60+ const shouldNavigateToUpgradePath = ! policyForMovingExpensesID && ! shouldSelectPolicy ;
61+ const { showConfirmModal} = useConfirmModal ( ) ;
62+
63+ const shouldRedirectToExpensifyClassic = useMemo ( ( ) => {
64+ return areAllGroupPoliciesExpenseChatDisabled ( ( allPolicies as OnyxCollection < OnyxTypes . Policy > ) ?? { } ) ;
65+ } , [ allPolicies ] ) ;
66+
67+ const defaultChatEnabledPolicy = useMemo (
68+ ( ) => getDefaultChatEnabledPolicy ( groupPoliciesWithChatEnabled as Array < OnyxEntry < OnyxTypes . Policy > > , activePolicy ) ,
69+ [ activePolicy , groupPoliciesWithChatEnabled ] ,
70+ ) ;
71+ const defaultChatEnabledPolicyID = defaultChatEnabledPolicy ?. id ;
72+
73+ const hasEmptyReport = useHasEmptyReportsForPolicy ( defaultChatEnabledPolicyID ) ;
74+ const [ hasDismissedEmptyReportsConfirmation ] = useOnyx ( ONYXKEYS . NVP_EMPTY_REPORTS_CONFIRMATION_DISMISSED ) ;
75+ const shouldShowEmptyReportConfirmationForDefaultChatEnabledPolicy = hasEmptyReport && hasDismissedEmptyReportsConfirmation !== true ;
76+
77+ const showRedirectToExpensifyClassicModal = useCallback ( async ( ) => {
78+ const { action} = await showConfirmModal ( {
79+ title : translate ( 'sidebarScreen.redirectToExpensifyClassicModal.title' ) ,
80+ prompt : translate ( 'sidebarScreen.redirectToExpensifyClassicModal.description' ) ,
81+ confirmText : translate ( 'exitSurvey.goToExpensifyClassic' ) ,
82+ cancelText : translate ( 'common.cancel' ) ,
83+ } ) ;
84+ if ( action === ModalActions . CONFIRM ) {
85+ openOldDotLink ( CONST . OLDDOT_URLS . INBOX ) ;
86+ }
87+ } , [ showConfirmModal , translate ] ) ;
88+
89+ const handleCreateWorkspaceReport = useCallback (
90+ ( shouldDismissEmptyReportsConfirmation ?: boolean ) => {
91+ if ( ! defaultChatEnabledPolicy ?. id ) {
92+ return ;
93+ }
94+
95+ const { reportID : createdReportID } = createNewReport (
96+ currentUserPersonalDetails ,
97+ hasViolations ,
98+ isASAPSubmitBetaEnabled ,
99+ defaultChatEnabledPolicy ,
100+ allBetas ,
101+ false ,
102+ shouldDismissEmptyReportsConfirmation ,
103+ ) ;
104+ Navigation . setNavigationActionToMicrotaskQueue ( ( ) => {
105+ Navigation . navigate (
106+ isSearchTopmostFullScreenRoute ( )
107+ ? ROUTES . SEARCH_MONEY_REQUEST_REPORT . getRoute ( { reportID : createdReportID , backTo : Navigation . getActiveRoute ( ) } )
108+ : ROUTES . REPORT_WITH_ID . getRoute ( createdReportID , undefined , undefined , Navigation . getActiveRoute ( ) ) ,
109+ ) ;
110+ } ) ;
111+ } ,
112+ [ currentUserPersonalDetails , hasViolations , defaultChatEnabledPolicy , isASAPSubmitBetaEnabled , allBetas ] ,
113+ ) ;
114+
115+ const { openCreateReportConfirmation, CreateReportConfirmationModal} = useCreateEmptyReportConfirmation ( {
116+ policyID : defaultChatEnabledPolicyID ,
117+ policyName : defaultChatEnabledPolicy ?. name ?? '' ,
118+ onConfirm : handleCreateWorkspaceReport ,
119+ } ) ;
39120
40121 const hideCreateMenu = useCallback ( ( ) => setIsCreateMenuActive ( false ) , [ ] ) ;
41122 const showCreateMenu = useCallback ( ( ) => {
@@ -69,24 +150,72 @@ function SearchFiltersBarCreateButton() {
69150 startDistanceRequest ( CONST . IOU . TYPE . CREATE , generateReportID ( ) ) ;
70151 } ) ,
71152 } ,
72- ...( shouldShowCreateReportOption
73- ? [
74- {
75- icon : expensifyIcons . Document ,
76- text : translate ( 'report.newReport.createReport' ) ,
77- onSelected : ( ) =>
78- interceptAnonymousUser ( ( ) => {
79- Navigation . navigate ( ROUTES . NEW_REPORT_WORKSPACE_SELECTION . getRoute ( ) ) ;
80- } ) ,
81- } ,
82- ]
83- : [ ] ) ,
153+ {
154+ icon : expensifyIcons . Document ,
155+ text : translate ( 'report.newReport.createReport' ) ,
156+ onSelected : ( ) =>
157+ interceptAnonymousUser ( ( ) => {
158+ if ( shouldRedirectToExpensifyClassic ) {
159+ showRedirectToExpensifyClassicModal ( ) ;
160+ return ;
161+ }
162+
163+ // No valid policy at all → upgrade + create workspace flow
164+ if ( shouldNavigateToUpgradePath ) {
165+ const freshReportID = generateReportID ( ) ;
166+ const freshTransactionID = generateReportID ( ) ;
167+ Navigation . navigate (
168+ ROUTES . MONEY_REQUEST_UPGRADE . getRoute ( {
169+ action : CONST . IOU . ACTION . CREATE ,
170+ iouType : CONST . IOU . TYPE . CREATE ,
171+ transactionID : freshTransactionID ,
172+ reportID : freshReportID ,
173+ upgradePath : CONST . UPGRADE_PATHS . REPORTS ,
174+ } ) ,
175+ ) ;
176+ return ;
177+ }
178+
179+ const workspaceIDForReportCreation = defaultChatEnabledPolicyID ;
180+
181+ // No default or restricted with multiple workspaces → workspace selector
182+ if ( ! workspaceIDForReportCreation || ( shouldRestrictUserBillableActions ( workspaceIDForReportCreation ) && groupPoliciesWithChatEnabled . length > 1 ) ) {
183+ Navigation . navigate ( ROUTES . NEW_REPORT_WORKSPACE_SELECTION . getRoute ( ) ) ;
184+ return ;
185+ }
186+
187+ // Default workspace is not restricted → create report directly
188+ if ( ! shouldRestrictUserBillableActions ( workspaceIDForReportCreation ) ) {
189+ // Check if empty report confirmation should be shown
190+ if ( shouldShowEmptyReportConfirmationForDefaultChatEnabledPolicy ) {
191+ openCreateReportConfirmation ( ) ;
192+ } else {
193+ handleCreateWorkspaceReport ( false ) ;
194+ }
195+ return ;
196+ }
197+
198+ Navigation . navigate ( ROUTES . RESTRICTED_ACTION . getRoute ( workspaceIDForReportCreation ) ) ;
199+ } ) ,
200+ } ,
201+ ] ,
202+ [
203+ translate ,
204+ expensifyIcons ,
205+ shouldRedirectToExpensifyClassic ,
206+ showRedirectToExpensifyClassicModal ,
207+ shouldNavigateToUpgradePath ,
208+ groupPoliciesWithChatEnabled . length ,
209+ defaultChatEnabledPolicyID ,
210+ shouldShowEmptyReportConfirmationForDefaultChatEnabledPolicy ,
211+ openCreateReportConfirmation ,
212+ handleCreateWorkspaceReport ,
84213 ] ,
85- [ translate , expensifyIcons , shouldShowCreateReportOption ] ,
86214 ) ;
87215
88216 return (
89217 < View style = { [ styles . pr5 , styles . searchFiltersBarCreateButton ] } >
218+ { CreateReportConfirmationModal }
90219 < PopoverMenu
91220 onClose = { hideCreateMenu }
92221 isVisible = { isCreateMenuActive }
0 commit comments