mirror of
https://github.com/streetwriters/notesnook.git
synced 2025-12-16 19:57:52 +01:00
add compact premium dialog
This commit is contained in:
@@ -84,7 +84,7 @@ const GeneralSheet = ({context}) => {
|
||||
) : null}
|
||||
</View>
|
||||
|
||||
{dialogData.component}
|
||||
{typeof dialogData.component === "function" ? dialogData.component(actionSheetRef):dialogData.component}
|
||||
|
||||
{dialogData?.learnMore ? (
|
||||
<Paragraph
|
||||
|
||||
69
apps/mobile/src/components/Premium/compactfeatures.js
Normal file
69
apps/mobile/src/components/Premium/compactfeatures.js
Normal file
@@ -0,0 +1,69 @@
|
||||
import React from 'react';
|
||||
import {ScrollView} from 'react-native';
|
||||
import {useTracked} from '../../provider';
|
||||
import {FeatureBlock} from './feature';
|
||||
|
||||
export const CompactFeatures = ({vertical,features = [],maxHeight=500,scrollRef}) => {
|
||||
const [state, dispatch] = useTracked();
|
||||
const {colors} = state;
|
||||
let data = vertical ? features : [
|
||||
{
|
||||
highlight: 'Everything',
|
||||
content: 'in basic',
|
||||
icon: 'emoticon-wink'
|
||||
},
|
||||
{
|
||||
highlight: 'Unlimited',
|
||||
content: 'notebooks',
|
||||
icon: 'notebook'
|
||||
},
|
||||
{
|
||||
highlight: 'File & image',
|
||||
content: 'attachments',
|
||||
icon: 'attachment'
|
||||
},
|
||||
{
|
||||
highlight: 'Instant',
|
||||
content: 'syncing',
|
||||
icon: 'sync'
|
||||
},
|
||||
{
|
||||
highlight: 'Private',
|
||||
content: 'vault',
|
||||
icon: 'shield'
|
||||
},
|
||||
{
|
||||
highlight: 'Rich text',
|
||||
content: 'editing',
|
||||
icon: 'square-edit-outline'
|
||||
},
|
||||
{
|
||||
highlight: 'PDF & markdown',
|
||||
content: 'exports',
|
||||
icon: 'file'
|
||||
},
|
||||
{
|
||||
highlight: 'Encrypted',
|
||||
content: 'backups',
|
||||
icon: 'backup-restore'
|
||||
}
|
||||
]
|
||||
|
||||
return (
|
||||
<ScrollView
|
||||
horizontal={!vertical}
|
||||
nestedScrollEnabled
|
||||
onMomentumScrollEnd={() => {
|
||||
scrollRef?.current?.handleChildScrollEnd();
|
||||
}}
|
||||
showsHorizontalScrollIndicator={false}
|
||||
style={{
|
||||
width: '100%',
|
||||
maxHeight:maxHeight
|
||||
}}>
|
||||
{data.map(item => (
|
||||
<FeatureBlock vertical={vertical} {...item} />
|
||||
))}
|
||||
</ScrollView>
|
||||
);
|
||||
};
|
||||
@@ -9,7 +9,6 @@ import { eOpenLoginDialog } from '../../utils/Events';
|
||||
import { SIZE } from '../../utils/SizeUtils';
|
||||
import { ActionIcon } from '../ActionIcon';
|
||||
import { Button } from '../Button';
|
||||
import { Dialog } from '../Dialog';
|
||||
import GeneralSheet from '../GeneralSheet';
|
||||
import Seperator from '../Seperator';
|
||||
import { Toast } from '../Toast';
|
||||
@@ -62,7 +61,6 @@ export const Component = ({close, promo, getRef}) => {
|
||||
borderRadius: 10,
|
||||
maxHeight: DDS.isTab ? '90%' : '100%'
|
||||
}}>
|
||||
|
||||
<GeneralSheet context="pricing_plans" />
|
||||
<ActionIcon
|
||||
onPress={() => {
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { ScrollView, View } from 'react-native';
|
||||
import { View } from 'react-native';
|
||||
import { useTracked } from '../../provider';
|
||||
import {
|
||||
eSendEvent,
|
||||
eSubscribeEvent,
|
||||
eUnSubscribeEvent,
|
||||
presentSheet
|
||||
eUnSubscribeEvent
|
||||
} from '../../services/EventManager';
|
||||
import PremiumService from '../../services/PremiumService';
|
||||
import {
|
||||
eOpenPremiumDialog,
|
||||
eOpenResultDialog,
|
||||
@@ -20,18 +20,17 @@ import DialogContainer from '../Dialog/dialog-container';
|
||||
import Seperator from '../Seperator';
|
||||
import Heading from '../Typography/Heading';
|
||||
import Paragraph from '../Typography/Paragraph';
|
||||
import { FeatureBlock } from './feature';
|
||||
import { CompactFeatures } from './compact-features';
|
||||
import { Offer } from './offer';
|
||||
import { PricingPlans } from './pricing-plans';
|
||||
|
||||
export const Expiring = () => {
|
||||
const [state, dispatch] = useTracked();
|
||||
const {colors} = state;
|
||||
const [visible, setVisible] = useState(false);
|
||||
const [status, setStatus] = useState({
|
||||
title: '',
|
||||
title: 'Your trial is ending soon',
|
||||
offer: null,
|
||||
extend: false
|
||||
extend: true
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
@@ -97,57 +96,7 @@ export const Expiring = () => {
|
||||
</>
|
||||
)}
|
||||
|
||||
<ScrollView
|
||||
horizontal
|
||||
showsHorizontalScrollIndicator={false}
|
||||
style={{
|
||||
width: '100%'
|
||||
}}>
|
||||
{[
|
||||
{
|
||||
highlight: 'Everything',
|
||||
content: 'in basic',
|
||||
icon: 'emoticon-wink'
|
||||
},
|
||||
{
|
||||
highlight: 'Unlimited',
|
||||
content: 'notebooks',
|
||||
icon: 'notebook'
|
||||
},
|
||||
{
|
||||
highlight: 'File & image',
|
||||
content: 'attachments',
|
||||
icon: 'attachment'
|
||||
},
|
||||
{
|
||||
highlight: 'Instant',
|
||||
content: 'syncing',
|
||||
icon: 'sync'
|
||||
},
|
||||
{
|
||||
highlight: 'Private',
|
||||
content: 'vault',
|
||||
icon: 'shield'
|
||||
},
|
||||
{
|
||||
highlight: 'Rich text',
|
||||
content: 'editing',
|
||||
icon: 'square-edit-outline'
|
||||
},
|
||||
{
|
||||
highlight: 'PDF & markdown',
|
||||
content: 'exports',
|
||||
icon: 'file'
|
||||
},
|
||||
{
|
||||
highlight: 'Encrypted',
|
||||
content: 'backups',
|
||||
icon: 'backup-restore'
|
||||
}
|
||||
].map(item => (
|
||||
<FeatureBlock {...item} />
|
||||
))}
|
||||
</ScrollView>
|
||||
<CompactFeatures/>
|
||||
|
||||
<Paragraph
|
||||
onPress={async () => {
|
||||
@@ -181,16 +130,12 @@ export const Expiring = () => {
|
||||
onPress={async () => {
|
||||
setVisible(false);
|
||||
await sleep(300);
|
||||
presentSheet({
|
||||
component: <PricingPlans marginTop={1} promo={null} />,
|
||||
noIcon: true,
|
||||
noProgress: true
|
||||
});
|
||||
PremiumService.sheet(null,status.offer)
|
||||
}}
|
||||
fontSize={SIZE.lg}
|
||||
fontSize={SIZE.md + 2}
|
||||
style={{
|
||||
marginBottom: status.extend ? 0 : 12,
|
||||
marginTop: 12,
|
||||
marginBottom: status.extend ? 0 : 10,
|
||||
marginTop: 10,
|
||||
paddingHorizontal: 24
|
||||
}}
|
||||
/>
|
||||
@@ -212,10 +157,10 @@ export const Expiring = () => {
|
||||
button: 'Continue'
|
||||
});
|
||||
}}
|
||||
fontSize={SIZE.sm}
|
||||
fontSize={SIZE.xs + 1}
|
||||
height={30}
|
||||
style={{
|
||||
marginBottom: 12
|
||||
marginBottom: 10
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -8,11 +8,38 @@ import Seperator from '../Seperator';
|
||||
import Paragraph from '../Typography/Paragraph';
|
||||
import {ProTag} from './pro-tag';
|
||||
|
||||
export const FeatureBlock = ({highlight, content, icon, pro, proTagBg}) => {
|
||||
export const FeatureBlock = ({
|
||||
vertical,
|
||||
highlight,
|
||||
content,
|
||||
icon,
|
||||
pro,
|
||||
proTagBg
|
||||
}) => {
|
||||
const [state, dispatch] = useTracked();
|
||||
const {colors} = state;
|
||||
|
||||
return (
|
||||
return vertical ? (
|
||||
<View
|
||||
style={{
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
paddingHorizontal: 12,
|
||||
marginBottom: 10,
|
||||
}}>
|
||||
<Icon color={colors.accent} name="check" size={SIZE.lg} />
|
||||
|
||||
<Paragraph
|
||||
style={{
|
||||
flexWrap: 'wrap',
|
||||
marginLeft: 5,
|
||||
flexShrink: 1
|
||||
}}
|
||||
size={SIZE.md}>
|
||||
{content}
|
||||
</Paragraph>
|
||||
</View>
|
||||
) : (
|
||||
<View
|
||||
style={{
|
||||
height: 100,
|
||||
|
||||
@@ -1,34 +1,41 @@
|
||||
import React from 'react';
|
||||
import {View} from 'react-native';
|
||||
import {useTracked} from '../../provider';
|
||||
import { getElevation } from '../../utils';
|
||||
import {SIZE} from '../../utils/SizeUtils';
|
||||
import {PressableButton} from '../PressableButton';
|
||||
import Heading from '../Typography/Heading';
|
||||
import Paragraph from '../Typography/Paragraph';
|
||||
|
||||
export const PricingItem = ({product, onPress}) => {
|
||||
export const PricingItem = ({product, onPress, compact}) => {
|
||||
const [state, dispatch] = useTracked();
|
||||
const colors = state.colors;
|
||||
|
||||
return (
|
||||
<PressableButton
|
||||
onPress={onPress}
|
||||
type="grayBg"
|
||||
customStyle={{
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'flex-start',
|
||||
alignItems: 'center',
|
||||
paddingHorizontal: 12,
|
||||
paddingVertical: 10
|
||||
paddingVertical: compact ? 15 : 10,
|
||||
width: compact ? null : '100%',
|
||||
minWidth: 150,
|
||||
}}>
|
||||
<View>
|
||||
<Heading size={SIZE.lg - 2}>
|
||||
{product?.type === 'yearly' || product?.offerType === 'yearly'
|
||||
? 'Yearly'
|
||||
: 'Monthly'}
|
||||
</Heading>
|
||||
{product?.info && (
|
||||
<Paragraph size={SIZE.xs + 1}>{product.info}</Paragraph>
|
||||
)}
|
||||
</View>
|
||||
{!compact && (
|
||||
<View>
|
||||
<Heading size={SIZE.lg - 2}>
|
||||
{product?.type === 'yearly' || product?.offerType === 'yearly'
|
||||
? 'Yearly'
|
||||
: 'Monthly'}
|
||||
</Heading>
|
||||
{product?.info && (
|
||||
<Paragraph size={SIZE.xs + 1}>{product.info}</Paragraph>
|
||||
)}
|
||||
</View>
|
||||
)}
|
||||
|
||||
<View>
|
||||
<Paragraph size={SIZE.sm}>
|
||||
|
||||
@@ -37,10 +37,15 @@ const promoCyclesYearly = {
|
||||
3: 'first 3 years'
|
||||
};
|
||||
|
||||
export const PricingPlans = ({promo, marginTop}) => {
|
||||
export const PricingPlans = ({
|
||||
promo,
|
||||
marginTop,
|
||||
heading = true,
|
||||
compact = false
|
||||
}) => {
|
||||
const [state, dispatch] = useTracked();
|
||||
const colors = state.colors;
|
||||
const user = useUserStore(state => state.user);
|
||||
const user = {}; //useUserStore(state => state.user);
|
||||
const [product, setProduct] = useState(null);
|
||||
const [products, setProducts] = useState([]);
|
||||
const [offers, setOffers] = useState(null);
|
||||
@@ -155,40 +160,52 @@ export const PricingPlans = ({promo, marginTop}) => {
|
||||
|
||||
{user && !product ? (
|
||||
<>
|
||||
<Heading
|
||||
style={{
|
||||
alignSelf: 'center',
|
||||
marginTop: marginTop || 20,
|
||||
marginBottom: 20
|
||||
}}>
|
||||
Choose a plan
|
||||
</Heading>
|
||||
|
||||
<PricingItem
|
||||
onPress={() => buySubscription(offers?.monthly)}
|
||||
product={{
|
||||
type: 'monthly',
|
||||
data: offers?.monthly,
|
||||
info: 'Pay monthly, cancel anytime.'
|
||||
}}
|
||||
/>
|
||||
{heading ? (
|
||||
<Heading
|
||||
style={{
|
||||
alignSelf: 'center',
|
||||
marginTop: marginTop || 20,
|
||||
marginBottom: 20
|
||||
}}>
|
||||
Choose a plan
|
||||
</Heading>
|
||||
) : null}
|
||||
|
||||
<View
|
||||
style={{
|
||||
height: 1,
|
||||
backgroundColor: colors.nav,
|
||||
marginVertical: 10
|
||||
}}
|
||||
/>
|
||||
flexDirection: !compact ? 'column' : 'row',
|
||||
flexWrap: 'wrap',
|
||||
justifyContent: 'space-around'
|
||||
}}>
|
||||
<PricingItem
|
||||
onPress={() => buySubscription(offers?.monthly)}
|
||||
compact={compact}
|
||||
product={{
|
||||
type: 'monthly',
|
||||
data: offers?.monthly,
|
||||
info: 'Pay monthly, cancel anytime.'
|
||||
}}
|
||||
/>
|
||||
|
||||
<PricingItem
|
||||
onPress={() => buySubscription(offers?.yearly)}
|
||||
product={{
|
||||
type: 'yearly',
|
||||
data: offers?.yearly,
|
||||
info: 'Pay yearly'
|
||||
}}
|
||||
/>
|
||||
{!compact && (
|
||||
<View
|
||||
style={{
|
||||
height: 1,
|
||||
marginVertical: 5
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
<PricingItem
|
||||
onPress={() => buySubscription(offers?.yearly)}
|
||||
compact={compact}
|
||||
product={{
|
||||
type: 'yearly',
|
||||
data: offers?.yearly,
|
||||
info: 'Pay yearly'
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
|
||||
<Button
|
||||
height={35}
|
||||
@@ -258,7 +275,7 @@ export const PricingPlans = ({promo, marginTop}) => {
|
||||
<>
|
||||
<PricingItem
|
||||
product={product}
|
||||
onPress={() => buySubscription(product)}
|
||||
onPress={() => buySubscription(product.data)}
|
||||
/>
|
||||
<Button
|
||||
onPress={() => {
|
||||
@@ -318,20 +335,12 @@ export const PricingPlans = ({promo, marginTop}) => {
|
||||
marginTop: 10,
|
||||
textAlign: 'center'
|
||||
}}>
|
||||
By tapping Subscribe,
|
||||
<Paragraph size={SIZE.xs + 1} color={colors.accent}>
|
||||
{product?.data?.localizedPrice}
|
||||
</Paragraph>{' '}
|
||||
will be charged to your iTunes Account for 1-
|
||||
{product?.type === 'yearly' ? 'year' : 'month'} subscription of
|
||||
Notesnook Pro.{'\n\n'}
|
||||
Subscriptions will automatically renew unless cancelled within
|
||||
24-hours before the end of the current period. You can cancel
|
||||
anytime with your iTunes Account settings.
|
||||
By subscribing, you will be charged to your iTunes Account for the
|
||||
selected plan. Subscriptions will automatically renew unless
|
||||
cancelled within 24-hours before the end of the current period.
|
||||
</Paragraph>
|
||||
) : (
|
||||
<Paragraph
|
||||
textBreakStrategy="balanced"
|
||||
size={SIZE.xs + 1}
|
||||
color={colors.icon}
|
||||
style={{
|
||||
@@ -339,22 +348,15 @@ export const PricingPlans = ({promo, marginTop}) => {
|
||||
marginTop: 10,
|
||||
textAlign: 'center'
|
||||
}}>
|
||||
By tapping Subscribe, your payment will be charged on your Google
|
||||
Account, and your subscription will automatically renew for the
|
||||
same package length at the same price until you cancel in settings
|
||||
in the Android Play Store prior to the end of the then current
|
||||
period.
|
||||
By subscribing, your will be charged on your Google Account, and
|
||||
your subscription will automatically renew until you cancel prior
|
||||
to the end of the then current period.
|
||||
</Paragraph>
|
||||
)}
|
||||
|
||||
<View
|
||||
style={{
|
||||
backgroundColor: colors.nav,
|
||||
width: '100%',
|
||||
paddingVertical: 10,
|
||||
marginTop: 5,
|
||||
borderRadius: 5,
|
||||
paddingHorizontal: 12
|
||||
}}>
|
||||
<Paragraph
|
||||
size={SIZE.xs + 1}
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
import {CHECK_IDS} from 'notes-core/common';
|
||||
import React from 'react';
|
||||
import * as RNIap from 'react-native-iap';
|
||||
import InAppBrowser from 'react-native-inappbrowser-reborn';
|
||||
import DialogHeader from '../components/Dialog/dialog-header';
|
||||
import {CompactFeatures} from '../components/Premium/compact-features';
|
||||
import {PricingPlans} from '../components/Premium/pricing-plans';
|
||||
import Seperator from '../components/Seperator';
|
||||
import {useMessageStore, useUserStore} from '../provider/stores';
|
||||
import {itemSkus, SUBSCRIPTION_STATUS} from '../utils';
|
||||
import {db} from '../utils/database';
|
||||
import {
|
||||
eOpenPremiumDialog,
|
||||
eOpenProgressDialog,
|
||||
eOpenTrialEndingDialog,
|
||||
eShowGetPremium
|
||||
} from '../utils/Events';
|
||||
@@ -302,6 +305,56 @@ async function getRemainingTrialDaysStatus() {
|
||||
}
|
||||
}
|
||||
|
||||
const features_list = [
|
||||
{
|
||||
content: 'Unlock unlimited notebooks, tags, colors. Organize like a pro'
|
||||
},
|
||||
{
|
||||
content: 'Attach files upto 500MB, upload 4K images with unlimited storage'
|
||||
},
|
||||
{
|
||||
content: 'Instantly sync to unlimited devices'
|
||||
},
|
||||
{
|
||||
content: 'A private vault to keep everything imporant always locked'
|
||||
},
|
||||
{
|
||||
content:
|
||||
'Rich note editing experience with markdown, tables, checklists and more'
|
||||
},
|
||||
{
|
||||
content: 'Export your notes in Pdf, markdown and html formats'
|
||||
}
|
||||
];
|
||||
|
||||
const sheet = (context, promo) => {
|
||||
presentSheet({
|
||||
context:context,
|
||||
component: ref => (
|
||||
<>
|
||||
<DialogHeader
|
||||
centered
|
||||
title="Upgrade to Notesnook"
|
||||
titlePart="Pro"
|
||||
paragraph="Manage your work on another level, enjoy seemless sync and keep all notes in one place."
|
||||
padding={12}
|
||||
/>
|
||||
<Seperator />
|
||||
<CompactFeatures
|
||||
scrollRef={ref}
|
||||
maxHeight={300}
|
||||
features={features_list}
|
||||
vertical
|
||||
/>
|
||||
<Seperator half />
|
||||
<PricingPlans compact heading={false} promo={promo} />
|
||||
</>
|
||||
),
|
||||
noIcon: true,
|
||||
noProgress: true
|
||||
});
|
||||
};
|
||||
|
||||
export default {
|
||||
verify,
|
||||
setPremiumStatus,
|
||||
@@ -312,5 +365,6 @@ export default {
|
||||
getUser,
|
||||
subscriptions,
|
||||
getMontlySub,
|
||||
getRemainingTrialDaysStatus
|
||||
getRemainingTrialDaysStatus,
|
||||
sheet
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user