Merge pull request #608 from ente-io/family-member-screen

Family member screen
This commit is contained in:
Abhinav Kumar 2022-06-22 10:04:21 +05:30 committed by GitHub
commit ae3f64745d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 170 additions and 85 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 408 KiB

View file

@ -0,0 +1,73 @@
import { Button, DialogContent, Typography } from '@mui/material';
import VerticallyCentered from 'components/Container';
import DialogBoxBase from 'components/DialogBox/base';
import DialogTitleWithCloseButton from 'components/DialogBox/titleWithCloseButton';
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 MemberSubscriptionManage({ open, userDetails, onClose }) {
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,
},
});
if (!userDetails) {
return <></>;
}
return (
<DialogBoxBase open={open} onClose={onClose} maxWidth="xs">
<DialogTitleWithCloseButton onClose={onClose}>
<Typography variant="h3">{constants.SUBSCRIPTION}</Typography>
<Typography color={'text.secondary'}>
{constants.FAMILY_PLAN}
</Typography>
</DialogTitleWithCloseButton>
<DialogContent>
<VerticallyCentered>
<Typography color="text.secondary ">
{constants.FAMILY_SUBSCRIPTION_INFO(
getFamilyPlanAdmin(userDetails.familyData)?.email
)}
</Typography>
<img
height="267px"
width="256px"
src="/images/family_plan_leave@3x.png"
/>
<Button
size="large"
variant="outlined"
color="danger"
onClick={confirmLeaveFamily}>
{constants.LEAVE_FAMILY}
</Button>
</VerticallyCentered>
</DialogContent>
</DialogBoxBase>
);
}

View file

@ -12,10 +12,13 @@ import {
import { SubscriptionCardContentOverlay } from './contentOverlay';
interface Iprops {
userDetails: UserDetails;
closeSidebar: () => void;
openMemberSubscriptionDialog: () => void;
}
export default function SubscriptionCard({ userDetails }: Iprops) {
export default function SubscriptionCard({
userDetails,
openMemberSubscriptionDialog,
}: Iprops) {
const { showPlanSelectorModal } = useContext(GalleryContext);
if (!userDetails) {
@ -30,9 +33,9 @@ export default function SubscriptionCard({ userDetails }: Iprops) {
);
}
const allowClick =
!isPartOfFamily(userDetails.familyData) ||
isFamilyAdmin(userDetails.familyData);
const isMemberSubscription =
isPartOfFamily(userDetails.familyData) &&
!isFamilyAdmin(userDetails.familyData);
return (
<Box position="relative">
@ -43,7 +46,13 @@ export default function SubscriptionCard({ userDetails }: Iprops) {
}}
src="/images/subscription-card-background.png"
/>
{allowClick && <ClickOverlay onClick={showPlanSelectorModal} />}
<ClickOverlay
onClick={
isMemberSubscription
? openMemberSubscriptionDialog
: showPlanSelectorModal
}
/>
<SubscriptionCardContentOverlay
hasNonAdminFamilyMembers={hasNonAdminFamilyMembers}
userDetails={userDetails}

View file

@ -15,7 +15,8 @@ export function AdminSubscriptionStatus({
<Typography
variant="body2"
color={'text.secondary'}
onClick={showPlanSelectorModal}>
onClick={showPlanSelectorModal}
sx={{ cursor: 'pointer' }}>
{isSubscriptionActive(userDetails.subscription)
? isOnFreePlan(userDetails.subscription)
? constants.FREE_SUBSCRIPTION_INFO(

View file

@ -1,9 +1,8 @@
import { MemberSubscriptionStatus } from './member';
import { AdminSubscriptionStatus as AdminSubscriptionStatus } from './admin';
import { GalleryContext } from 'pages/gallery';
import React, { useContext, useMemo } from 'react';
import {
hasNonAdminFamilyMembers,
hasPaidSubscription,
isFamilyAdmin,
isOnFreePlan,
isSubscriptionActive,
@ -11,6 +10,8 @@ import {
} from 'utils/billing';
import Box from '@mui/material/Box';
import { UserDetails } from 'types/user';
import constants from 'utils/strings/constants';
import { Typography } from '@mui/material';
export default function SubscriptionStatus({
userDetails,
@ -34,14 +35,29 @@ export default function SubscriptionStatus({
return (
<Box px={1}>
{!hasNonAdminFamilyMembers(userDetails.familyData) ||
isFamilyAdmin(userDetails.familyData) ? (
<AdminSubscriptionStatus
userDetails={userDetails}
showPlanSelectorModal={showPlanSelectorModal}
/>
) : (
<MemberSubscriptionStatus userDetails={userDetails} />
{(!hasNonAdminFamilyMembers(userDetails.familyData) ||
isFamilyAdmin(userDetails.familyData) ||
hasPaidSubscription(userDetails.subscription)) && (
<Typography
variant="body2"
color={'text.secondary'}
onClick={showPlanSelectorModal}
sx={{ cursor: 'pointer' }}>
{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>
)}
</Box>
);

View file

@ -1,46 +0,0 @@
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>
);
}

View file

@ -24,10 +24,7 @@ export default function Sidebar({
<DrawerSidebar open={sidebarView} onClose={closeSidebar}>
<HeaderSection closeSidebar={closeSidebar} />
<PaddedDivider spaced />
<UserDetailsSection
sidebarView={sidebarView}
closeSidebar={closeSidebar}
/>
<UserDetailsSection sidebarView={sidebarView} />
<PaddedDivider invisible />
<ShortcutSection
closeSidebar={closeSidebar}

View file

@ -1,4 +1,4 @@
import React, { useEffect } from 'react';
import React, { useEffect, useState } from 'react';
import SubscriptionCard from './SubscriptionCard';
import { getUserDetailsV2 } from 'services/userService';
import { UserDetails } from 'types/user';
@ -8,12 +8,21 @@ import Typography from '@mui/material/Typography';
import SubscriptionStatus from './SubscriptionStatus';
import Stack from '@mui/material/Stack';
import { Skeleton } from '@mui/material';
import { MemberSubscriptionManage } from '../MemberSubscriptionManage';
export default function UserDetailsSection({ sidebarView, closeSidebar }) {
export default function UserDetailsSection({ sidebarView }) {
const [userDetails, setUserDetails] = useLocalState<UserDetails>(
LS_KEYS.USER_DETAILS
);
const [memberSubscriptionManageView, setMemberSubscriptionManageView] =
useState(false);
const openMemberSubscriptionManage = () =>
setMemberSubscriptionManageView(true);
const closeMemberSubscriptionManage = () =>
setMemberSubscriptionManageView(false);
useEffect(() => {
if (!sidebarView) {
return;
@ -26,6 +35,7 @@ export default function UserDetailsSection({ sidebarView, closeSidebar }) {
}, [sidebarView]);
return (
<>
<Stack spacing={1}>
<Typography px={1} color="text.secondary">
{userDetails ? (
@ -37,9 +47,16 @@ export default function UserDetailsSection({ sidebarView, closeSidebar }) {
<SubscriptionCard
userDetails={userDetails}
closeSidebar={closeSidebar}
openMemberSubscriptionDialog={openMemberSubscriptionManage}
/>
<SubscriptionStatus userDetails={userDetails} />
</Stack>
<MemberSubscriptionManage
userDetails={userDetails}
open={memberSubscriptionManageView}
onClose={closeMemberSubscriptionManage}
/>
</>
);
}

View file

@ -84,7 +84,6 @@ const darkThemeOptions = createTheme({
},
styleOverrides: {
root: {
textTransform: 'none',
padding: '12px 16px',
borderRadius: '4px',
},
@ -171,9 +170,27 @@ const darkThemeOptions = createTheme({
display: 'block',
},
caption: {
display: 'block',
fontSize: '12px',
lineHeight: '15px',
},
h1: {
fontSize: '36px',
lineHeight: '44px',
},
h2: {
fontSize: '30px',
lineHeight: '36px',
},
h3: {
fontSize: '24px',
lineHeight: '29px',
},
h4: {
fontSize: '18px',
lineHeight: '22px',
},
fontFamily: ['Inter', 'sans-serif'].join(','),
},
});

View file

@ -252,6 +252,7 @@ const englishConstants = {
// ========================
// Subscription
// ========================
SUBSCRIPTION: 'Subscription',
SUBSCRIBE: 'Subscribe',
SUBSCRIPTION_PLAN: 'Subscription plan',
USAGE_DETAILS: 'Usage',
@ -273,10 +274,9 @@ const englishConstants = {
</>
),
FAMILY_PLAN_MANAGE_ADMIN_ONLY: (adminEmail) => (
FAMILY_SUBSCRIPTION_INFO: (adminEmail) => (
<>
Only your family plan admin <strong>{adminEmail}</strong> can change
the plan
You are on a family plan managed by <strong>{adminEmail}</strong>
</>
),
RENEWAL_ACTIVE_SUBSCRIPTION_INFO: (expiryTime) => (
@ -777,6 +777,7 @@ const englishConstants = {
OF: 'of',
MONTH_SHORT: 'mo',
YEAR_SHORT: 'yr',
FAMILY_PLAN: 'Family plan',
};
export default englishConstants;