|
@@ -17,7 +17,9 @@ import {
|
|
|
encryptToB64,
|
|
|
generateEncryptionKey,
|
|
|
} from "@ente/shared/crypto/internal/libsodium";
|
|
|
+import { useLocalState } from "@ente/shared/hooks/useLocalState";
|
|
|
import { getAccountsURL } from "@ente/shared/network/api";
|
|
|
+import { LS_KEYS, getData, setData } from "@ente/shared/storage/localStorage";
|
|
|
import { THEME_COLOR } from "@ente/shared/themes/constants";
|
|
|
import { downloadAsFile } from "@ente/shared/utils";
|
|
|
import ArchiveOutlined from "@mui/icons-material/ArchiveOutlined";
|
|
@@ -25,7 +27,7 @@ import CategoryIcon from "@mui/icons-material/Category";
|
|
|
import DeleteOutline from "@mui/icons-material/DeleteOutline";
|
|
|
import LockOutlined from "@mui/icons-material/LockOutlined";
|
|
|
import VisibilityOff from "@mui/icons-material/VisibilityOff";
|
|
|
-import { Divider, Stack } from "@mui/material";
|
|
|
+import { Box, Divider, Skeleton, Stack } from "@mui/material";
|
|
|
import Typography from "@mui/material/Typography";
|
|
|
import DeleteAccountModal from "components/DeleteAccountModal";
|
|
|
import { EnteMenuItem } from "components/Menu/EnteMenuItem";
|
|
@@ -42,20 +44,26 @@ import isElectron from "is-electron";
|
|
|
import { useRouter } from "next/router";
|
|
|
import { AppContext } from "pages/_app";
|
|
|
import { GalleryContext } from "pages/gallery";
|
|
|
-import { useContext, useEffect, useState } from "react";
|
|
|
+import { useContext, useEffect, useMemo, useState } from "react";
|
|
|
import { Trans } from "react-i18next";
|
|
|
+import billingService from "services/billingService";
|
|
|
import { getUncategorizedCollection } from "services/collectionService";
|
|
|
import exportService from "services/export";
|
|
|
-import { getAccountsToken } from "services/userService";
|
|
|
+import { getAccountsToken, getUserDetailsV2 } from "services/userService";
|
|
|
import { CollectionSummaries } from "types/collection";
|
|
|
+import { UserDetails } from "types/user";
|
|
|
+import { hasStripeSubscription, isSubscriptionPastDue } from "utils/billing";
|
|
|
import { openLink } from "utils/common";
|
|
|
import { getDownloadAppMessage } from "utils/ui";
|
|
|
import { isInternalUser } from "utils/user";
|
|
|
+import { isFamilyAdmin, isPartOfFamily } from "utils/user/family";
|
|
|
import { testUpload } from "../../../tests/upload.test";
|
|
|
+import { MemberSubscriptionManage } from "../MemberSubscriptionManage";
|
|
|
import HeaderSection from "./Header";
|
|
|
import Preferences from "./Preferences";
|
|
|
+import SubscriptionCard from "./SubscriptionCard";
|
|
|
+import SubscriptionStatus from "./SubscriptionStatus";
|
|
|
import { DrawerSidebar } from "./styledComponents";
|
|
|
-import UserDetailsSection from "./userDetailsSection";
|
|
|
|
|
|
interface Iprops {
|
|
|
collectionSummaries: CollectionSummaries;
|
|
@@ -89,6 +97,94 @@ export default function Sidebar({
|
|
|
);
|
|
|
}
|
|
|
|
|
|
+interface UserDetailsSectionProps {
|
|
|
+ sidebarView: boolean;
|
|
|
+}
|
|
|
+
|
|
|
+const UserDetailsSection: React.FC<UserDetailsSectionProps> = ({
|
|
|
+ sidebarView,
|
|
|
+}) => {
|
|
|
+ const galleryContext = useContext(GalleryContext);
|
|
|
+
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+ const main = async () => {
|
|
|
+ const userDetails = await getUserDetailsV2();
|
|
|
+ setUserDetails(userDetails);
|
|
|
+ setData(LS_KEYS.SUBSCRIPTION, userDetails.subscription);
|
|
|
+ setData(LS_KEYS.FAMILY_DATA, userDetails.familyData);
|
|
|
+ setData(LS_KEYS.USER, {
|
|
|
+ ...getData(LS_KEYS.USER),
|
|
|
+ email: userDetails.email,
|
|
|
+ });
|
|
|
+ };
|
|
|
+ main();
|
|
|
+ }, [sidebarView]);
|
|
|
+
|
|
|
+ const isMemberSubscription = useMemo(
|
|
|
+ () =>
|
|
|
+ userDetails &&
|
|
|
+ isPartOfFamily(userDetails.familyData) &&
|
|
|
+ !isFamilyAdmin(userDetails.familyData),
|
|
|
+ [userDetails],
|
|
|
+ );
|
|
|
+
|
|
|
+ const handleSubscriptionCardClick = () => {
|
|
|
+ if (isMemberSubscription) {
|
|
|
+ openMemberSubscriptionManage();
|
|
|
+ } else {
|
|
|
+ if (
|
|
|
+ hasStripeSubscription(userDetails.subscription) &&
|
|
|
+ isSubscriptionPastDue(userDetails.subscription)
|
|
|
+ ) {
|
|
|
+ billingService.redirectToCustomerPortal();
|
|
|
+ } else {
|
|
|
+ galleryContext.showPlanSelectorModal();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ return (
|
|
|
+ <>
|
|
|
+ <Box px={0.5} mt={2} pb={1.5} mb={1}>
|
|
|
+ <Typography px={1} pb={1} color="text.muted">
|
|
|
+ {userDetails ? (
|
|
|
+ userDetails.email
|
|
|
+ ) : (
|
|
|
+ <Skeleton animation="wave" />
|
|
|
+ )}
|
|
|
+ </Typography>
|
|
|
+
|
|
|
+ <SubscriptionCard
|
|
|
+ userDetails={userDetails}
|
|
|
+ onClick={handleSubscriptionCardClick}
|
|
|
+ />
|
|
|
+ <SubscriptionStatus userDetails={userDetails} />
|
|
|
+ </Box>
|
|
|
+ {isMemberSubscription && (
|
|
|
+ <MemberSubscriptionManage
|
|
|
+ userDetails={userDetails}
|
|
|
+ open={memberSubscriptionManageView}
|
|
|
+ onClose={closeMemberSubscriptionManage}
|
|
|
+ />
|
|
|
+ )}
|
|
|
+ </>
|
|
|
+ );
|
|
|
+};
|
|
|
+
|
|
|
interface ShortcutSectionProps {
|
|
|
closeSidebar: () => void;
|
|
|
collectionSummaries: CollectionSummaries;
|