add subscription component
This commit is contained in:
parent
9e01516f5d
commit
03228664f6
|
@ -1,14 +1,13 @@
|
|||
import { ClickIndicator } from './clickIndicator';
|
||||
import { IndividualUsageSection } from './individualUsageSection';
|
||||
import React, { useContext } from 'react';
|
||||
import { Box, CircularProgress } from '@mui/material';
|
||||
import Container from 'components/Container';
|
||||
import React, { useContext, useMemo } from 'react';
|
||||
import { Box } from '@mui/material';
|
||||
import { UserDetails } from 'types/user';
|
||||
|
||||
import StorageSection from './storageSection';
|
||||
import { GalleryContext } from 'pages/gallery';
|
||||
import { FamilyUsageSection } from './familyUsageSection';
|
||||
import { hasNonAdminFamilyMembers } from 'utils/billing';
|
||||
import { hasNonAdminFamilyMembers, isPartOfFamily } from 'utils/billing';
|
||||
interface Iprops {
|
||||
userDetails: UserDetails;
|
||||
closeSidebar: () => void;
|
||||
|
@ -17,6 +16,29 @@ interface Iprops {
|
|||
export default function SubscriptionCard({ userDetails }: Iprops) {
|
||||
const { showPlanSelectorModal } = useContext(GalleryContext);
|
||||
|
||||
if (!userDetails) {
|
||||
return <></>;
|
||||
}
|
||||
|
||||
const totalUsage = useMemo(() => {
|
||||
if (isPartOfFamily(userDetails.familyData)) {
|
||||
return userDetails.familyData.members.reduce(
|
||||
(sum, currentMember) => sum + currentMember.usage,
|
||||
0
|
||||
);
|
||||
} else {
|
||||
return userDetails.usage;
|
||||
}
|
||||
}, [userDetails]);
|
||||
|
||||
const totalStorage = useMemo(() => {
|
||||
if (isPartOfFamily(userDetails.familyData)) {
|
||||
return userDetails.familyData.storage;
|
||||
} else {
|
||||
return userDetails.subscription.storage;
|
||||
}
|
||||
}, [userDetails]);
|
||||
|
||||
return (
|
||||
<Box
|
||||
display="flex"
|
||||
|
@ -27,13 +49,11 @@ export default function SubscriptionCard({ userDetails }: Iprops) {
|
|||
style={{ position: 'absolute' }}
|
||||
src="/subscription-card-background.png"
|
||||
/>
|
||||
{!userDetails ? (
|
||||
<Container>
|
||||
<CircularProgress />
|
||||
</Container>
|
||||
) : (
|
||||
<Box zIndex={1} position={'relative'} height={148}>
|
||||
<StorageSection userDetails={userDetails} />
|
||||
<StorageSection
|
||||
totalStorage={totalStorage}
|
||||
totalUsage={totalUsage}
|
||||
/>
|
||||
{hasNonAdminFamilyMembers(userDetails.familyData) ? (
|
||||
<FamilyUsageSection userDetails={userDetails} />
|
||||
) : (
|
||||
|
@ -41,7 +61,6 @@ export default function SubscriptionCard({ userDetails }: Iprops) {
|
|||
)}
|
||||
<ClickIndicator />
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -3,7 +3,11 @@ import React from 'react';
|
|||
import { convertBytesToHumanReadable } from 'utils/billing';
|
||||
import constants from 'utils/strings/constants';
|
||||
|
||||
export default function StorageSection({ userDetails }) {
|
||||
interface Iprops {
|
||||
totalUsage: number;
|
||||
totalStorage: number;
|
||||
}
|
||||
export default function StorageSection({ totalUsage, totalStorage }: Iprops) {
|
||||
return (
|
||||
<Box padding={2}>
|
||||
<Typography variant="body2" color={'text.secondary'}>
|
||||
|
@ -16,12 +20,12 @@ export default function StorageSection({ userDetails }) {
|
|||
fontSize: '24px',
|
||||
}}>
|
||||
{`${convertBytesToHumanReadable(
|
||||
userDetails.usage,
|
||||
totalStorage - totalUsage,
|
||||
1
|
||||
)} of ${convertBytesToHumanReadable(
|
||||
userDetails.subscription.storage,
|
||||
)} ${constants.OF} ${convertBytesToHumanReadable(
|
||||
totalStorage,
|
||||
0
|
||||
)}`}
|
||||
)} ${constants.FREE}`}
|
||||
</Typography>
|
||||
</Box>
|
||||
);
|
||||
|
|
|
@ -1,86 +0,0 @@
|
|||
import React from 'react';
|
||||
|
||||
export default function SubscriptionStatus() {
|
||||
return <div>SubscriptionStatus</div>;
|
||||
|
||||
{
|
||||
// const { setDialogMessage } = useContext(AppContext);
|
||||
// async function onLeaveFamilyClick() {
|
||||
// try {
|
||||
// await billingService.leaveFamily();
|
||||
// closeSidebar();
|
||||
// } catch (e) {
|
||||
// setDialogMessage({
|
||||
// title: constants.ERROR,
|
||||
// close: { variant: 'danger' },
|
||||
// content: constants.UNKNOWN_ERROR,
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
/* {!hasNonAdminFamilyMembers(userDetails.familyData) ||
|
||||
isFamilyAdmin(userDetails.familyData) ? (
|
||||
<div style={{ color: '#959595' }}>
|
||||
{isSubscriptionActive(userDetails.subscription) ? (
|
||||
isOnFreePlan(userDetails.subscription) ? (
|
||||
constants.FREE_SUBSCRIPTION_INFO(
|
||||
userDetails.subscription?.expiryTime
|
||||
)
|
||||
) : isSubscriptionCancelled(
|
||||
userDetails.subscription
|
||||
) ? (
|
||||
constants.RENEWAL_CANCELLED_SUBSCRIPTION_INFO(
|
||||
userDetails.subscription?.expiryTime
|
||||
)
|
||||
) : (
|
||||
constants.RENEWAL_ACTIVE_SUBSCRIPTION_INFO(
|
||||
userDetails.subscription?.expiryTime
|
||||
)
|
||||
)
|
||||
) : (
|
||||
<p>{constants.SUBSCRIPTION_EXPIRED(onManageClick)}</p>
|
||||
)}
|
||||
<Button onClick={onManageClick}>
|
||||
{isSubscribed(userDetails.subscription)
|
||||
? constants.MANAGE
|
||||
: constants.SUBSCRIBE}
|
||||
</Button>
|
||||
</div>
|
||||
) : (
|
||||
<div style={{ color: '#959595' }}>
|
||||
{constants.FAMILY_PLAN_MANAGE_ADMIN_ONLY(
|
||||
getFamilyPlanAdmin(userDetails.familyData)?.email
|
||||
)}
|
||||
<Button
|
||||
onClick={() =>
|
||||
setDialogMessage({
|
||||
title: `${constants.LEAVE_FAMILY}`,
|
||||
content: constants.LEAVE_FAMILY_CONFIRM,
|
||||
staticBackdrop: true,
|
||||
proceed: {
|
||||
text: constants.LEAVE_FAMILY,
|
||||
action: onLeaveFamilyClick,
|
||||
variant: 'danger',
|
||||
},
|
||||
close: { text: constants.CANCEL },
|
||||
})
|
||||
}>
|
||||
{constants.LEAVE_FAMILY}
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{hasNonAdminFamilyMembers(userDetails.familyData)
|
||||
? constants.FAMILY_USAGE_INFO(
|
||||
userDetails.usage,
|
||||
convertBytesToHumanReadable(
|
||||
getStorage(userDetails.familyData)
|
||||
)
|
||||
)
|
||||
: constants.USAGE_INFO(
|
||||
userDetails.usage,
|
||||
convertBytesToHumanReadable(
|
||||
userDetails.subscription?.storage
|
||||
)
|
||||
)} */
|
||||
}
|
||||
}
|
31
src/components/Sidebar/SubscriptionStatus/admin.tsx
Normal file
31
src/components/Sidebar/SubscriptionStatus/admin.tsx
Normal file
|
@ -0,0 +1,31 @@
|
|||
import { Typography } from '@mui/material';
|
||||
import React from 'react';
|
||||
import {
|
||||
isSubscriptionActive,
|
||||
isOnFreePlan,
|
||||
isSubscriptionCancelled,
|
||||
} from 'utils/billing';
|
||||
import constants from 'utils/strings/constants';
|
||||
|
||||
export function AdminSubscriptionStatus({
|
||||
userDetails,
|
||||
showPlanSelectorModal,
|
||||
}) {
|
||||
return (
|
||||
<Typography
|
||||
variant="body2"
|
||||
color={'text.secondary'}
|
||||
onClick={showPlanSelectorModal}>
|
||||
{isSubscriptionActive(userDetails.subscription)
|
||||
? isOnFreePlan(userDetails.subscription)
|
||||
? constants.FREE_SUBSCRIPTION_INFO(
|
||||
userDetails.subscription?.expiryTime
|
||||
)
|
||||
: isSubscriptionCancelled(userDetails.subscription) &&
|
||||
constants.RENEWAL_CANCELLED_SUBSCRIPTION_INFO(
|
||||
userDetails.subscription?.expiryTime
|
||||
)
|
||||
: constants.SUBSCRIPTION_EXPIRED_MESSAGE(showPlanSelectorModal)}
|
||||
</Typography>
|
||||
);
|
||||
}
|
27
src/components/Sidebar/SubscriptionStatus/index.tsx
Normal file
27
src/components/Sidebar/SubscriptionStatus/index.tsx
Normal file
|
@ -0,0 +1,27 @@
|
|||
import { MemberSubscriptionStatus } from './member';
|
||||
import { AdminSubscriptionStatus as AdminSubscriptionStatus } from './admin';
|
||||
import { GalleryContext } from 'pages/gallery';
|
||||
import React, { useContext } from 'react';
|
||||
import { hasNonAdminFamilyMembers, isFamilyAdmin } from 'utils/billing';
|
||||
import Box from '@mui/material/Box';
|
||||
|
||||
export default function SubscriptionStatus({ userDetails }) {
|
||||
const { showPlanSelectorModal } = useContext(GalleryContext);
|
||||
|
||||
if (!userDetails) {
|
||||
return <></>;
|
||||
}
|
||||
return (
|
||||
<Box px={1}>
|
||||
{!hasNonAdminFamilyMembers(userDetails.familyData) ||
|
||||
isFamilyAdmin(userDetails.familyData) ? (
|
||||
<AdminSubscriptionStatus
|
||||
userDetails={userDetails}
|
||||
showPlanSelectorModal={showPlanSelectorModal}
|
||||
/>
|
||||
) : (
|
||||
<MemberSubscriptionStatus userDetails={userDetails} />
|
||||
)}
|
||||
</Box>
|
||||
);
|
||||
}
|
46
src/components/Sidebar/SubscriptionStatus/member.tsx
Normal file
46
src/components/Sidebar/SubscriptionStatus/member.tsx
Normal file
|
@ -0,0 +1,46 @@
|
|||
import { Button, Stack, Typography } from '@mui/material';
|
||||
import { AppContext } from 'pages/_app';
|
||||
import React, { useContext } from 'react';
|
||||
import billingService from 'services/billingService';
|
||||
import { getFamilyPlanAdmin } from 'utils/billing';
|
||||
import constants from 'utils/strings/constants';
|
||||
export function MemberSubscriptionStatus({ userDetails }) {
|
||||
const { setDialogMessage } = useContext(AppContext);
|
||||
|
||||
async function onLeaveFamilyClick() {
|
||||
try {
|
||||
await billingService.leaveFamily();
|
||||
} catch (e) {
|
||||
setDialogMessage({
|
||||
title: constants.ERROR,
|
||||
close: { variant: 'danger' },
|
||||
content: constants.UNKNOWN_ERROR,
|
||||
});
|
||||
}
|
||||
}
|
||||
const confirmLeaveFamily = () =>
|
||||
setDialogMessage({
|
||||
title: `${constants.LEAVE_FAMILY}`,
|
||||
content: constants.LEAVE_FAMILY_CONFIRM,
|
||||
proceed: {
|
||||
text: constants.LEAVE_FAMILY,
|
||||
action: onLeaveFamilyClick,
|
||||
variant: 'danger',
|
||||
},
|
||||
close: {
|
||||
text: constants.CANCEL,
|
||||
},
|
||||
});
|
||||
return (
|
||||
<Stack spacing={1}>
|
||||
<Typography variant="body2" color="text.secondary ">
|
||||
{constants.FAMILY_PLAN_MANAGE_ADMIN_ONLY(
|
||||
getFamilyPlanAdmin(userDetails.familyData)?.email
|
||||
)}
|
||||
</Typography>
|
||||
<Button onClick={confirmLeaveFamily}>
|
||||
{constants.LEAVE_FAMILY}
|
||||
</Button>
|
||||
</Stack>
|
||||
);
|
||||
}
|
|
@ -1,20 +1,17 @@
|
|||
import React, { useEffect } from 'react';
|
||||
import { SpaceBetweenFlex } from 'components/Container';
|
||||
import { PaddedDivider } from './styledComponents';
|
||||
import SubscriptionCard from './SubscriptionCard';
|
||||
import { getUserDetailsV2 } from 'services/userService';
|
||||
import { UserDetails } from 'types/user';
|
||||
import { LS_KEYS } from 'utils/storage/localStorage';
|
||||
import { useLocalState } from 'hooks/useLocalState';
|
||||
import { THEMES } from 'types/theme';
|
||||
import ThemeSwitcher from './ThemeSwitcher';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import SubscriptionStatus from './SubscriptionStatus';
|
||||
import Stack from '@mui/material/Stack';
|
||||
|
||||
export default function UserDetailsSection({ sidebarView, closeSidebar }) {
|
||||
const [userDetails, setUserDetails] = useLocalState<UserDetails>(
|
||||
LS_KEYS.USER_DETAILS
|
||||
);
|
||||
const [theme, setTheme] = useLocalState<THEMES>(LS_KEYS.THEME, THEMES.DARK);
|
||||
|
||||
useEffect(() => {
|
||||
if (!sidebarView) {
|
||||
|
@ -28,16 +25,13 @@ export default function UserDetailsSection({ sidebarView, closeSidebar }) {
|
|||
}, [sidebarView]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<SpaceBetweenFlex px={1}>
|
||||
<Stack spacing={1}>
|
||||
<Typography>{userDetails?.email}</Typography>
|
||||
<ThemeSwitcher theme={theme} setTheme={setTheme} />
|
||||
</SpaceBetweenFlex>
|
||||
<PaddedDivider invisible />
|
||||
<SubscriptionCard
|
||||
userDetails={userDetails}
|
||||
closeSidebar={closeSidebar}
|
||||
/>
|
||||
</>
|
||||
<SubscriptionStatus userDetails={userDetails} />
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { Box, Typography } from '@mui/material';
|
||||
import Link from '@mui/material/Link';
|
||||
import LinkButton from 'components/pages/gallery/LinkButton';
|
||||
import { DotSeparator } from 'components/Sidebar/styledComponents';
|
||||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
|
@ -126,6 +127,12 @@ const englishConstants = {
|
|||
UPLOADING_FILES: 'File upload',
|
||||
FILE_NOT_UPLOADED_LIST: 'The following files were not uploaded',
|
||||
SUBSCRIPTION_EXPIRED: 'Subscription expired',
|
||||
SUBSCRIPTION_EXPIRED_MESSAGE: (onClick) => (
|
||||
<>
|
||||
Your subscription has expired, please{' '}
|
||||
<LinkButton onClick={onClick}> renew </LinkButton>
|
||||
</>
|
||||
),
|
||||
STORAGE_QUOTA_EXCEEDED: 'Storage limit exceeded',
|
||||
INITIAL_LOAD_DELAY_WARNING: 'First load may take some time',
|
||||
USER_DOES_NOT_EXIST: 'Sorry, could not find a user with that email',
|
||||
|
@ -274,10 +281,8 @@ const englishConstants = {
|
|||
|
||||
FAMILY_PLAN_MANAGE_ADMIN_ONLY: (adminEmail) => (
|
||||
<>
|
||||
<p>
|
||||
Only your family plan admin <strong>{adminEmail}</strong> can
|
||||
change the plan
|
||||
</p>
|
||||
Only your family plan admin <strong>{adminEmail}</strong> can change
|
||||
the plan
|
||||
</>
|
||||
),
|
||||
RENEWAL_ACTIVE_SUBSCRIPTION_INFO: (expiryTime) => (
|
||||
|
@ -777,6 +782,8 @@ const englishConstants = {
|
|||
USED: 'used',
|
||||
YOU: 'You',
|
||||
FAMILY: 'Family',
|
||||
FREE: 'free',
|
||||
OF: 'of',
|
||||
};
|
||||
|
||||
export default englishConstants;
|
||||
|
|
Loading…
Reference in a new issue