Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions src/components/SettlementButton/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,7 @@ function SettlementButton({
currentUserEmailParam: currentUserPersonalDetails.email ?? '',
betas,
isSelfTourViewed,
hasActiveAdminPolicies: !!activeAdminPolicies.length,
}).policyID;
};

Expand Down
15 changes: 15 additions & 0 deletions src/hooks/useHasActiveAdminPolicies.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import type {OnyxCollection} from 'react-native-onyx';
import ONYXKEYS from '@src/ONYXKEYS';
import {hasActiveAdminPoliciesSelector} from '@src/selectors/Policy';
import type {Policy} from '@src/types/onyx';
import useCurrentUserPersonalDetails from './useCurrentUserPersonalDetails';
import useOnyx from './useOnyx';

function useHasActiveAdminPolicies() {
const login = useCurrentUserPersonalDetails().login ?? '';
const selector = (policies: OnyxCollection<Policy>) => hasActiveAdminPoliciesSelector(policies, login);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❌ CONSISTENCY-3 (docs)

The sibling hook useActiveAdminPolicies (in src/hooks/useActiveAdminPolicies.ts) wraps its selector in useCallback and passes [login] as the third argument to useOnyx so that the selector reference is stable and useOnyx knows when to re-evaluate. This new hook creates a fresh closure on every render and omits the dependencies argument, which is inconsistent with the established pattern.

Follow the same pattern as useActiveAdminPolicies:

import {useCallback} from 'react';

function useHasActiveAdminPolicies() {
    const login = useCurrentUserPersonalDetails().login ?? '';
    const selector = useCallback(
        (policies: OnyxCollection<Policy>) => hasActiveAdminPoliciesSelector(policies, login),
        [login],
    );
    const [hasActiveAdminPolicies] = useOnyx(ONYXKEYS.COLLECTION.POLICY, {selector}, [login]);
    return !!hasActiveAdminPolicies;
}

Please rate this suggestion with 👍 or 👎 to help us improve! Reactions are used to monitor reviewer efficiency.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's auto memoized by the compiler

const [hasActiveAdminPolicies] = useOnyx(ONYXKEYS.COLLECTION.POLICY, {selector});
return !!hasActiveAdminPolicies;
}

export default useHasActiveAdminPolicies;
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {hasSeenTourSelector} from '@selectors/Onboarding';
import {useEffect, useRef} from 'react';
import {useInitialURLActions, useInitialURLState} from '@components/InitialURLContextProvider';
import useHasActiveAdminPolicies from '@hooks/useHasActiveAdminPolicies';
import useOnyx from '@hooks/useOnyx';
import {init, isClientTheLeader} from '@libs/ActiveClientManager';
import Log from '@libs/Log';
Expand Down Expand Up @@ -48,6 +49,7 @@ function AuthScreensInitHandler() {
const delegatorEmail = getSearchParamFromUrl(currentUrl, 'delegatorEmail');
const {initialURL, isAuthenticatedAtStartup} = useInitialURLState();
const {setIsAuthenticatedAtStartup} = useInitialURLActions();
const hasActiveAdminPolicies = useHasActiveAdminPolicies();

const [session] = useOnyx(ONYXKEYS.SESSION);
const [introSelected] = useOnyx(ONYXKEYS.NVP_INTRO_SELECTED);
Expand Down Expand Up @@ -133,7 +135,7 @@ function AuthScreensInitHandler() {
App.reconnectApp(initialLastUpdateIDAppliedToClient);
}

App.setUpPoliciesAndNavigate(session, introSelected, activePolicyID, isSelfTourViewed);
App.setUpPoliciesAndNavigate(session, introSelected, activePolicyID, isSelfTourViewed, hasActiveAdminPolicies);

Download.clearDownloads();

Expand Down
10 changes: 10 additions & 0 deletions src/libs/actions/App.ts
Original file line number Diff line number Diff line change
Expand Up @@ -569,6 +569,7 @@ type CreateWorkspaceWithPolicyDraftParams = {
type?: PolicyType;
// TODO: Remove optional (?) once allBetas Onyx.connect is removed (https://github.com/Expensify/App/issues/66417)
betas?: OnyxEntry<OnyxTypes.Beta[]>;
hasActiveAdminPolicies: boolean;
};

/**
Expand All @@ -594,6 +595,7 @@ function createWorkspaceWithPolicyDraftAndNavigateToIt(params: CreateWorkspaceWi
type,
isSelfTourViewed,
betas,
hasActiveAdminPolicies,
} = params;

const policyIDWithDefault = policyID || generatePolicyID();
Expand Down Expand Up @@ -621,6 +623,7 @@ function createWorkspaceWithPolicyDraftAndNavigateToIt(params: CreateWorkspaceWi
type,
isSelfTourViewed,
betas,
hasActiveAdminPolicies,
});
Navigation.navigate(routeToNavigate, {forceReplace: !transitionFromOldDot});
});
Expand All @@ -642,6 +645,7 @@ function createWorkspaceWithPolicyDraft(params: CreateWorkspaceWithPolicyDraftPa
shouldCreateControlPolicy,
isSelfTourViewed,
betas,
hasActiveAdminPolicies,
} = params;

createDraftInitialWorkspace(introSelected, policyOwnerEmail, policyName, policyID, makeMeAdmin, currency, file);
Expand All @@ -661,6 +665,7 @@ function createWorkspaceWithPolicyDraft(params: CreateWorkspaceWithPolicyDraftPa
shouldCreateControlPolicy,
isSelfTourViewed,
betas,
hasActiveAdminPolicies,
});
}

Expand All @@ -682,6 +687,7 @@ type SavePolicyDraftByNewWorkspaceParams = {
type?: PolicyType;
// TODO: Remove optional (?) once allBetas Onyx.connect is removed (https://github.com/Expensify/App/issues/66417)
betas?: OnyxEntry<OnyxTypes.Beta[]>;
hasActiveAdminPolicies: boolean;
};

/**
Expand All @@ -704,6 +710,7 @@ function savePolicyDraftByNewWorkspace({
type,
isSelfTourViewed,
betas,
hasActiveAdminPolicies,
}: SavePolicyDraftByNewWorkspaceParams) {
createWorkspace({
policyOwnerEmail,
Expand All @@ -723,6 +730,7 @@ function savePolicyDraftByNewWorkspace({
type,
isSelfTourViewed,
betas,
hasActiveAdminPolicies,
});
}

Expand All @@ -746,6 +754,7 @@ function setUpPoliciesAndNavigate(
introSelected: OnyxEntry<OnyxTypes.IntroSelected>,
activePolicyID: string | undefined,
isSelfTourViewed: boolean | undefined,
hasActiveAdminPolicies: boolean,
) {
const currentUrl = getCurrentUrl();
if (!session || !currentUrl?.includes('exitTo')) {
Expand Down Expand Up @@ -777,6 +786,7 @@ function setUpPoliciesAndNavigate(
currentUserAccountIDParam: currentSessionData.accountID ?? CONST.DEFAULT_NUMBER_ID,
currentUserEmailParam: currentSessionData.email ?? '',
isSelfTourViewed,
hasActiveAdminPolicies,
});
return;
}
Expand Down
4 changes: 2 additions & 2 deletions src/libs/actions/Policy/Policy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@
// TODO: Remove this type once we complete refactoring the buildPolicyData function to use isSelfTourViewed. Refactor issue: https://github.com/Expensify/App/issues/66424
type CreateWorkspaceDataOptions = Omit<BuildPolicyDataOptions, 'isSelfTourViewed'> & {
isSelfTourViewed: boolean | undefined;
hasActiveAdminPolicies: boolean;
};

type DuplicatePolicyDataOptions = {
Expand Down Expand Up @@ -238,7 +239,7 @@
};

const deprecatedAllPolicies: OnyxCollection<Policy> = {};
Onyx.connect({

Check warning on line 242 in src/libs/actions/Policy/Policy.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
key: ONYXKEYS.COLLECTION.POLICY,
callback: (val, key) => {
if (!key) {
Expand All @@ -254,7 +255,7 @@
});

let deprecatedAllReportActions: OnyxCollection<ReportActions>;
Onyx.connect({

Check warning on line 258 in src/libs/actions/Policy/Policy.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
key: ONYXKEYS.COLLECTION.REPORT_ACTIONS,
waitForCollectionCallback: true,
callback: (actions) => {
Expand All @@ -264,7 +265,7 @@

let deprecatedSessionEmail = '';
let deprecatedSessionAccountID = 0;
Onyx.connect({

Check warning on line 268 in src/libs/actions/Policy/Policy.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
key: ONYXKEYS.SESSION,
callback: (val) => {
deprecatedSessionEmail = val?.email ?? '';
Expand All @@ -273,7 +274,7 @@
});

let deprecatedAllPersonalDetails: OnyxEntry<PersonalDetailsList>;
Onyx.connect({

Check warning on line 277 in src/libs/actions/Policy/Policy.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
key: ONYXKEYS.PERSONAL_DETAILS_LIST,
callback: (val) => (deprecatedAllPersonalDetails = val),
});
Expand Down Expand Up @@ -2904,7 +2905,7 @@
API.write(WRITE_COMMANDS.CREATE_WORKSPACE, params, {optimisticData, successData, failureData});

// Publish a workspace created event if this is their first policy
if (getAdminPolicies().length === 0) {
if (!options.hasActiveAdminPolicies) {
GoogleTagManager.publishEvent(CONST.ANALYTICS.EVENT.WORKSPACE_CREATED, options.currentUserAccountIDParam ?? CONST.DEFAULT_NUMBER_ID);
}

Expand Down Expand Up @@ -7155,7 +7156,6 @@
updateMemberCustomField,
openPolicyEditCardLimitTypePage,
requestExpensifyCardLimitIncrease,
getAdminPolicies,
hasInvoicingDetails,
clearAllPolicies,
enablePolicyRules,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import isSidePanelReportSupported from '@components/SidePanel/isSidePanelReportS
import Text from '@components/Text';
import useArchivedReportsIdSet from '@hooks/useArchivedReportsIdSet';
import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails';
import useHasActiveAdminPolicies from '@hooks/useHasActiveAdminPolicies';
import {useMemoizedLazyIllustrations} from '@hooks/useLazyAsset';
import useLocalize from '@hooks/useLocalize';
import useNetwork from '@hooks/useNetwork';
Expand Down Expand Up @@ -60,6 +61,7 @@ function BaseOnboardingInterestedFeatures({shouldUseNativeStyles}: BaseOnboardin
const [session] = useOnyx(ONYXKEYS.SESSION);
const [conciergeReportID = ''] = useOnyx(ONYXKEYS.CONCIERGE_REPORT_ID);
const archivedReportsIdSet = useArchivedReportsIdSet();
const hasActiveAdminPolicies = useHasActiveAdminPolicies();

const paidGroupPolicy = Object.values(allPolicies ?? {}).find((policy) => isPaidGroupPolicy(policy) && isPolicyAdmin(policy, session?.email));
const {isOffline} = useNetwork();
Expand Down Expand Up @@ -205,6 +207,7 @@ function BaseOnboardingInterestedFeatures({shouldUseNativeStyles}: BaseOnboardin
shouldAddGuideWelcomeMessage: false,
betas,
isSelfTourViewed,
hasActiveAdminPolicies,
})
: {adminsChatReportID: onboardingAdminsChatReportID, policyID: onboardingPolicyID};

Expand Down Expand Up @@ -277,6 +280,7 @@ function BaseOnboardingInterestedFeatures({shouldUseNativeStyles}: BaseOnboardin
isSelfTourViewed,
conciergeReportID,
betas,
hasActiveAdminPolicies,
]);

// Create items for enabled features
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import Text from '@components/Text';
import TextInput from '@components/TextInput';
import useAutoFocusInput from '@hooks/useAutoFocusInput';
import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails';
import useHasActiveAdminPolicies from '@hooks/useHasActiveAdminPolicies';
import useLocalize from '@hooks/useLocalize';
import useOnyx from '@hooks/useOnyx';
import useResponsiveLayout from '@hooks/useResponsiveLayout';
Expand Down Expand Up @@ -49,6 +50,7 @@ function BaseOnboardingWorkspaceConfirmation({shouldUseNativeStyles}: BaseOnboar
const [draftValues, draftValuesMetadata] = useOnyx(ONYXKEYS.FORMS.ONBOARDING_WORKSPACE_DETAILS_FORM_DRAFT);
const [session, sessionMetadata] = useOnyx(ONYXKEYS.SESSION);
const currentUserPersonalDetails = useCurrentUserPersonalDetails();
const hasActiveAdminPolicies = useHasActiveAdminPolicies();

const paidGroupPolicy = Object.values(allPolicies ?? {}).find((policy) => isPaidGroupPolicy(policy) && isPolicyAdmin(policy, session?.email));

Expand Down Expand Up @@ -87,6 +89,7 @@ function BaseOnboardingWorkspaceConfirmation({shouldUseNativeStyles}: BaseOnboar
onboardingPurposeSelected,
betas,
isSelfTourViewed,
hasActiveAdminPolicies,
})
: {adminsChatReportID: onboardingAdminsChatReportID, policyID: onboardingPolicyID};

Expand All @@ -108,6 +111,7 @@ function BaseOnboardingWorkspaceConfirmation({shouldUseNativeStyles}: BaseOnboar
introSelected,
betas,
isSelfTourViewed,
hasActiveAdminPolicies,
],
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import ScreenWrapper from '@components/ScreenWrapper';
import Text from '@components/Text';
import useArchivedReportsIdSet from '@hooks/useArchivedReportsIdSet';
import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails';
import useHasActiveAdminPolicies from '@hooks/useHasActiveAdminPolicies';
import useHasTeam2025Pricing from '@hooks/useHasTeam2025Pricing';
import {useMemoizedLazyIllustrations} from '@hooks/useLazyAsset';
import useLocalize from '@hooks/useLocalize';
Expand Down Expand Up @@ -64,6 +65,7 @@ function BaseOnboardingWorkspaceOptional({shouldUseNativeStyles}: BaseOnboarding
// eslint-disable-next-line rulesdir/prefer-shouldUseNarrowLayout-instead-of-isSmallScreenWidth
const {onboardingIsMediumOrLargerScreenWidth, isSmallScreenWidth} = useResponsiveLayout();
const currentUserPersonalDetails = useCurrentUserPersonalDetails();
const hasActiveAdminPolicies = useHasActiveAdminPolicies();
const {isBetaEnabled} = usePermissions();
const ICON_SIZE = 48;
const illustrations = useMemoizedLazyIllustrations(['MoneyReceipts', 'Tag', 'ReportReceipt']);
Expand Down Expand Up @@ -171,6 +173,7 @@ function BaseOnboardingWorkspaceOptional({shouldUseNativeStyles}: BaseOnboarding
onboardingPurposeSelected,
betas,
isSelfTourViewed,
hasActiveAdminPolicies,
})
: {adminsChatReportID: onboardingAdminsChatReportID, policyID: onboardingPolicyID};

Expand All @@ -192,6 +195,7 @@ function BaseOnboardingWorkspaceOptional({shouldUseNativeStyles}: BaseOnboarding
activePolicyID,
betas,
isSelfTourViewed,
hasActiveAdminPolicies,
completeOnboarding,
]);

Expand Down
3 changes: 3 additions & 0 deletions src/pages/Travel/WorkspaceConfirmationForTravelPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import ScreenWrapper from '@components/ScreenWrapper';
import WorkspaceConfirmationForm from '@components/WorkspaceConfirmationForm';
import type {WorkspaceConfirmationSubmitFunctionParams} from '@components/WorkspaceConfirmationForm';
import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails';
import useHasActiveAdminPolicies from '@hooks/useHasActiveAdminPolicies';
import useOnyx from '@hooks/useOnyx';
import {createDraftWorkspace, createWorkspace} from '@libs/actions/Policy/Policy';
import Navigation from '@libs/Navigation/Navigation';
Expand All @@ -22,6 +23,7 @@ function WorkspaceConfirmationForTravelPage({route}: WorkspaceConfirmationForTra
const [isSelfTourViewed] = useOnyx(ONYXKEYS.NVP_ONBOARDING, {selector: hasSeenTourSelector});

const currentUserPersonalDetails = useCurrentUserPersonalDetails();
const hasActiveAdminPolicies = useHasActiveAdminPolicies();

const goBack = () => {
Navigation.goBack(route.params?.backTo ?? ROUTES.TRAVEL_UPGRADE.route);
Expand All @@ -41,6 +43,7 @@ function WorkspaceConfirmationForTravelPage({route}: WorkspaceConfirmationForTra
currentUserEmailParam: currentUserPersonalDetails.email ?? '',
betas,
isSelfTourViewed,
hasActiveAdminPolicies,
});
goBack();
};
Expand Down
4 changes: 4 additions & 0 deletions src/pages/iou/request/step/IOURequestStepUpgrade.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import ScrollView from '@components/ScrollView';
import WorkspaceConfirmationForm from '@components/WorkspaceConfirmationForm';
import type {WorkspaceConfirmationSubmitFunctionParams} from '@components/WorkspaceConfirmationForm';
import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails';
import useHasActiveAdminPolicies from '@hooks/useHasActiveAdminPolicies';
import useLocalize from '@hooks/useLocalize';
import useNetwork from '@hooks/useNetwork';
import useOnyx from '@hooks/useOnyx';
Expand Down Expand Up @@ -43,6 +44,7 @@ function IOURequestStepUpgrade({
const {isOffline} = useNetwork();
const currentUserPersonalDetails = useCurrentUserPersonalDetails();
const personalDetails = usePersonalDetails();
const hasActiveAdminPolicies = useHasActiveAdminPolicies();

const [transaction] = useOnyx(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`);
const [onboardingPurposeSelected] = useOnyx(ONYXKEYS.ONBOARDING_PURPOSE_SELECTED);
Expand Down Expand Up @@ -167,6 +169,7 @@ function IOURequestStepUpgrade({
onboardingPurposeSelected,
betas,
isSelfTourViewed,
hasActiveAdminPolicies,
});
setIsUpgraded(true);
policyDataRef.current = policyData;
Expand Down Expand Up @@ -194,6 +197,7 @@ function IOURequestStepUpgrade({
onboardingPurposeSelected,
betas,
isSelfTourViewed,
hasActiveAdminPolicies,
});
policyDataRef.current = policyData;
setCreatedPolicyName(params.name);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import HeaderWithBackButton from '@components/HeaderWithBackButton';
import ScreenWrapper from '@components/ScreenWrapper';
import ScrollView from '@components/ScrollView';
import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails';
import useHasActiveAdminPolicies from '@hooks/useHasActiveAdminPolicies';
import useLocalize from '@hooks/useLocalize';
import useNetwork from '@hooks/useNetwork';
import useOnyx from '@hooks/useOnyx';
Expand Down Expand Up @@ -31,6 +32,7 @@ function PersonalCardUpgradePage() {
const [isSelfTourViewed] = useOnyx(ONYXKEYS.NVP_ONBOARDING, {selector: hasSeenTourSelector});

const currentUserPersonalDetails = useCurrentUserPersonalDetails();
const hasActiveAdminPolicies = useHasActiveAdminPolicies();

const onUpgrade = () => {
createWorkspaceWithPolicyDraft({
Expand All @@ -46,6 +48,7 @@ function PersonalCardUpgradePage() {
shouldCreateControlPolicy: false,
isSelfTourViewed,
betas,
hasActiveAdminPolicies,
});
setIsUpgraded(true);
};
Expand Down
4 changes: 4 additions & 0 deletions src/pages/workspace/WorkspaceConfirmationPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import ScreenWrapper from '@components/ScreenWrapper';
import WorkspaceConfirmationForm from '@components/WorkspaceConfirmationForm';
import type {WorkspaceConfirmationSubmitFunctionParams} from '@components/WorkspaceConfirmationForm';
import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails';
import useHasActiveAdminPolicies from '@hooks/useHasActiveAdminPolicies';
import useOnyx from '@hooks/useOnyx';
import usePrivateSubscription from '@hooks/usePrivateSubscription';
import useResponsiveLayout from '@hooks/useResponsiveLayout';
Expand All @@ -28,6 +29,8 @@ function WorkspaceConfirmationPage() {

const currentUserPersonalDetails = useCurrentUserPersonalDetails();
const privateSubscription = usePrivateSubscription();
const hasActiveAdminPolicies = useHasActiveAdminPolicies();

const onSubmit = (params: WorkspaceConfirmationSubmitFunctionParams) => {
const policyID = params.policyID || generatePolicyID();
const routeToNavigate = isSmallScreenWidth ? ROUTES.WORKSPACE_INITIAL.getRoute(policyID) : ROUTES.WORKSPACE_OVERVIEW.getRoute(policyID);
Expand All @@ -50,6 +53,7 @@ function WorkspaceConfirmationPage() {
type: params.planType,
isSelfTourViewed,
betas,
hasActiveAdminPolicies,
});
};
const currentUrl = getCurrentUrl();
Expand Down
3 changes: 3 additions & 0 deletions src/selectors/Policy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ const ownerPoliciesSelector = (policies: OnyxCollection<Policy>, currentUserAcco

const activeAdminPoliciesSelector = (policies: OnyxCollection<Policy>, currentUserAccountLogin: string) => getActiveAdminWorkspaces(policies, currentUserAccountLogin);

const hasActiveAdminPoliciesSelector = (policies: OnyxCollection<Policy>, currentUserAccountLogin: string) => !!activeAdminPoliciesSelector(policies, currentUserAccountLogin).length;

/**
* Creates a selector that aggregates all non-formula policy report fields from all policies,
* sorted alphabetically by field key using the provided locale compare function
Expand Down Expand Up @@ -137,6 +139,7 @@ export {
createAllPolicyReportFieldsSelector,
ownerPoliciesSelector,
activeAdminPoliciesSelector,
hasActiveAdminPoliciesSelector,
createPoliciesForDomainCardsSelector,
policyTimeTrackingSelector,
hasMultipleOutputCurrenciesSelector,
Expand Down
Loading
Loading