forked from Expensify/App
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request Expensify#42690 from JKobrynski/createYourPlanSection
[Payment card / Subscription] Implement “Your plan” section (UI)
- Loading branch information
Showing
14 changed files
with
296 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import {useMemo} from 'react'; | ||
import {useOnyx} from 'react-native-onyx'; | ||
import {isPolicyOwner} from '@libs/PolicyUtils'; | ||
import CONST from '@src/CONST'; | ||
import ONYXKEYS from '@src/ONYXKEYS'; | ||
import {isEmptyObject} from '@src/types/utils/EmptyObject'; | ||
|
||
function useSubscriptionPlan() { | ||
const [policies] = useOnyx(ONYXKEYS.COLLECTION.POLICY); | ||
const [session] = useOnyx(ONYXKEYS.SESSION); | ||
|
||
// Filter workspaces in which user is the owner and the type is either corporate (control) or team (collect) | ||
const ownerPolicies = useMemo( | ||
() => | ||
Object.values(policies ?? {}).filter( | ||
(policy) => isPolicyOwner(policy, session?.accountID ?? -1) && (CONST.POLICY.TYPE.CORPORATE === policy?.type || CONST.POLICY.TYPE.TEAM === policy?.type), | ||
), | ||
[policies, session?.accountID], | ||
); | ||
|
||
if (isEmptyObject(ownerPolicies)) { | ||
return null; | ||
} | ||
|
||
// Check if user has corporate (control) workspace | ||
const hasControlWorkspace = ownerPolicies.some((policy) => policy?.type === CONST.POLICY.TYPE.CORPORATE); | ||
|
||
// Corporate (control) workspace is supposed to be the higher priority | ||
return hasControlWorkspace ? CONST.POLICY.TYPE.CORPORATE : CONST.POLICY.TYPE.TEAM; | ||
} | ||
|
||
export default useSubscriptionPlan; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import * as API from '@libs/API'; | ||
import {READ_COMMANDS} from '@libs/API/types'; | ||
|
||
/** | ||
* Fetches data when the user opens the SubscriptionSettingsPage | ||
*/ | ||
function openSubscriptionPage() { | ||
API.read(READ_COMMANDS.OPEN_SUBSCRIPTION_PAGE, {}); | ||
} | ||
|
||
export { | ||
// eslint-disable-next-line import/prefer-default-export | ||
openSubscriptionPage, | ||
}; |
6 changes: 6 additions & 0 deletions
6
src/pages/settings/Subscription/SaveWithExpensifyButton/index.native.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
/** Return null because this button is not supposed to be rendered in the native apps */ | ||
function SaveWithExpensifyButton() { | ||
return null; | ||
} | ||
|
||
export default SaveWithExpensifyButton; |
23 changes: 23 additions & 0 deletions
23
src/pages/settings/Subscription/SaveWithExpensifyButton/index.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import React from 'react'; | ||
import {Linking} from 'react-native'; | ||
import Button from '@components/Button'; | ||
import useLocalize from '@hooks/useLocalize'; | ||
import CONST from '@src/CONST'; | ||
|
||
function SaveWithExpensifyButton() { | ||
const {translate} = useLocalize(); | ||
|
||
const onLinkPress = () => { | ||
Linking.openURL(CONST.SAVE_WITH_EXPENSIFY_URL); | ||
}; | ||
|
||
return ( | ||
<Button | ||
text={translate('subscription.yourPlan.saveWithExpensifyButton')} | ||
onPress={onLinkPress} | ||
medium | ||
/> | ||
); | ||
} | ||
|
||
export default SaveWithExpensifyButton; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
import React from 'react'; | ||
import {View} from 'react-native'; | ||
import {useOnyx} from 'react-native-onyx'; | ||
import Icon from '@components/Icon'; | ||
import * as Expensicons from '@components/Icon/Expensicons'; | ||
import * as Illustrations from '@components/Icon/Illustrations'; | ||
import Section from '@components/Section'; | ||
import Text from '@components/Text'; | ||
import useLocalize from '@hooks/useLocalize'; | ||
import useSubscriptionPlan from '@hooks/useSubscriptionPlan'; | ||
import useTheme from '@hooks/useTheme'; | ||
import useThemeStyles from '@hooks/useThemeStyles'; | ||
import variables from '@styles/variables'; | ||
import CONST from '@src/CONST'; | ||
import ONYXKEYS from '@src/ONYXKEYS'; | ||
import SaveWithExpensifyButton from './SaveWithExpensifyButton'; | ||
|
||
function SubscriptionPlan() { | ||
const {translate} = useLocalize(); | ||
const styles = useThemeStyles(); | ||
const theme = useTheme(); | ||
|
||
const subscriptionPlan = useSubscriptionPlan(); | ||
const [privateSubscription] = useOnyx(ONYXKEYS.NVP_PRIVATE_SUBSCRIPTION); | ||
|
||
const isCollect = subscriptionPlan === CONST.POLICY.TYPE.TEAM; | ||
const isAnnual = privateSubscription?.type === CONST.SUBSCRIPTION.TYPE.ANNUAL; | ||
|
||
const benefitsList = isCollect | ||
? [ | ||
translate('subscription.yourPlan.collect.benefit1'), | ||
translate('subscription.yourPlan.collect.benefit2'), | ||
translate('subscription.yourPlan.collect.benefit3'), | ||
translate('subscription.yourPlan.collect.benefit4'), | ||
translate('subscription.yourPlan.collect.benefit5'), | ||
translate('subscription.yourPlan.collect.benefit6'), | ||
translate('subscription.yourPlan.collect.benefit7'), | ||
] | ||
: [ | ||
translate('subscription.yourPlan.control.benefit1'), | ||
translate('subscription.yourPlan.control.benefit2'), | ||
translate('subscription.yourPlan.control.benefit3'), | ||
translate('subscription.yourPlan.control.benefit4'), | ||
translate('subscription.yourPlan.control.benefit5'), | ||
translate('subscription.yourPlan.control.benefit6'), | ||
]; | ||
|
||
return ( | ||
<Section | ||
title={translate('subscription.yourPlan.title')} | ||
isCentralPane | ||
titleStyles={styles.textStrong} | ||
> | ||
<View style={[styles.borderedContentCard, styles.mt5, styles.p5]}> | ||
<Icon | ||
src={isCollect ? Illustrations.Mailbox : Illustrations.ShieldYellow} | ||
width={variables.iconHeader} | ||
height={variables.iconHeader} | ||
/> | ||
<Text style={[styles.headerText, styles.mt2]}>{translate(`subscription.yourPlan.${isCollect ? 'collect' : 'control'}.title`)}</Text> | ||
<Text style={[styles.textLabelSupporting, styles.mb2]}> | ||
{translate(`subscription.yourPlan.${isCollect ? 'collect' : 'control'}.${isAnnual ? 'priceAnnual' : 'pricePayPerUse'}`)} | ||
</Text> | ||
{benefitsList.map((benefit) => ( | ||
<View | ||
style={[styles.flexRow, styles.alignItemsCenter, styles.mt2]} | ||
key={benefit} | ||
> | ||
<Icon | ||
src={Expensicons.Checkmark} | ||
fill={theme.iconSuccessFill} | ||
/> | ||
<Text style={[styles.textMicroSupporting, styles.ml2]}>{benefit}</Text> | ||
</View> | ||
))} | ||
</View> | ||
<View style={[styles.flexRow, styles.alignItemsCenter, styles.mt6]}> | ||
<Icon | ||
src={Illustrations.HandCard} | ||
width={variables.iconHeader} | ||
height={variables.iconHeader} | ||
additionalStyles={styles.mr2} | ||
/> | ||
<View style={[styles.flexColumn, styles.justifyContentCenter, styles.flex1, styles.mr2]}> | ||
<Text style={[styles.headerText, styles.mt2]}>{translate('subscription.yourPlan.saveWithExpensifyTitle')}</Text> | ||
<Text style={[styles.textLabelSupporting, styles.mb2]}>{translate('subscription.yourPlan.saveWithExpensifyDescription')}</Text> | ||
</View> | ||
<SaveWithExpensifyButton /> | ||
</View> | ||
</Section> | ||
); | ||
} | ||
|
||
export default SubscriptionPlan; |
22 changes: 18 additions & 4 deletions
22
src/pages/settings/Subscription/SubscriptionSettingsPage.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import type {ValueOf} from 'type-fest'; | ||
import type CONST from '@src/CONST'; | ||
|
||
type PrivateSubscription = { | ||
/** "auto increase annual seats" setting */ | ||
addNewUsersAutomatically: boolean; | ||
|
||
/** "auto renew" setting */ | ||
autoRenew: boolean; | ||
|
||
/** The date "auto renew" was last edited */ | ||
autoRenewLastChangedDate: string; | ||
|
||
/** "corporate karma" setting */ | ||
donateToExpensifyOrg?: true; | ||
|
||
/** Subscription end date */ | ||
endDate: string; | ||
|
||
/** Subscription start date */ | ||
startDate: string; | ||
|
||
/** Subscription variant. "yearly2018" - annual, "monthly2018" - pay-per-use */ | ||
type: ValueOf<typeof CONST.SUBSCRIPTION.TYPE>; | ||
|
||
/** Subscription size */ | ||
userCount?: number; | ||
}; | ||
|
||
export default PrivateSubscription; |
Oops, something went wrong.