mirror of
https://github.com/4ian/GDevelop.git
synced 2025-10-15 10:19:04 +00:00
Compare commits
1 Commits
fix/disabl
...
refactor/l
Author | SHA1 | Date | |
---|---|---|---|
![]() |
cb2fad173c |
@@ -1,185 +0,0 @@
|
||||
// @flow
|
||||
import * as React from 'react';
|
||||
import { t, Trans } from '@lingui/macro';
|
||||
import { I18n as I18nType } from '@lingui/core';
|
||||
import { useResponsiveWindowSize } from '../../../../UI/Responsive/ResponsiveWindowMeasurer';
|
||||
import GDevelopThemeContext from '../../../../UI/Theme/GDevelopThemeContext';
|
||||
import { type SubscriptionPlanWithPricingSystems } from '../../../../Utils/GDevelopServices/Usage';
|
||||
import { Column, Line } from '../../../../UI/Grid';
|
||||
import Paper from '../../../../UI/Paper';
|
||||
import {
|
||||
ColumnStackLayout,
|
||||
ResponsiveLineStackLayout,
|
||||
} from '../../../../UI/Layout';
|
||||
import Text from '../../../../UI/Text';
|
||||
import CheckCircle from '../../../../UI/CustomSvgIcons/CheckCircle';
|
||||
import RaisedButton from '../../../../UI/RaisedButton';
|
||||
import Window from '../../../../Utils/Window';
|
||||
import { selectMessageByLocale } from '../../../../Utils/i18n/MessageByLocale';
|
||||
|
||||
const styles = {
|
||||
bulletIcon: { width: 20, height: 20, marginRight: 10 },
|
||||
bulletText: { flex: 1 },
|
||||
planRecommendationThumbnail: { maxWidth: 350, flex: 1 },
|
||||
planRecommendationContainer: { borderRadius: 8, maxWidth: 850, padding: 8 },
|
||||
};
|
||||
|
||||
const planImages = {
|
||||
individual: {
|
||||
path: 'res/plan-individual.svg',
|
||||
alt: t`Red hero taking care of their diamond`,
|
||||
},
|
||||
education: {
|
||||
path: 'res/plan-education.svg',
|
||||
alt: t`Red hero sharing knowledge with pink cloud students`,
|
||||
},
|
||||
professional: {
|
||||
path: 'res/plan-professional.svg',
|
||||
alt: t`Red and Green heroes running side by side carrying their diamonds`,
|
||||
},
|
||||
};
|
||||
|
||||
const planDetailsById = {
|
||||
silver: {
|
||||
title: <Trans>GDevelop's Silver plan</Trans>,
|
||||
description: (
|
||||
<Trans>Unlock GDevelop's features to build more and faster.</Trans>
|
||||
),
|
||||
image: planImages.individual,
|
||||
link: 'https://gdevelop.io/pricing/individual',
|
||||
},
|
||||
gold: {
|
||||
title: <Trans>GDevelop's Gold plan</Trans>,
|
||||
description: (
|
||||
<Trans>Unlock GDevelop's features to build more and faster.</Trans>
|
||||
),
|
||||
image: planImages.individual,
|
||||
link: 'https://gdevelop.io/pricing/individual',
|
||||
},
|
||||
education: {
|
||||
title: <Trans>GDevelop's Education plan</Trans>,
|
||||
description: (
|
||||
<Trans>
|
||||
For universities, extra curricular classes and summer camps.
|
||||
</Trans>
|
||||
),
|
||||
image: planImages.education,
|
||||
link: 'https://gdevelop.io/pricing/education',
|
||||
},
|
||||
startup: {
|
||||
title: <Trans>GDevelop's Startup plan</Trans>,
|
||||
description: (
|
||||
<Trans>
|
||||
Get the most out of GDevelop and get your games out in no time.
|
||||
</Trans>
|
||||
),
|
||||
image: planImages.professional,
|
||||
link: 'https://gdevelop.io/pricing/business',
|
||||
},
|
||||
business: {
|
||||
title: <Trans>GDevelop's Business plan</Trans>,
|
||||
description: (
|
||||
<Trans>
|
||||
Get the most out of GDevelop and get your games out in no time.
|
||||
</Trans>
|
||||
),
|
||||
image: planImages.professional,
|
||||
link: 'https://gdevelop.io/pricing/business',
|
||||
},
|
||||
};
|
||||
|
||||
const PlanRecommendationRow = ({
|
||||
recommendationPlanId,
|
||||
subscriptionPlansWithPricingSystems,
|
||||
i18n,
|
||||
}: {|
|
||||
recommendationPlanId: string,
|
||||
subscriptionPlansWithPricingSystems: SubscriptionPlanWithPricingSystems[],
|
||||
i18n: I18nType,
|
||||
|}) => {
|
||||
const gdevelopTheme = React.useContext(GDevelopThemeContext);
|
||||
const { isMobile } = useResponsiveWindowSize();
|
||||
const planToUse =
|
||||
recommendationPlanId === 'silver'
|
||||
? 'gdevelop_silver'
|
||||
: recommendationPlanId === 'gold'
|
||||
? 'gdevelop_gold'
|
||||
: recommendationPlanId === 'education'
|
||||
? 'gdevelop_education'
|
||||
: recommendationPlanId === 'startup' ||
|
||||
recommendationPlanId === 'business'
|
||||
? 'gdevelop_startup'
|
||||
: null;
|
||||
if (!planToUse) return null;
|
||||
|
||||
const plan = subscriptionPlansWithPricingSystems.find(
|
||||
plan => plan.id === planToUse
|
||||
);
|
||||
if (!plan) return null;
|
||||
|
||||
const planDetails = planDetailsById[recommendationPlanId];
|
||||
|
||||
return (
|
||||
<Line justifyContent="center">
|
||||
<Paper
|
||||
background="dark"
|
||||
style={{
|
||||
...styles.planRecommendationContainer,
|
||||
border: `1px solid ${gdevelopTheme.palette.secondary}`,
|
||||
}}
|
||||
>
|
||||
<ResponsiveLineStackLayout noColumnMargin noMargin>
|
||||
<img
|
||||
src={planDetails.image.path}
|
||||
alt={i18n._(planDetails.image.alt)}
|
||||
style={styles.planRecommendationThumbnail}
|
||||
/>
|
||||
<Line expand>
|
||||
<ColumnStackLayout>
|
||||
<Text
|
||||
noMargin
|
||||
align={isMobile ? 'center' : 'left'}
|
||||
size="section-title"
|
||||
>
|
||||
{planDetails.title}
|
||||
</Text>
|
||||
<Text align={isMobile ? 'center' : 'left'}>
|
||||
{planDetails.description}
|
||||
</Text>
|
||||
<div style={{ padding: `0 20px` }}>
|
||||
<ColumnStackLayout noMargin>
|
||||
{plan.bulletPointsByLocale.map(
|
||||
(bulletPointByLocale, index) => (
|
||||
<Column key={index} expand noMargin>
|
||||
<Line noMargin alignItems="center">
|
||||
<CheckCircle
|
||||
style={{
|
||||
...styles.bulletIcon,
|
||||
color: gdevelopTheme.message.valid,
|
||||
}}
|
||||
/>
|
||||
|
||||
<Text style={styles.bulletText} size="body2" noMargin>
|
||||
{selectMessageByLocale(i18n, bulletPointByLocale)}
|
||||
</Text>
|
||||
</Line>
|
||||
</Column>
|
||||
)
|
||||
)}
|
||||
</ColumnStackLayout>
|
||||
</div>
|
||||
<Column noMargin>
|
||||
<RaisedButton
|
||||
primary
|
||||
label={<Trans>Learn More</Trans>}
|
||||
onClick={() => Window.openExternalURL(planDetails.link)}
|
||||
/>
|
||||
</Column>
|
||||
</ColumnStackLayout>
|
||||
</Line>
|
||||
</ResponsiveLineStackLayout>
|
||||
</Paper>
|
||||
</Line>
|
||||
);
|
||||
};
|
||||
export default PlanRecommendationRow;
|
@@ -8,7 +8,6 @@ import { makeStyles } from '@material-ui/styles';
|
||||
import GridList from '@material-ui/core/GridList';
|
||||
import GridListTile from '@material-ui/core/GridListTile';
|
||||
import { type AuthenticatedUser } from '../../../../Profile/AuthenticatedUserContext';
|
||||
import { type Subscription } from '../../../../Utils/GDevelopServices/Usage';
|
||||
import { TutorialContext } from '../../../../Tutorial/TutorialContext';
|
||||
import { SectionRow } from '../SectionContainer';
|
||||
import GuidedLessons from '../InAppTutorials/GuidedLessons';
|
||||
@@ -21,16 +20,11 @@ import {
|
||||
import Text from '../../../../UI/Text';
|
||||
import { Column, Line, Spacer } from '../../../../UI/Grid';
|
||||
import { type Tutorial } from '../../../../Utils/GDevelopServices/Tutorial';
|
||||
import { type SubscriptionPlanWithPricingSystems } from '../../../../Utils/GDevelopServices/Usage';
|
||||
import { CardWidget } from '../CardWidget';
|
||||
import Window from '../../../../Utils/Window';
|
||||
import { ColumnStackLayout } from '../../../../UI/Layout';
|
||||
import {
|
||||
type GuidedLessonsRecommendation,
|
||||
type PlanRecommendation,
|
||||
} from '../../../../Utils/GDevelopServices/User';
|
||||
import { type GuidedLessonsRecommendation } from '../../../../Utils/GDevelopServices/User';
|
||||
import PreferencesContext from '../../../Preferences/PreferencesContext';
|
||||
import PlanRecommendationRow from './PlanRecommendationRow';
|
||||
import { SurveyCard } from './SurveyCard';
|
||||
import PlaceholderLoader from '../../../../UI/PlaceholderLoader';
|
||||
import PromotionsSlideshow from '../../../../Promotions/PromotionsSlideshow';
|
||||
@@ -109,26 +103,6 @@ const getTutorialsLimitsFromWidth = (
|
||||
}
|
||||
};
|
||||
|
||||
const isPlanRecommendationRelevant = (
|
||||
subscription: Subscription,
|
||||
planRecommendation: PlanRecommendation
|
||||
): boolean => {
|
||||
// Don't recommend plans to holders of education plan.
|
||||
if (subscription.planId === 'gdevelop_education') return false;
|
||||
|
||||
const relevantPlans =
|
||||
subscription.planId === 'gdevelop_silver' ||
|
||||
subscription.planId === 'gdevelop_indie'
|
||||
? ['gold', 'startup', 'business', 'education']
|
||||
: subscription.planId === 'gdevelop_gold' ||
|
||||
subscription.planId === 'gdevelop_pro'
|
||||
? ['startup', 'business', 'education']
|
||||
: subscription.planId === 'gdevelop_startup'
|
||||
? ['business']
|
||||
: [];
|
||||
return relevantPlans.includes(planRecommendation.id);
|
||||
};
|
||||
|
||||
type TextTutorialsRowProps = {|
|
||||
tutorials: Array<Tutorial>,
|
||||
i18n: I18nType,
|
||||
@@ -186,7 +160,6 @@ const TextTutorialsRow = ({ tutorials, i18n }: TextTutorialsRowProps) => {
|
||||
type Props = {|
|
||||
authenticatedUser: AuthenticatedUser,
|
||||
selectInAppTutorial: (tutorialId: string) => void,
|
||||
subscriptionPlansWithPricingSystems: ?(SubscriptionPlanWithPricingSystems[]),
|
||||
onStartSurvey: null | (() => void),
|
||||
hasFilledSurveyAlready: boolean,
|
||||
onOpenProfile: () => void,
|
||||
@@ -202,14 +175,13 @@ type Props = {|
|
||||
const RecommendationList = ({
|
||||
authenticatedUser,
|
||||
selectInAppTutorial,
|
||||
subscriptionPlansWithPricingSystems,
|
||||
onStartSurvey,
|
||||
hasFilledSurveyAlready,
|
||||
onOpenProfile,
|
||||
onCreateProjectFromExample,
|
||||
askToCloseProject,
|
||||
}: Props) => {
|
||||
const { recommendations, subscription, limits } = authenticatedUser;
|
||||
const { recommendations, limits } = authenticatedUser;
|
||||
const { tutorials } = React.useContext(TutorialContext);
|
||||
const {
|
||||
getTutorialProgress,
|
||||
@@ -251,11 +223,6 @@ const RecommendationList = ({
|
||||
? guidedLessonsRecommendation.lessonsIds
|
||||
: null;
|
||||
|
||||
// $FlowIgnore
|
||||
const planRecommendation: ?PlanRecommendation = recommendations.find(
|
||||
recommendation => recommendation.type === 'plan'
|
||||
);
|
||||
|
||||
const getInAppTutorialPartProgress = ({
|
||||
tutorialId,
|
||||
}: {
|
||||
@@ -373,32 +340,6 @@ const RecommendationList = ({
|
||||
</SectionRow>
|
||||
);
|
||||
}
|
||||
if (planRecommendation) {
|
||||
const shouldDisplayPlanRecommendation =
|
||||
limits &&
|
||||
!(
|
||||
limits.capabilities.classrooms &&
|
||||
limits.capabilities.classrooms.hideUpgradeNotice
|
||||
) &&
|
||||
(!subscription ||
|
||||
isPlanRecommendationRelevant(subscription, planRecommendation));
|
||||
if (
|
||||
shouldDisplayPlanRecommendation &&
|
||||
subscriptionPlansWithPricingSystems
|
||||
) {
|
||||
items.push(
|
||||
<SectionRow key="plan">
|
||||
<PlanRecommendationRow
|
||||
recommendationPlanId={planRecommendation.id}
|
||||
subscriptionPlansWithPricingSystems={
|
||||
subscriptionPlansWithPricingSystems
|
||||
}
|
||||
i18n={i18n}
|
||||
/>
|
||||
</SectionRow>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
|
@@ -23,7 +23,6 @@ import PreferencesContext from '../../../Preferences/PreferencesContext';
|
||||
import RecommendationList from './RecommendationList';
|
||||
import ErrorBoundary from '../../../../UI/ErrorBoundary';
|
||||
import { delay } from '../../../../Utils/Delay';
|
||||
import { type SubscriptionPlanWithPricingSystems } from '../../../../Utils/GDevelopServices/Usage';
|
||||
import Checkbox from '../../../../UI/Checkbox';
|
||||
import { sendUserSurveyCompleted } from '../../../../Utils/Analytics/EventSender';
|
||||
import { type NewProjectSetup } from '../../../../ProjectCreation/NewProjectSetupDialog';
|
||||
@@ -60,7 +59,6 @@ type Props = {|
|
||||
onUserSurveyStarted: () => void,
|
||||
onUserSurveyHidden: () => void,
|
||||
selectInAppTutorial: (tutorialId: string) => void,
|
||||
subscriptionPlansWithPricingSystems: ?(SubscriptionPlanWithPricingSystems[]),
|
||||
onOpenProfile: () => void,
|
||||
onCreateProjectFromExample: (
|
||||
exampleShortHeader: ExampleShortHeader,
|
||||
@@ -75,7 +73,6 @@ const GetStartedSection = ({
|
||||
selectInAppTutorial,
|
||||
onUserSurveyStarted,
|
||||
onUserSurveyHidden,
|
||||
subscriptionPlansWithPricingSystems,
|
||||
onOpenProfile,
|
||||
onCreateProjectFromExample,
|
||||
askToCloseProject,
|
||||
@@ -247,9 +244,6 @@ const GetStartedSection = ({
|
||||
<RecommendationList
|
||||
authenticatedUser={authenticatedUser}
|
||||
selectInAppTutorial={selectInAppTutorial}
|
||||
subscriptionPlansWithPricingSystems={
|
||||
subscriptionPlansWithPricingSystems
|
||||
}
|
||||
onOpenProfile={onOpenProfile}
|
||||
onStartSurvey={
|
||||
profile
|
||||
|
@@ -273,7 +273,7 @@ const ManageEducationAccountDialog = ({ onClose }: Props) => {
|
||||
const { openSubscriptionDialog } = React.useContext(
|
||||
SubscriptionSuggestionContext
|
||||
);
|
||||
const { subscriptionPlansWithPricingSystems } = useSubscriptionPlans({
|
||||
const { getSubscriptionPlansWithPricingSystems } = useSubscriptionPlans({
|
||||
includeLegacy: true,
|
||||
});
|
||||
const [selectedUserIds, setSelectedUserIds] = React.useState<string[]>([]);
|
||||
@@ -374,6 +374,7 @@ const ManageEducationAccountDialog = ({ onClose }: Props) => {
|
||||
[selectedUserIds, members]
|
||||
);
|
||||
|
||||
const subscriptionPlansWithPricingSystems = getSubscriptionPlansWithPricingSystems();
|
||||
const isLoading = !subscriptionPlansWithPricingSystems;
|
||||
|
||||
const availableSeats = getAvailableSeats();
|
||||
|
@@ -28,7 +28,6 @@ import { useResponsiveWindowSize } from '../../../UI/Responsive/ResponsiveWindow
|
||||
import { type PrivateGameTemplateListingData } from '../../../Utils/GDevelopServices/Shop';
|
||||
import { PrivateGameTemplateStoreContext } from '../../../AssetStore/PrivateGameTemplates/PrivateGameTemplateStoreContext';
|
||||
import PreferencesContext from '../../Preferences/PreferencesContext';
|
||||
import useSubscriptionPlans from '../../../Utils/UseSubscriptionPlans';
|
||||
import { incrementGetStartedSectionViewCount } from '../../../Utils/Analytics/LocalStats';
|
||||
import {
|
||||
sendUserSurveyHidden,
|
||||
@@ -292,9 +291,6 @@ export const HomePage = React.memo<Props>(
|
||||
: games.find(game => game.id === openedGameId),
|
||||
[games, openedGameId]
|
||||
);
|
||||
const { subscriptionPlansWithPricingSystems } = useSubscriptionPlans({
|
||||
includeLegacy: false,
|
||||
});
|
||||
|
||||
// Open the store and a pack or game template if asked to do so, either at
|
||||
// app opening, either when the route changes (when clicking on an announcement
|
||||
@@ -592,9 +588,6 @@ export const HomePage = React.memo<Props>(
|
||||
selectInAppTutorial={selectInAppTutorial}
|
||||
onUserSurveyStarted={onUserSurveyStarted}
|
||||
onUserSurveyHidden={onUserSurveyHidden}
|
||||
subscriptionPlansWithPricingSystems={
|
||||
subscriptionPlansWithPricingSystems
|
||||
}
|
||||
onOpenProfile={onOpenProfile}
|
||||
onCreateProjectFromExample={onCreateProjectFromExample}
|
||||
askToCloseProject={askToCloseProject}
|
||||
|
@@ -32,7 +32,7 @@ const ProfileDialog = ({ onClose }: Props) => {
|
||||
const authenticatedUser = React.useContext(AuthenticatedUserContext);
|
||||
const badgesSeenNotificationTimeoutRef = React.useRef<?TimeoutID>(null);
|
||||
const badgesSeenNotificationSentRef = React.useRef<boolean>(false);
|
||||
const { subscriptionPlansWithPricingSystems } = useSubscriptionPlans({
|
||||
const { getSubscriptionPlansWithPricingSystems } = useSubscriptionPlans({
|
||||
includeLegacy: true,
|
||||
authenticatedUser,
|
||||
});
|
||||
@@ -184,9 +184,7 @@ const ProfileDialog = ({ onClose }: Props) => {
|
||||
{isStudentAccount ? null : (
|
||||
<SubscriptionDetails
|
||||
subscription={authenticatedUser.subscription}
|
||||
subscriptionPlansWithPricingSystems={
|
||||
subscriptionPlansWithPricingSystems
|
||||
}
|
||||
subscriptionPlansWithPricingSystems={getSubscriptionPlansWithPricingSystems()}
|
||||
onManageSubscription={onManageSubscription}
|
||||
isManageSubscriptionLoading={isManageSubscriptionLoading}
|
||||
/>
|
||||
|
@@ -24,14 +24,16 @@ import AlertMessage from '../../../UI/AlertMessage';
|
||||
|
||||
type Props = {|
|
||||
onClose: Function,
|
||||
subscriptionPlansWithPricingSystems: ?(SubscriptionPlanWithPricingSystems[]),
|
||||
getAvailableSubscriptionPlansWithPrices: () =>
|
||||
| SubscriptionPlanWithPricingSystems[]
|
||||
| null,
|
||||
recommendedPlanId: string,
|
||||
onOpenPendingDialog: (open: boolean) => void,
|
||||
|};
|
||||
|
||||
export default function PromotionSubscriptionDialog({
|
||||
onClose,
|
||||
subscriptionPlansWithPricingSystems,
|
||||
getAvailableSubscriptionPlansWithPrices,
|
||||
recommendedPlanId,
|
||||
onOpenPendingDialog,
|
||||
}: Props) {
|
||||
@@ -79,6 +81,8 @@ export default function PromotionSubscriptionDialog({
|
||||
);
|
||||
};
|
||||
|
||||
const subscriptionPlansWithPricingSystems = getAvailableSubscriptionPlansWithPrices();
|
||||
|
||||
const purchasablePlansWithPricingSystems = React.useMemo(
|
||||
() =>
|
||||
subscriptionPlansWithPricingSystems
|
||||
|
@@ -203,16 +203,18 @@ export const getPlanSpecificRequirements = (
|
||||
|
||||
type Props = {|
|
||||
onClose: Function,
|
||||
subscriptionPlansWithPricingSystems: ?(SubscriptionPlanWithPricingSystems[]),
|
||||
userLegacySubscriptionPlanWithPricingSystem: ?SubscriptionPlanWithPricingSystems,
|
||||
getAvailableSubscriptionPlansWithPrices: () =>
|
||||
| SubscriptionPlanWithPricingSystems[]
|
||||
| null,
|
||||
getUserLegacySubscriptionPlanWithPricingSystem: () => SubscriptionPlanWithPricingSystems | null,
|
||||
filter: ?SubscriptionType,
|
||||
onOpenPendingDialog: (open: boolean) => void,
|
||||
|};
|
||||
|
||||
export default function SubscriptionDialog({
|
||||
onClose,
|
||||
subscriptionPlansWithPricingSystems,
|
||||
userLegacySubscriptionPlanWithPricingSystem,
|
||||
getAvailableSubscriptionPlansWithPrices,
|
||||
getUserLegacySubscriptionPlanWithPricingSystem,
|
||||
filter,
|
||||
onOpenPendingDialog,
|
||||
}: Props) {
|
||||
@@ -225,6 +227,8 @@ export default function SubscriptionDialog({
|
||||
] = React.useState<number>(20);
|
||||
const [redeemCodeDialogOpen, setRedeemCodeDialogOpen] = React.useState(false);
|
||||
const authenticatedUser = React.useContext(AuthenticatedUserContext);
|
||||
const subscriptionPlansWithPricingSystems = getAvailableSubscriptionPlansWithPrices();
|
||||
const userLegacySubscriptionPlanWithPricingSystem = getUserLegacySubscriptionPlanWithPricingSystem();
|
||||
const [period, setPeriod] = React.useState<'year' | 'month'>(
|
||||
getSubscriptionPricingSystemPeriod(
|
||||
authenticatedUser.subscription,
|
||||
|
@@ -14,11 +14,12 @@ import {
|
||||
import AuthenticatedUserContext from '../AuthenticatedUserContext';
|
||||
import useAlertDialog from '../../UI/Alert/useAlertDialog';
|
||||
import useSubscriptionPlans, {
|
||||
getAvailableSubscriptionPlansWithPrices,
|
||||
filterAvailableSubscriptionPlansWithPrices,
|
||||
} from '../../Utils/UseSubscriptionPlans';
|
||||
import PromotionSubscriptionDialog from './PromotionSubscriptionDialog';
|
||||
import SubscriptionPendingDialog from './SubscriptionPendingDialog';
|
||||
import LoaderModal from '../../UI/LoaderModal';
|
||||
import { useLazyMemo } from '../../Utils/UseLazyMemo';
|
||||
|
||||
export type SubscriptionType = 'individual' | 'team' | 'education';
|
||||
|
||||
@@ -62,7 +63,7 @@ export const SubscriptionSuggestionProvider = ({
|
||||
>(null);
|
||||
const authenticatedUser = React.useContext(AuthenticatedUserContext);
|
||||
const { showAlert } = useAlertDialog();
|
||||
const { subscriptionPlansWithPricingSystems } = useSubscriptionPlans({
|
||||
const { getSubscriptionPlansWithPricingSystems } = useSubscriptionPlans({
|
||||
includeLegacy: true,
|
||||
authenticatedUser,
|
||||
});
|
||||
@@ -101,46 +102,57 @@ export const SubscriptionSuggestionProvider = ({
|
||||
openSubscriptionDialog,
|
||||
]);
|
||||
|
||||
const availableSubscriptionPlansWithPrices = React.useMemo(
|
||||
() =>
|
||||
subscriptionPlansWithPricingSystems
|
||||
? getAvailableSubscriptionPlansWithPrices(
|
||||
subscriptionPlansWithPricingSystems
|
||||
)
|
||||
: null,
|
||||
[subscriptionPlansWithPricingSystems]
|
||||
const getAvailableSubscriptionPlansWithPrices = useLazyMemo(
|
||||
React.useCallback(
|
||||
() => {
|
||||
const subscriptionPlansWithPricingSystems = getSubscriptionPlansWithPricingSystems();
|
||||
|
||||
return subscriptionPlansWithPricingSystems
|
||||
? filterAvailableSubscriptionPlansWithPrices(
|
||||
subscriptionPlansWithPricingSystems
|
||||
)
|
||||
: null;
|
||||
},
|
||||
[getSubscriptionPlansWithPricingSystems]
|
||||
)
|
||||
);
|
||||
|
||||
const userLegacySubscriptionPlanWithPricingSystem = React.useMemo(
|
||||
() => {
|
||||
if (
|
||||
!authenticatedUser.subscription ||
|
||||
!authenticatedUser.subscription.planId ||
|
||||
!authenticatedUser.subscription.pricingSystemId ||
|
||||
!subscriptionPlansWithPricingSystems
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
const {
|
||||
planId: userPlanId,
|
||||
pricingSystemId: userPricingSystemId,
|
||||
} = authenticatedUser.subscription;
|
||||
const userPlanWithPricingSystems = subscriptionPlansWithPricingSystems.find(
|
||||
planWithPricingSystems => planWithPricingSystems.id === userPlanId
|
||||
);
|
||||
if (!userPlanWithPricingSystems || !userPlanWithPricingSystems.isLegacy) {
|
||||
return null;
|
||||
}
|
||||
const userPricingSystem = userPlanWithPricingSystems.pricingSystems.find(
|
||||
pricingSystem => pricingSystem.id === userPricingSystemId
|
||||
);
|
||||
if (!userPricingSystem) return null;
|
||||
return {
|
||||
...userPlanWithPricingSystems,
|
||||
pricingSystems: [userPricingSystem],
|
||||
};
|
||||
},
|
||||
[subscriptionPlansWithPricingSystems, authenticatedUser.subscription]
|
||||
const getUserLegacySubscriptionPlanWithPricingSystem = useLazyMemo(
|
||||
React.useCallback(
|
||||
() => {
|
||||
const subscriptionPlansWithPricingSystems = getSubscriptionPlansWithPricingSystems();
|
||||
if (
|
||||
!authenticatedUser.subscription ||
|
||||
!authenticatedUser.subscription.planId ||
|
||||
!authenticatedUser.subscription.pricingSystemId ||
|
||||
!subscriptionPlansWithPricingSystems
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
const {
|
||||
planId: userPlanId,
|
||||
pricingSystemId: userPricingSystemId,
|
||||
} = authenticatedUser.subscription;
|
||||
const userPlanWithPricingSystems = subscriptionPlansWithPricingSystems.find(
|
||||
planWithPricingSystems => planWithPricingSystems.id === userPlanId
|
||||
);
|
||||
if (
|
||||
!userPlanWithPricingSystems ||
|
||||
!userPlanWithPricingSystems.isLegacy
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
const userPricingSystem = userPlanWithPricingSystems.pricingSystems.find(
|
||||
pricingSystem => pricingSystem.id === userPricingSystemId
|
||||
);
|
||||
if (!userPricingSystem) return null;
|
||||
return {
|
||||
...userPlanWithPricingSystems,
|
||||
pricingSystems: [userPricingSystem],
|
||||
};
|
||||
},
|
||||
[getSubscriptionPlansWithPricingSystems, authenticatedUser.subscription]
|
||||
)
|
||||
);
|
||||
|
||||
// When the analyticsMetadata is set, a dialog is shown so we can send an event.
|
||||
@@ -172,8 +184,8 @@ export const SubscriptionSuggestionProvider = ({
|
||||
) : !hasValidSubscriptionPlan(authenticatedUser.subscription) &&
|
||||
analyticsMetadata.recommendedPlanId ? (
|
||||
<PromotionSubscriptionDialog
|
||||
subscriptionPlansWithPricingSystems={
|
||||
availableSubscriptionPlansWithPrices
|
||||
getAvailableSubscriptionPlansWithPrices={
|
||||
getAvailableSubscriptionPlansWithPrices
|
||||
}
|
||||
onClose={closeSubscriptionDialog}
|
||||
recommendedPlanId={analyticsMetadata.recommendedPlanId}
|
||||
@@ -183,11 +195,11 @@ export const SubscriptionSuggestionProvider = ({
|
||||
/>
|
||||
) : (
|
||||
<SubscriptionDialog
|
||||
subscriptionPlansWithPricingSystems={
|
||||
availableSubscriptionPlansWithPrices
|
||||
getAvailableSubscriptionPlansWithPrices={
|
||||
getAvailableSubscriptionPlansWithPrices
|
||||
}
|
||||
userLegacySubscriptionPlanWithPricingSystem={
|
||||
userLegacySubscriptionPlanWithPricingSystem
|
||||
getUserLegacySubscriptionPlanWithPricingSystem={
|
||||
getUserLegacySubscriptionPlanWithPricingSystem
|
||||
}
|
||||
onClose={closeSubscriptionDialog}
|
||||
filter={filter}
|
||||
|
78
newIDE/app/src/Utils/UseLazyMemo.js
Normal file
78
newIDE/app/src/Utils/UseLazyMemo.js
Normal file
@@ -0,0 +1,78 @@
|
||||
// @flow
|
||||
import * as React from 'react';
|
||||
import { useStableUpToDateRef } from './UseStableUpToDateCallback';
|
||||
|
||||
/**
|
||||
* Expose a getter that returns the value computed by the function, which
|
||||
* is then memoized as long as the function dependencies are stable.
|
||||
*
|
||||
* The function should be a React.useCallback - so that it is stable
|
||||
* and only recomputed when the dependencies change.
|
||||
*
|
||||
* During the computation, the previous value or null is returned.
|
||||
*/
|
||||
export const useAsyncLazyMemo = <T>(fn: () => Promise<T>): (() => T | null) => {
|
||||
const [value, setValue] = React.useState(null);
|
||||
const [requestedVersion, setRequestedVersion] = React.useState(0);
|
||||
const valueVersion = React.useRef(0);
|
||||
const isComputingForVersion = React.useRef<{ [version: number]: boolean }>(
|
||||
{}
|
||||
);
|
||||
const requestedVersionRef = useStableUpToDateRef(requestedVersion);
|
||||
|
||||
// If the function changes, it means that the value is no longer valid.
|
||||
// We increment the requested version.
|
||||
React.useEffect(
|
||||
() => {
|
||||
setRequestedVersion(requestedVersion => {
|
||||
return requestedVersion + 1;
|
||||
});
|
||||
},
|
||||
[fn]
|
||||
);
|
||||
|
||||
// If the function changes, we need to recompute the value.
|
||||
// If the value changed, the getter is also invalidated so it can be called again by components
|
||||
// depending on it.
|
||||
const getter = React.useCallback(
|
||||
() => {
|
||||
// Recompute the value if its version is older than the requested version
|
||||
// or if it's not even set.
|
||||
const shouldCompute =
|
||||
valueVersion.current < requestedVersion || value === null;
|
||||
|
||||
if (shouldCompute && !isComputingForVersion.current[requestedVersion]) {
|
||||
isComputingForVersion.current[requestedVersion] = true;
|
||||
fn()
|
||||
.then(result => {
|
||||
// Update the version of the value only if the computation is still
|
||||
// for the same version that is requested.
|
||||
if (requestedVersion === requestedVersionRef.current) {
|
||||
setValue(result);
|
||||
valueVersion.current = requestedVersion;
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
// We're done computing the value for this version.
|
||||
delete isComputingForVersion.current[requestedVersion];
|
||||
});
|
||||
}
|
||||
|
||||
return value;
|
||||
},
|
||||
[value, fn, requestedVersion, requestedVersionRef]
|
||||
);
|
||||
|
||||
return getter;
|
||||
};
|
||||
|
||||
/**
|
||||
* Expose a getter that returns the value computed by the function, which
|
||||
* is then memoized as long as the function dependencies are stable.
|
||||
*
|
||||
* The function should be a React.useCallback - so that it is stable
|
||||
* and only recomputed when the dependencies change.
|
||||
*/
|
||||
export const useLazyMemo = <T>(fn: () => T): (() => T | null) => {
|
||||
return useAsyncLazyMemo(React.useCallback(() => Promise.resolve(fn()), [fn]));
|
||||
};
|
@@ -9,6 +9,7 @@ import {
|
||||
type SubscriptionPlanPricingSystem,
|
||||
} from './GDevelopServices/Usage';
|
||||
import { type AuthenticatedUser } from '../Profile/AuthenticatedUserContext';
|
||||
import { useAsyncLazyMemo } from './UseLazyMemo';
|
||||
|
||||
const mergeSubscriptionPlansWithPrices = (
|
||||
subscriptionPlans: SubscriptionPlan[],
|
||||
@@ -35,7 +36,7 @@ const mergeSubscriptionPlansWithPrices = (
|
||||
.filter(Boolean);
|
||||
};
|
||||
|
||||
export const getAvailableSubscriptionPlansWithPrices = (
|
||||
export const filterAvailableSubscriptionPlansWithPrices = (
|
||||
subscriptionPlansWithPricingSystems: SubscriptionPlanWithPricingSystems[]
|
||||
): SubscriptionPlanWithPricingSystems[] => {
|
||||
const nonLegacyPlans = subscriptionPlansWithPricingSystems.filter(
|
||||
@@ -61,10 +62,6 @@ type Props = {|
|
||||
* Hook to access subscription plans across the app.
|
||||
*/
|
||||
const useSubscriptionPlans = ({ includeLegacy, authenticatedUser }: Props) => {
|
||||
const [
|
||||
subscriptionPlansWithPricingSystems,
|
||||
setSubscriptionPlansWithPrices,
|
||||
] = React.useState<?(SubscriptionPlanWithPricingSystems[])>(null);
|
||||
const userId =
|
||||
authenticatedUser && authenticatedUser.profile
|
||||
? authenticatedUser.profile.id
|
||||
@@ -74,7 +71,12 @@ const useSubscriptionPlans = ({ includeLegacy, authenticatedUser }: Props) => {
|
||||
: null;
|
||||
|
||||
const fetchSubscriptionPlansAndPrices = React.useCallback(
|
||||
async () => {
|
||||
async (): Promise<SubscriptionPlanWithPricingSystems[]> => {
|
||||
console.info(
|
||||
`Fetching subscription plans and pricing systems (includeLegacy=${
|
||||
includeLegacy ? 'true' : 'false'
|
||||
}, userId=${userId || 'null'})...`
|
||||
);
|
||||
const results = await Promise.all([
|
||||
listSubscriptionPlans({
|
||||
includeLegacy,
|
||||
@@ -87,21 +89,23 @@ const useSubscriptionPlans = ({ includeLegacy, authenticatedUser }: Props) => {
|
||||
userId,
|
||||
}),
|
||||
]);
|
||||
setSubscriptionPlansWithPrices(
|
||||
mergeSubscriptionPlansWithPrices(results[0], results[1])
|
||||
console.info(
|
||||
`Subscription plans and pricing systems (includeLegacy=${
|
||||
includeLegacy ? 'true' : 'false'
|
||||
}, userId=${userId || 'null'}) fetched.`
|
||||
);
|
||||
return mergeSubscriptionPlansWithPrices(results[0], results[1]);
|
||||
},
|
||||
[includeLegacy, getAuthorizationHeader, userId]
|
||||
);
|
||||
|
||||
React.useEffect(
|
||||
() => {
|
||||
fetchSubscriptionPlansAndPrices();
|
||||
},
|
||||
[fetchSubscriptionPlansAndPrices]
|
||||
const getSubscriptionPlansWithPricingSystems = useAsyncLazyMemo(
|
||||
fetchSubscriptionPlansAndPrices
|
||||
);
|
||||
|
||||
return { subscriptionPlansWithPricingSystems };
|
||||
return {
|
||||
getSubscriptionPlansWithPricingSystems,
|
||||
};
|
||||
};
|
||||
|
||||
export default useSubscriptionPlans;
|
||||
|
@@ -9,10 +9,6 @@ import PreferencesContext, {
|
||||
} from '../../../../MainFrame/Preferences/PreferencesContext';
|
||||
import inAppTutorialDecorator from '../../../InAppTutorialDecorator';
|
||||
import { TutorialStateProvider } from '../../../../Tutorial/TutorialContext';
|
||||
import useSubscriptionPlans, {
|
||||
getAvailableSubscriptionPlansWithPrices,
|
||||
} from '../../../../Utils/UseSubscriptionPlans';
|
||||
import LoaderModal from '../../../../UI/LoaderModal';
|
||||
|
||||
export default {
|
||||
title: 'HomePage/GetStartedSectionSection/RecommendationList',
|
||||
@@ -21,48 +17,29 @@ export default {
|
||||
};
|
||||
|
||||
export const Default = () => {
|
||||
const { subscriptionPlansWithPricingSystems } = useSubscriptionPlans({
|
||||
includeLegacy: true,
|
||||
authenticatedUser: fakeAuthenticatedUserWithNoSubscription,
|
||||
});
|
||||
return subscriptionPlansWithPricingSystems ? (
|
||||
<PreferencesContext.Provider value={initialPreferences}>
|
||||
<TutorialStateProvider>
|
||||
<RecommendationList
|
||||
onOpenProfile={action('onOpenProfile')}
|
||||
authenticatedUser={fakeAuthenticatedUserWithNoSubscription}
|
||||
selectInAppTutorial={action('selectInAppTutorial')}
|
||||
subscriptionPlansWithPricingSystems={getAvailableSubscriptionPlansWithPrices(
|
||||
subscriptionPlansWithPricingSystems
|
||||
)}
|
||||
onStartSurvey={null}
|
||||
hasFilledSurveyAlready={false}
|
||||
askToCloseProject={async () => true}
|
||||
onCreateProjectFromExample={action('onCreateProjectFromExample')}
|
||||
/>
|
||||
</TutorialStateProvider>
|
||||
</PreferencesContext.Provider>
|
||||
) : (
|
||||
<LoaderModal show />
|
||||
);
|
||||
<PreferencesContext.Provider value={initialPreferences}>
|
||||
<TutorialStateProvider>
|
||||
<RecommendationList
|
||||
onOpenProfile={action('onOpenProfile')}
|
||||
authenticatedUser={fakeAuthenticatedUserWithNoSubscription}
|
||||
selectInAppTutorial={action('selectInAppTutorial')}
|
||||
onStartSurvey={null}
|
||||
hasFilledSurveyAlready={false}
|
||||
askToCloseProject={async () => true}
|
||||
onCreateProjectFromExample={action('onCreateProjectFromExample')}
|
||||
/>
|
||||
</TutorialStateProvider>
|
||||
</PreferencesContext.Provider>;
|
||||
};
|
||||
|
||||
export const WithSurvey = () => {
|
||||
const { subscriptionPlansWithPricingSystems } = useSubscriptionPlans({
|
||||
includeLegacy: true,
|
||||
authenticatedUser: fakeAuthenticatedUserWithNoSubscription,
|
||||
});
|
||||
|
||||
return subscriptionPlansWithPricingSystems ? (
|
||||
return (
|
||||
<PreferencesContext.Provider value={initialPreferences}>
|
||||
<TutorialStateProvider>
|
||||
<RecommendationList
|
||||
onOpenProfile={action('onOpenProfile')}
|
||||
authenticatedUser={fakeAuthenticatedUserWithNoSubscription}
|
||||
selectInAppTutorial={action('selectInAppTutorial')}
|
||||
subscriptionPlansWithPricingSystems={getAvailableSubscriptionPlansWithPrices(
|
||||
subscriptionPlansWithPricingSystems
|
||||
)}
|
||||
onStartSurvey={action('onStartSurvey')}
|
||||
hasFilledSurveyAlready={false}
|
||||
askToCloseProject={async () => true}
|
||||
@@ -70,27 +47,17 @@ export const WithSurvey = () => {
|
||||
/>
|
||||
</TutorialStateProvider>
|
||||
</PreferencesContext.Provider>
|
||||
) : (
|
||||
<LoaderModal show />
|
||||
);
|
||||
};
|
||||
|
||||
export const WithSurveyAlreadyFilled = () => {
|
||||
const { subscriptionPlansWithPricingSystems } = useSubscriptionPlans({
|
||||
includeLegacy: true,
|
||||
authenticatedUser: fakeAuthenticatedUserWithNoSubscription,
|
||||
});
|
||||
|
||||
return subscriptionPlansWithPricingSystems ? (
|
||||
return (
|
||||
<PreferencesContext.Provider value={initialPreferences}>
|
||||
<TutorialStateProvider>
|
||||
<RecommendationList
|
||||
onOpenProfile={action('onOpenProfile')}
|
||||
authenticatedUser={fakeAuthenticatedUserWithNoSubscription}
|
||||
selectInAppTutorial={action('selectInAppTutorial')}
|
||||
subscriptionPlansWithPricingSystems={getAvailableSubscriptionPlansWithPrices(
|
||||
subscriptionPlansWithPricingSystems
|
||||
)}
|
||||
onStartSurvey={action('onStartSurvey')}
|
||||
hasFilledSurveyAlready={true}
|
||||
askToCloseProject={async () => true}
|
||||
@@ -98,7 +65,5 @@ export const WithSurveyAlreadyFilled = () => {
|
||||
/>
|
||||
</TutorialStateProvider>
|
||||
</PreferencesContext.Provider>
|
||||
) : (
|
||||
<LoaderModal show />
|
||||
);
|
||||
};
|
||||
|
@@ -10,10 +10,7 @@ import {
|
||||
} from '../../../../fixtures/GDevelopServicesTestData';
|
||||
import PromotionSubscriptionDialog from '../../../../Profile/Subscription/PromotionSubscriptionDialog';
|
||||
import AlertProvider from '../../../../UI/Alert/AlertProvider';
|
||||
import useSubscriptionPlans, {
|
||||
getAvailableSubscriptionPlansWithPrices,
|
||||
} from '../../../../Utils/UseSubscriptionPlans';
|
||||
import LoaderModal from '../../../../UI/LoaderModal';
|
||||
import { useGetAvailableSubscriptionPlansWithPrices } from './Utils';
|
||||
|
||||
export default {
|
||||
title: 'Subscription/PromotionSubscriptionDialog',
|
||||
@@ -22,154 +19,141 @@ export default {
|
||||
};
|
||||
|
||||
export const NotAuthenticatedSilverRecommended = () => {
|
||||
const { subscriptionPlansWithPricingSystems } = useSubscriptionPlans({
|
||||
includeLegacy: true,
|
||||
authenticatedUser: fakeNotAuthenticatedUser,
|
||||
});
|
||||
return subscriptionPlansWithPricingSystems ? (
|
||||
const getAvailableSubscriptionPlansWithPrices = useGetAvailableSubscriptionPlansWithPrices(
|
||||
{
|
||||
authenticatedUser: fakeNotAuthenticatedUser,
|
||||
}
|
||||
);
|
||||
return (
|
||||
<AlertProvider>
|
||||
<AuthenticatedUserContext.Provider value={fakeNotAuthenticatedUser}>
|
||||
<PromotionSubscriptionDialog
|
||||
subscriptionPlansWithPricingSystems={getAvailableSubscriptionPlansWithPrices(
|
||||
subscriptionPlansWithPricingSystems
|
||||
)}
|
||||
getAvailableSubscriptionPlansWithPrices={
|
||||
getAvailableSubscriptionPlansWithPrices
|
||||
}
|
||||
onClose={() => action('on close')()}
|
||||
recommendedPlanId="gdevelop_silver"
|
||||
onOpenPendingDialog={() => action('on open pending dialog')()}
|
||||
/>
|
||||
</AuthenticatedUserContext.Provider>
|
||||
</AlertProvider>
|
||||
) : (
|
||||
<LoaderModal show />
|
||||
);
|
||||
};
|
||||
|
||||
export const AuthenticatedSilverRecommended = () => {
|
||||
const { subscriptionPlansWithPricingSystems } = useSubscriptionPlans({
|
||||
includeLegacy: true,
|
||||
authenticatedUser: fakeAuthenticatedUserWithNoSubscription,
|
||||
});
|
||||
return subscriptionPlansWithPricingSystems ? (
|
||||
const getAvailableSubscriptionPlansWithPrices = useGetAvailableSubscriptionPlansWithPrices(
|
||||
{
|
||||
authenticatedUser: fakeNotAuthenticatedUser,
|
||||
}
|
||||
);
|
||||
return (
|
||||
<AlertProvider>
|
||||
<AuthenticatedUserContext.Provider
|
||||
value={fakeAuthenticatedUserWithNoSubscription}
|
||||
>
|
||||
<PromotionSubscriptionDialog
|
||||
subscriptionPlansWithPricingSystems={getAvailableSubscriptionPlansWithPrices(
|
||||
subscriptionPlansWithPricingSystems
|
||||
)}
|
||||
getAvailableSubscriptionPlansWithPrices={
|
||||
getAvailableSubscriptionPlansWithPrices
|
||||
}
|
||||
onClose={() => action('on close')()}
|
||||
recommendedPlanId="gdevelop_silver"
|
||||
onOpenPendingDialog={() => action('on open pending dialog')()}
|
||||
/>
|
||||
</AuthenticatedUserContext.Provider>
|
||||
</AlertProvider>
|
||||
) : (
|
||||
<LoaderModal show />
|
||||
);
|
||||
};
|
||||
|
||||
export const GoldRecommended = () => {
|
||||
const { subscriptionPlansWithPricingSystems } = useSubscriptionPlans({
|
||||
includeLegacy: true,
|
||||
authenticatedUser: fakeAuthenticatedUserWithNoSubscription,
|
||||
});
|
||||
return subscriptionPlansWithPricingSystems ? (
|
||||
const getAvailableSubscriptionPlansWithPrices = useGetAvailableSubscriptionPlansWithPrices(
|
||||
{
|
||||
authenticatedUser: fakeNotAuthenticatedUser,
|
||||
}
|
||||
);
|
||||
return (
|
||||
<AlertProvider>
|
||||
<AuthenticatedUserContext.Provider
|
||||
value={fakeAuthenticatedUserWithNoSubscription}
|
||||
>
|
||||
<PromotionSubscriptionDialog
|
||||
subscriptionPlansWithPricingSystems={getAvailableSubscriptionPlansWithPrices(
|
||||
subscriptionPlansWithPricingSystems
|
||||
)}
|
||||
getAvailableSubscriptionPlansWithPrices={
|
||||
getAvailableSubscriptionPlansWithPrices
|
||||
}
|
||||
onClose={() => action('on close')()}
|
||||
recommendedPlanId="gdevelop_gold"
|
||||
onOpenPendingDialog={() => action('on open pending dialog')()}
|
||||
/>
|
||||
</AuthenticatedUserContext.Provider>
|
||||
</AlertProvider>
|
||||
) : (
|
||||
<LoaderModal show />
|
||||
);
|
||||
};
|
||||
|
||||
export const ProRecommended = () => {
|
||||
const { subscriptionPlansWithPricingSystems } = useSubscriptionPlans({
|
||||
includeLegacy: true,
|
||||
authenticatedUser: fakeAuthenticatedUserWithNoSubscription,
|
||||
});
|
||||
return subscriptionPlansWithPricingSystems ? (
|
||||
const getAvailableSubscriptionPlansWithPrices = useGetAvailableSubscriptionPlansWithPrices(
|
||||
{
|
||||
authenticatedUser: fakeNotAuthenticatedUser,
|
||||
}
|
||||
);
|
||||
return (
|
||||
<AlertProvider>
|
||||
<AuthenticatedUserContext.Provider
|
||||
value={fakeAuthenticatedUserWithNoSubscription}
|
||||
>
|
||||
<PromotionSubscriptionDialog
|
||||
subscriptionPlansWithPricingSystems={getAvailableSubscriptionPlansWithPrices(
|
||||
subscriptionPlansWithPricingSystems
|
||||
)}
|
||||
getAvailableSubscriptionPlansWithPrices={
|
||||
getAvailableSubscriptionPlansWithPrices
|
||||
}
|
||||
onClose={() => action('on close')()}
|
||||
recommendedPlanId="gdevelop_startup"
|
||||
onOpenPendingDialog={() => action('on open pending dialog')()}
|
||||
/>
|
||||
</AuthenticatedUserContext.Provider>
|
||||
</AlertProvider>
|
||||
) : (
|
||||
<LoaderModal show />
|
||||
);
|
||||
};
|
||||
|
||||
export const EducationRecommended = () => {
|
||||
const { subscriptionPlansWithPricingSystems } = useSubscriptionPlans({
|
||||
includeLegacy: true,
|
||||
authenticatedUser: fakeAuthenticatedUserWithNoSubscription,
|
||||
});
|
||||
return subscriptionPlansWithPricingSystems ? (
|
||||
const getAvailableSubscriptionPlansWithPrices = useGetAvailableSubscriptionPlansWithPrices(
|
||||
{
|
||||
authenticatedUser: fakeNotAuthenticatedUser,
|
||||
}
|
||||
);
|
||||
return (
|
||||
<AlertProvider>
|
||||
<AuthenticatedUserContext.Provider
|
||||
value={fakeAuthenticatedUserWithNoSubscription}
|
||||
>
|
||||
<PromotionSubscriptionDialog
|
||||
subscriptionPlansWithPricingSystems={getAvailableSubscriptionPlansWithPrices(
|
||||
subscriptionPlansWithPricingSystems
|
||||
)}
|
||||
getAvailableSubscriptionPlansWithPrices={
|
||||
getAvailableSubscriptionPlansWithPrices
|
||||
}
|
||||
onClose={() => action('on close')()}
|
||||
recommendedPlanId="gdevelop_education"
|
||||
onOpenPendingDialog={() => action('on open pending dialog')()}
|
||||
/>
|
||||
</AuthenticatedUserContext.Provider>
|
||||
</AlertProvider>
|
||||
) : (
|
||||
<LoaderModal show />
|
||||
);
|
||||
};
|
||||
|
||||
export const WithoutSilverButRecommended = () => {
|
||||
const { subscriptionPlansWithPricingSystems } = useSubscriptionPlans({
|
||||
includeLegacy: true,
|
||||
authenticatedUser: fakeAuthenticatedUserWithNoSubscription,
|
||||
});
|
||||
const subscriptionPlansWithoutSilver = subscriptionPlansWithPricingSystems
|
||||
? subscriptionPlansWithPricingSystems.filter(
|
||||
plan => plan.id !== 'gdevelop_silver'
|
||||
)
|
||||
: null;
|
||||
return subscriptionPlansWithoutSilver ? (
|
||||
const getAvailableSubscriptionPlansWithPrices = useGetAvailableSubscriptionPlansWithPrices(
|
||||
{ authenticatedUser: fakeNotAuthenticatedUser, filterSilver: true }
|
||||
);
|
||||
return (
|
||||
<AlertProvider>
|
||||
<AuthenticatedUserContext.Provider
|
||||
value={fakeAuthenticatedUserWithNoSubscription}
|
||||
>
|
||||
<PromotionSubscriptionDialog
|
||||
subscriptionPlansWithPricingSystems={getAvailableSubscriptionPlansWithPrices(
|
||||
subscriptionPlansWithoutSilver
|
||||
)}
|
||||
getAvailableSubscriptionPlansWithPrices={
|
||||
getAvailableSubscriptionPlansWithPrices
|
||||
}
|
||||
onClose={() => action('on close')()}
|
||||
recommendedPlanId="gdevelop_silver"
|
||||
onOpenPendingDialog={() => action('on open pending dialog')()}
|
||||
/>
|
||||
</AuthenticatedUserContext.Provider>
|
||||
</AlertProvider>
|
||||
) : (
|
||||
<LoaderModal show />
|
||||
);
|
||||
};
|
||||
|
@@ -20,10 +20,10 @@ import {
|
||||
import subscriptionSuggestionDecorator from '../../../SubscriptionSuggestionDecorator';
|
||||
import SubscriptionDetails from '../../../../Profile/Subscription/SubscriptionDetails';
|
||||
import AlertProvider from '../../../../UI/Alert/AlertProvider';
|
||||
import useSubscriptionPlans, {
|
||||
getAvailableSubscriptionPlansWithPrices,
|
||||
} from '../../../../Utils/UseSubscriptionPlans';
|
||||
import LoaderModal from '../../../../UI/LoaderModal';
|
||||
import useSubscriptionPlans, {
|
||||
filterAvailableSubscriptionPlansWithPrices,
|
||||
} from '../../../../Utils/UseSubscriptionPlans';
|
||||
|
||||
export default {
|
||||
title: 'Subscription/SubscriptionDetails',
|
||||
@@ -184,15 +184,16 @@ export const Default = ({
|
||||
}
|
||||
|
||||
const { subscription: userSubscription } = authenticatedUser;
|
||||
const { subscriptionPlansWithPricingSystems } = useSubscriptionPlans({
|
||||
const { getSubscriptionPlansWithPricingSystems } = useSubscriptionPlans({
|
||||
includeLegacy: true,
|
||||
authenticatedUser,
|
||||
});
|
||||
const subscriptionPlansWithPricingSystems = getSubscriptionPlansWithPricingSystems();
|
||||
|
||||
return subscriptionPlansWithPricingSystems ? (
|
||||
<AlertProvider>
|
||||
<SubscriptionDetails
|
||||
subscriptionPlansWithPricingSystems={getAvailableSubscriptionPlansWithPrices(
|
||||
subscriptionPlansWithPricingSystems={filterAvailableSubscriptionPlansWithPrices(
|
||||
subscriptionPlansWithPricingSystems
|
||||
)}
|
||||
subscription={userSubscription}
|
||||
|
@@ -18,7 +18,7 @@ import {
|
||||
import SubscriptionDialog from '../../../../Profile/Subscription/SubscriptionDialog';
|
||||
import AlertProvider from '../../../../UI/Alert/AlertProvider';
|
||||
import useSubscriptionPlans, {
|
||||
getAvailableSubscriptionPlansWithPrices,
|
||||
filterAvailableSubscriptionPlansWithPrices,
|
||||
} from '../../../../Utils/UseSubscriptionPlans';
|
||||
import LoaderModal from '../../../../UI/LoaderModal';
|
||||
|
||||
@@ -161,29 +161,33 @@ export const Default = ({
|
||||
}
|
||||
}
|
||||
|
||||
const { subscriptionPlansWithPricingSystems } = useSubscriptionPlans({
|
||||
const { getSubscriptionPlansWithPricingSystems } = useSubscriptionPlans({
|
||||
includeLegacy: true,
|
||||
authenticatedUser,
|
||||
});
|
||||
const subscriptionPlansWithPricingSystems = getSubscriptionPlansWithPricingSystems();
|
||||
|
||||
const { subscription: userSubscription } = authenticatedUser;
|
||||
const userLegacySubscriptionPlanWithPricingSystem =
|
||||
userSubscription && subscriptionPlansWithPricingSystems
|
||||
? subscriptionPlansWithPricingSystems.find(
|
||||
planWithPricingSystem =>
|
||||
planWithPricingSystem.id === userSubscription.planId &&
|
||||
planWithPricingSystem.isLegacy
|
||||
)
|
||||
: null;
|
||||
(userSubscription &&
|
||||
subscriptionPlansWithPricingSystems &&
|
||||
subscriptionPlansWithPricingSystems.find(
|
||||
planWithPricingSystem =>
|
||||
planWithPricingSystem.id === userSubscription.planId &&
|
||||
planWithPricingSystem.isLegacy
|
||||
)) ||
|
||||
null;
|
||||
|
||||
return subscriptionPlansWithPricingSystems ? (
|
||||
<AlertProvider>
|
||||
<AuthenticatedUserContext.Provider value={authenticatedUser}>
|
||||
<SubscriptionDialog
|
||||
subscriptionPlansWithPricingSystems={getAvailableSubscriptionPlansWithPrices(
|
||||
subscriptionPlansWithPricingSystems
|
||||
)}
|
||||
userLegacySubscriptionPlanWithPricingSystem={
|
||||
getAvailableSubscriptionPlansWithPrices={() =>
|
||||
filterAvailableSubscriptionPlansWithPrices(
|
||||
subscriptionPlansWithPricingSystems
|
||||
)
|
||||
}
|
||||
getUserLegacySubscriptionPlanWithPricingSystem={() =>
|
||||
userLegacySubscriptionPlanWithPricingSystem
|
||||
}
|
||||
onClose={() => action('on close')()}
|
||||
|
@@ -0,0 +1,37 @@
|
||||
// @flow
|
||||
import * as React from 'react';
|
||||
import useSubscriptionPlans, {
|
||||
filterAvailableSubscriptionPlansWithPrices,
|
||||
} from '../../../../Utils/UseSubscriptionPlans';
|
||||
import { useLazyMemo } from '../../../../Utils/UseLazyMemo';
|
||||
import { type AuthenticatedUser } from '../../../../Profile/AuthenticatedUserContext';
|
||||
|
||||
export const useGetAvailableSubscriptionPlansWithPrices = ({
|
||||
authenticatedUser,
|
||||
filterSilver,
|
||||
}: {
|
||||
authenticatedUser: AuthenticatedUser,
|
||||
filterSilver?: boolean,
|
||||
}) => {
|
||||
const { getSubscriptionPlansWithPricingSystems } = useSubscriptionPlans({
|
||||
includeLegacy: true,
|
||||
authenticatedUser,
|
||||
});
|
||||
const getAvailableSubscriptionPlansWithPrices = useLazyMemo(
|
||||
React.useCallback(
|
||||
() => {
|
||||
const subscriptionPlansWithPricingSystems = getSubscriptionPlansWithPricingSystems();
|
||||
if (!subscriptionPlansWithPricingSystems) return null;
|
||||
|
||||
return filterAvailableSubscriptionPlansWithPrices(
|
||||
subscriptionPlansWithPricingSystems.filter(plan =>
|
||||
filterSilver ? plan.id !== 'gdevelop_silver' : true
|
||||
)
|
||||
);
|
||||
},
|
||||
[getSubscriptionPlansWithPricingSystems, filterSilver]
|
||||
)
|
||||
);
|
||||
|
||||
return getAvailableSubscriptionPlansWithPrices;
|
||||
};
|
Reference in New Issue
Block a user