From 322ed4e27971702816f77e1591e60e34d4cc1a48 Mon Sep 17 00:00:00 2001 From: daledah Date: Thu, 21 Aug 2025 23:58:34 +0700 Subject: [PATCH 1/8] fix: show not found page on change owner page for invalid account --- .../members/WorkspaceOwnerChangeErrorPage.tsx | 12 +++++-- .../WorkspaceOwnerChangeSuccessPage.tsx | 11 +++++- .../WorkspaceOwnerChangeWrapperPage.tsx | 3 ++ .../members/useShouldShowChangeOwnerPage.ts | 34 +++++++++++++++++++ 4 files changed, 57 insertions(+), 3 deletions(-) create mode 100644 src/pages/workspace/members/useShouldShowChangeOwnerPage.ts diff --git a/src/pages/workspace/members/WorkspaceOwnerChangeErrorPage.tsx b/src/pages/workspace/members/WorkspaceOwnerChangeErrorPage.tsx index 33d47086bd93..d5c0c1a15f46 100644 --- a/src/pages/workspace/members/WorkspaceOwnerChangeErrorPage.tsx +++ b/src/pages/workspace/members/WorkspaceOwnerChangeErrorPage.tsx @@ -1,5 +1,5 @@ import React, {useCallback} from 'react'; -import {View} from 'react-native'; +import {InteractionManager, View} from 'react-native'; import Button from '@components/Button'; import FixedFooter from '@components/FixedFooter'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; @@ -9,6 +9,7 @@ import RenderHTML from '@components/RenderHTML'; import ScreenWrapper from '@components/ScreenWrapper'; import Text from '@components/Text'; import useLocalize from '@hooks/useLocalize'; +import usePolicy from '@hooks/usePolicy'; import useThemeStyles from '@hooks/useThemeStyles'; import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types'; import Navigation from '@navigation/Navigation'; @@ -18,6 +19,7 @@ import {clearWorkspaceOwnerChangeFlow} from '@userActions/Policy/Member'; import CONST from '@src/CONST'; import ROUTES from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; +import useShouldShowChangeOwnerPage from './useShouldShowChangeOwnerPage'; type WorkspaceOwnerChangeSuccessPageProps = PlatformStackScreenProps; @@ -29,15 +31,21 @@ function WorkspaceOwnerChangeErrorPage({route}: WorkspaceOwnerChangeSuccessPageP const policyID = route.params.policyID; const closePage = useCallback(() => { - clearWorkspaceOwnerChangeFlow(policyID); Navigation.goBack(); Navigation.navigate(ROUTES.WORKSPACE_MEMBER_DETAILS.getRoute(policyID, accountID)); + InteractionManager.runAfterInteractions(() => { + clearWorkspaceOwnerChangeFlow(policyID); + }); }, [accountID, policyID]); + const policy = usePolicy(policyID); + const shouldShow = useShouldShowChangeOwnerPage(policy, accountID); + return ( ; @@ -24,15 +27,21 @@ function WorkspaceOwnerChangeSuccessPage({route}: WorkspaceOwnerChangeSuccessPag const policyID = route.params.policyID; const closePage = useCallback(() => { - clearWorkspaceOwnerChangeFlow(policyID); Navigation.goBack(); Navigation.navigate(ROUTES.WORKSPACE_MEMBER_DETAILS.getRoute(policyID, accountID)); + InteractionManager.runAfterInteractions(() => { + clearWorkspaceOwnerChangeFlow(policyID); + }); }, [accountID, policyID]); + const policy = usePolicy(policyID); + const shouldShow = useShouldShowChangeOwnerPage(policy, accountID); + return ( { if (!policy || policy?.isLoading) { return; @@ -63,6 +65,7 @@ function WorkspaceOwnerChangeWrapperPage({route, policy}: WorkspaceOwnerChangeWr , accountID: number) => { + const personalDetails = usePersonalDetails(); + const currentUserPersonalDetails = useCurrentUserPersonalDetails(); + const [shouldShow, setShouldShow] = useState(false); + + useEffect(() => { + const isCurrentUserOwner = policy?.owner === currentUserPersonalDetails?.login; + const isCurrentUserAdmin = policy?.employeeList?.[personalDetails?.[currentUserPersonalDetails?.accountID]?.login ?? '']?.role === CONST.POLICY.ROLE.ADMIN; + const isAccountOwner = policy?.owner === personalDetails?.[accountID]?.login; + const isSuccessOrFailed = (!policy?.errorFields && !!policy?.isChangeOwnerFailed) || (!policy?.errorFields?.changeOwner && !!policy?.isChangeOwnerSuccessful); + setShouldShow((!isCurrentUserOwner && isCurrentUserAdmin && isAccountOwner) || isSuccessOrFailed); + }, [ + accountID, + currentUserPersonalDetails?.accountID, + currentUserPersonalDetails?.login, + personalDetails, + policy?.employeeList, + policy?.errorFields, + policy?.isChangeOwnerFailed, + policy?.isChangeOwnerSuccessful, + policy?.owner, + ]); + + return shouldShow; +}; + +export default useShouldShowChangeOwnerPage; From 5e94cd268a97faa473be37288395fc2058ebbfde Mon Sep 17 00:00:00 2001 From: daledah Date: Thu, 11 Sep 2025 14:04:30 +0700 Subject: [PATCH 2/8] fix: update logics --- .../members/WorkspaceMemberDetailsPage.tsx | 10 +----- .../members/WorkspaceOwnerChangeErrorPage.tsx | 15 +++++--- .../WorkspaceOwnerChangeSuccessPage.tsx | 14 ++++++-- .../WorkspaceOwnerChangeWrapperPage.tsx | 9 ++--- .../members/useShouldShowChangeOwnerPage.ts | 34 ------------------- 5 files changed, 28 insertions(+), 54 deletions(-) delete mode 100644 src/pages/workspace/members/useShouldShowChangeOwnerPage.ts diff --git a/src/pages/workspace/members/WorkspaceMemberDetailsPage.tsx b/src/pages/workspace/members/WorkspaceMemberDetailsPage.tsx index ca4bfa8e6bb9..e98ce36e8b19 100644 --- a/src/pages/workspace/members/WorkspaceMemberDetailsPage.tsx +++ b/src/pages/workspace/members/WorkspaceMemberDetailsPage.tsx @@ -45,14 +45,7 @@ import type {ListItemType} from '@pages/workspace/WorkspaceMemberRoleSelectionMo import WorkspaceMemberDetailsRoleSelectionModal from '@pages/workspace/WorkspaceMemberRoleSelectionModal'; import variables from '@styles/variables'; import {setIssueNewCardStepAndData} from '@userActions/Card'; -import { - clearWorkspaceOwnerChangeFlow, - isApprover as isApproverUserAction, - openPolicyMemberProfilePage, - removeMembers, - requestWorkspaceOwnerChange, - updateWorkspaceMembersRole, -} from '@userActions/Policy/Member'; +import {clearWorkspaceOwnerChangeFlow, isApprover as isApproverUserAction, openPolicyMemberProfilePage, removeMembers, updateWorkspaceMembersRole} from '@userActions/Policy/Member'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; @@ -271,7 +264,6 @@ function WorkspaceMemberDetailsPage({personalDetails, policy, route}: WorkspaceM const startChangeOwnershipFlow = useCallback(() => { clearWorkspaceOwnerChangeFlow(policyID); - requestWorkspaceOwnerChange(policyID); Navigation.navigate(ROUTES.WORKSPACE_OWNER_CHANGE_CHECK.getRoute(policyID, accountID, 'amountOwed' as ValueOf)); }, [accountID, policyID]); diff --git a/src/pages/workspace/members/WorkspaceOwnerChangeErrorPage.tsx b/src/pages/workspace/members/WorkspaceOwnerChangeErrorPage.tsx index af78d984859d..2d1cbaaa1ade 100644 --- a/src/pages/workspace/members/WorkspaceOwnerChangeErrorPage.tsx +++ b/src/pages/workspace/members/WorkspaceOwnerChangeErrorPage.tsx @@ -1,13 +1,15 @@ import React, {useCallback} from 'react'; -import {View} from 'react-native'; +import {InteractionManager, View} from 'react-native'; import Button from '@components/Button'; import FixedFooter from '@components/FixedFooter'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import Icon from '@components/Icon'; import * as Expensicons from '@components/Icon/Expensicons'; +import {usePersonalDetails} from '@components/OnyxListItemProvider'; import RenderHTML from '@components/RenderHTML'; import ScreenWrapper from '@components/ScreenWrapper'; import Text from '@components/Text'; +import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; import useLocalize from '@hooks/useLocalize'; import usePolicy from '@hooks/usePolicy'; import useThemeStyles from '@hooks/useThemeStyles'; @@ -19,7 +21,6 @@ import {clearWorkspaceOwnerChangeFlow} from '@userActions/Policy/Member'; import CONST from '@src/CONST'; import ROUTES from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; -import useShouldShowChangeOwnerPage from './useShouldShowChangeOwnerPage'; type WorkspaceOwnerChangeSuccessPageProps = PlatformStackScreenProps; @@ -32,17 +33,23 @@ function WorkspaceOwnerChangeErrorPage({route}: WorkspaceOwnerChangeSuccessPageP const backTo = route.params.backTo; const closePage = useCallback(() => { - clearWorkspaceOwnerChangeFlow(policyID); if (backTo) { Navigation.goBack(backTo); } else { Navigation.goBack(); Navigation.navigate(ROUTES.WORKSPACE_MEMBER_DETAILS.getRoute(policyID, accountID)); } + InteractionManager.runAfterInteractions(() => { + clearWorkspaceOwnerChangeFlow(policyID); + }); }, [accountID, backTo, policyID]); const policy = usePolicy(policyID); - const shouldShow = useShouldShowChangeOwnerPage(policy, accountID); + const currentUserPersonalDetails = useCurrentUserPersonalDetails(); + const isCurrentUserOwner = policy?.owner === currentUserPersonalDetails?.login; + const personalDetails = usePersonalDetails(); + const isMember = policy?.employeeList?.[personalDetails?.[accountID]?.login ?? '']?.role === CONST.POLICY.ROLE.USER; + const shouldShow = (!isCurrentUserOwner && isMember) || (!policy?.errorFields && policy?.isChangeOwnerFailed); return ( ; @@ -27,17 +29,23 @@ function WorkspaceOwnerChangeSuccessPage({route}: WorkspaceOwnerChangeSuccessPag const backTo = route.params.backTo; const closePage = useCallback(() => { - clearWorkspaceOwnerChangeFlow(policyID); if (backTo) { Navigation.goBack(backTo); } else { Navigation.goBack(); Navigation.navigate(ROUTES.WORKSPACE_MEMBER_DETAILS.getRoute(policyID, accountID)); } + InteractionManager.runAfterInteractions(() => { + clearWorkspaceOwnerChangeFlow(policyID); + }); }, [accountID, backTo, policyID]); const policy = usePolicy(policyID); - const shouldShow = useShouldShowChangeOwnerPage(policy, accountID); + const currentUserPersonalDetails = useCurrentUserPersonalDetails(); + const isCurrentUserOwner = policy?.owner === currentUserPersonalDetails?.login; + const personalDetails = usePersonalDetails(); + const isMember = policy?.employeeList?.[personalDetails?.[accountID]?.login ?? '']?.role === CONST.POLICY.ROLE.USER; + const shouldShow = (!isCurrentUserOwner && isMember) || (!policy?.errorFields?.changeOwner && policy?.isChangeOwnerSuccessful); return ( { + requestWorkspaceOwnerChange(policyID); + }, [policyID]); + useEffect(() => { if (!policy || policy?.isLoading) { return; @@ -66,7 +68,6 @@ function WorkspaceOwnerChangeWrapperPage({route, policy}: WorkspaceOwnerChangeWr , accountID: number) => { - const personalDetails = usePersonalDetails(); - const currentUserPersonalDetails = useCurrentUserPersonalDetails(); - const [shouldShow, setShouldShow] = useState(false); - - useEffect(() => { - const isCurrentUserOwner = policy?.owner === currentUserPersonalDetails?.login; - const isCurrentUserAdmin = policy?.employeeList?.[personalDetails?.[currentUserPersonalDetails?.accountID]?.login ?? '']?.role === CONST.POLICY.ROLE.ADMIN; - const isAccountOwner = policy?.owner === personalDetails?.[accountID]?.login; - const isSuccessOrFailed = (!policy?.errorFields && !!policy?.isChangeOwnerFailed) || (!policy?.errorFields?.changeOwner && !!policy?.isChangeOwnerSuccessful); - setShouldShow((!isCurrentUserOwner && isCurrentUserAdmin && isAccountOwner) || isSuccessOrFailed); - }, [ - accountID, - currentUserPersonalDetails?.accountID, - currentUserPersonalDetails?.login, - personalDetails, - policy?.employeeList, - policy?.errorFields, - policy?.isChangeOwnerFailed, - policy?.isChangeOwnerSuccessful, - policy?.owner, - ]); - - return shouldShow; -}; - -export default useShouldShowChangeOwnerPage; From 23d2a4196cdebc9417bf4d0a6d4ff9890e97ab91 Mon Sep 17 00:00:00 2001 From: daledah Date: Wed, 17 Sep 2025 15:36:53 +0700 Subject: [PATCH 3/8] fix: simplify should show page logic --- .../workspace/members/WorkspaceOwnerChangeErrorPage.tsx | 8 +------- .../workspace/members/WorkspaceOwnerChangeSuccessPage.tsx | 8 +------- 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/src/pages/workspace/members/WorkspaceOwnerChangeErrorPage.tsx b/src/pages/workspace/members/WorkspaceOwnerChangeErrorPage.tsx index 2d1cbaaa1ade..ace984354241 100644 --- a/src/pages/workspace/members/WorkspaceOwnerChangeErrorPage.tsx +++ b/src/pages/workspace/members/WorkspaceOwnerChangeErrorPage.tsx @@ -5,11 +5,9 @@ import FixedFooter from '@components/FixedFooter'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import Icon from '@components/Icon'; import * as Expensicons from '@components/Icon/Expensicons'; -import {usePersonalDetails} from '@components/OnyxListItemProvider'; import RenderHTML from '@components/RenderHTML'; import ScreenWrapper from '@components/ScreenWrapper'; import Text from '@components/Text'; -import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; import useLocalize from '@hooks/useLocalize'; import usePolicy from '@hooks/usePolicy'; import useThemeStyles from '@hooks/useThemeStyles'; @@ -45,11 +43,7 @@ function WorkspaceOwnerChangeErrorPage({route}: WorkspaceOwnerChangeSuccessPageP }, [accountID, backTo, policyID]); const policy = usePolicy(policyID); - const currentUserPersonalDetails = useCurrentUserPersonalDetails(); - const isCurrentUserOwner = policy?.owner === currentUserPersonalDetails?.login; - const personalDetails = usePersonalDetails(); - const isMember = policy?.employeeList?.[personalDetails?.[accountID]?.login ?? '']?.role === CONST.POLICY.ROLE.USER; - const shouldShow = (!isCurrentUserOwner && isMember) || (!policy?.errorFields && policy?.isChangeOwnerFailed); + const shouldShow = !policy?.errorFields && policy?.isChangeOwnerFailed; return ( Date: Mon, 20 Oct 2025 10:18:09 +0700 Subject: [PATCH 4/8] fix: prevent multiple API calls --- .../workspace/members/WorkspaceOwnerChangeWrapperPage.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/pages/workspace/members/WorkspaceOwnerChangeWrapperPage.tsx b/src/pages/workspace/members/WorkspaceOwnerChangeWrapperPage.tsx index 9991997ab278..386e0ea97e4a 100644 --- a/src/pages/workspace/members/WorkspaceOwnerChangeWrapperPage.tsx +++ b/src/pages/workspace/members/WorkspaceOwnerChangeWrapperPage.tsx @@ -37,7 +37,11 @@ function WorkspaceOwnerChangeWrapperPage({route, policy}: WorkspaceOwnerChangeWr const shouldShowPaymentCardForm = error === CONST.POLICY.OWNERSHIP_ERRORS.NO_BILLING_CARD || isAuthRequired; useEffect(() => { - requestWorkspaceOwnerChange(policyID); + if (policy?.isChangeOwnerFailed || policy?.isChangeOwnerSuccessful) { + return; + } + // requestWorkspaceOwnerChange(policyID); + // eslint-disable-next-line react-comp react-hooks/exhaustive-deps }, [policyID]); useEffect(() => { From 71bf2cae69b0fd0edaef7020a0487f028375b8dd Mon Sep 17 00:00:00 2001 From: daledah Date: Mon, 20 Oct 2025 10:24:56 +0700 Subject: [PATCH 5/8] fix: lint --- .../workspace/members/WorkspaceOwnerChangeWrapperPage.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/workspace/members/WorkspaceOwnerChangeWrapperPage.tsx b/src/pages/workspace/members/WorkspaceOwnerChangeWrapperPage.tsx index 386e0ea97e4a..5a97683ae223 100644 --- a/src/pages/workspace/members/WorkspaceOwnerChangeWrapperPage.tsx +++ b/src/pages/workspace/members/WorkspaceOwnerChangeWrapperPage.tsx @@ -40,8 +40,8 @@ function WorkspaceOwnerChangeWrapperPage({route, policy}: WorkspaceOwnerChangeWr if (policy?.isChangeOwnerFailed || policy?.isChangeOwnerSuccessful) { return; } - // requestWorkspaceOwnerChange(policyID); - // eslint-disable-next-line react-comp react-hooks/exhaustive-deps + requestWorkspaceOwnerChange(policyID); + // eslint-disable-next-line react-compiler/react-compiler react-hooks/exhaustive-deps }, [policyID]); useEffect(() => { From de03d8f05696c25ed186dccdb263e8931a15cb37 Mon Sep 17 00:00:00 2001 From: daledah Date: Mon, 20 Oct 2025 10:36:03 +0700 Subject: [PATCH 6/8] fix: lint --- src/pages/workspace/members/WorkspaceOwnerChangeWrapperPage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/workspace/members/WorkspaceOwnerChangeWrapperPage.tsx b/src/pages/workspace/members/WorkspaceOwnerChangeWrapperPage.tsx index 5a97683ae223..518d76ede929 100644 --- a/src/pages/workspace/members/WorkspaceOwnerChangeWrapperPage.tsx +++ b/src/pages/workspace/members/WorkspaceOwnerChangeWrapperPage.tsx @@ -41,7 +41,7 @@ function WorkspaceOwnerChangeWrapperPage({route, policy}: WorkspaceOwnerChangeWr return; } requestWorkspaceOwnerChange(policyID); - // eslint-disable-next-line react-compiler/react-compiler react-hooks/exhaustive-deps + // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps }, [policyID]); useEffect(() => { From 6a80b179f09a01821dafbbc8571ab16a56b7f168 Mon Sep 17 00:00:00 2001 From: daledah Date: Thu, 4 Dec 2025 17:45:03 +0700 Subject: [PATCH 7/8] resolve conlifct --- src/pages/workspace/members/WorkspaceMemberDetailsPage.tsx | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/pages/workspace/members/WorkspaceMemberDetailsPage.tsx b/src/pages/workspace/members/WorkspaceMemberDetailsPage.tsx index e67df6786ac8..4f9b0bad09ec 100644 --- a/src/pages/workspace/members/WorkspaceMemberDetailsPage.tsx +++ b/src/pages/workspace/members/WorkspaceMemberDetailsPage.tsx @@ -336,10 +336,6 @@ function WorkspaceMemberDetailsPage({personalDetails, policy, route}: WorkspaceM const startChangeOwnershipFlow = useCallback(() => { clearWorkspaceOwnerChangeFlow(policyID); -<<<<<<< HEAD -======= - requestWorkspaceOwnerChange(policyID, currentUserPersonalDetails.accountID, currentUserPersonalDetails.login ?? ''); ->>>>>>> main Navigation.navigate(ROUTES.WORKSPACE_OWNER_CHANGE_CHECK.getRoute(policyID, accountID, 'amountOwed' as ValueOf)); }, [accountID, currentUserPersonalDetails.accountID, currentUserPersonalDetails.login, policyID]); From 145b2ccc7d55c6e6bde2b42afbc2f5b2b9dad0ac Mon Sep 17 00:00:00 2001 From: daledah Date: Thu, 4 Dec 2025 19:04:49 +0700 Subject: [PATCH 8/8] fix lint and fix comments --- .../workspace/members/WorkspaceMemberDetailsPage.tsx | 2 +- .../members/WorkspaceOwnerChangeErrorPage.tsx | 12 +++++------- .../members/WorkspaceOwnerChangeSuccessPage.tsx | 11 ++++------- .../members/WorkspaceOwnerChangeWrapperPage.tsx | 4 +++- 4 files changed, 13 insertions(+), 16 deletions(-) diff --git a/src/pages/workspace/members/WorkspaceMemberDetailsPage.tsx b/src/pages/workspace/members/WorkspaceMemberDetailsPage.tsx index 4f9b0bad09ec..2bd37003b4d7 100644 --- a/src/pages/workspace/members/WorkspaceMemberDetailsPage.tsx +++ b/src/pages/workspace/members/WorkspaceMemberDetailsPage.tsx @@ -337,7 +337,7 @@ function WorkspaceMemberDetailsPage({personalDetails, policy, route}: WorkspaceM const startChangeOwnershipFlow = useCallback(() => { clearWorkspaceOwnerChangeFlow(policyID); Navigation.navigate(ROUTES.WORKSPACE_OWNER_CHANGE_CHECK.getRoute(policyID, accountID, 'amountOwed' as ValueOf)); - }, [accountID, currentUserPersonalDetails.accountID, currentUserPersonalDetails.login, policyID]); + }, [accountID, policyID]); // eslint-disable-next-line rulesdir/no-negated-variables const shouldShowNotFoundPage = diff --git a/src/pages/workspace/members/WorkspaceOwnerChangeErrorPage.tsx b/src/pages/workspace/members/WorkspaceOwnerChangeErrorPage.tsx index ace984354241..b6573619e74a 100644 --- a/src/pages/workspace/members/WorkspaceOwnerChangeErrorPage.tsx +++ b/src/pages/workspace/members/WorkspaceOwnerChangeErrorPage.tsx @@ -1,5 +1,5 @@ -import React, {useCallback} from 'react'; -import {InteractionManager, View} from 'react-native'; +import React, {useCallback, useRef} from 'react'; +import {View} from 'react-native'; import Button from '@components/Button'; import FixedFooter from '@components/FixedFooter'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; @@ -37,19 +37,17 @@ function WorkspaceOwnerChangeErrorPage({route}: WorkspaceOwnerChangeSuccessPageP Navigation.goBack(); Navigation.navigate(ROUTES.WORKSPACE_MEMBER_DETAILS.getRoute(policyID, accountID)); } - InteractionManager.runAfterInteractions(() => { - clearWorkspaceOwnerChangeFlow(policyID); - }); + clearWorkspaceOwnerChangeFlow(policyID); }, [accountID, backTo, policyID]); const policy = usePolicy(policyID); - const shouldShow = !policy?.errorFields && policy?.isChangeOwnerFailed; + const shouldShowRef = useRef(!policy?.errorFields && policy?.isChangeOwnerFailed); return ( { - clearWorkspaceOwnerChangeFlow(policyID); - }); + clearWorkspaceOwnerChangeFlow(policyID); }, [accountID, backTo, policyID]); const policy = usePolicy(policyID); - const shouldShow = !policy?.errorFields?.changeOwner && policy?.isChangeOwnerSuccessful; + const shouldShowRef = useRef(!policy?.errorFields?.changeOwner && policy?.isChangeOwnerSuccessful); return (