diff --git a/web/apps/photos/src/components/Sidebar/userDetailsSection.tsx b/web/apps/photos/src/components/Sidebar/userDetailsSection.tsx index d2cf556fa..4d1bf3cb1 100644 --- a/web/apps/photos/src/components/Sidebar/userDetailsSection.tsx +++ b/web/apps/photos/src/components/Sidebar/userDetailsSection.tsx @@ -4,8 +4,10 @@ import { Box, Skeleton } from "@mui/material"; import Typography from "@mui/material/Typography"; import { GalleryContext } from "pages/gallery"; import { useContext, useEffect, useMemo, useState } from "react"; +import billingService from "services/billingService"; import { getUserDetailsV2 } from "services/userService"; import { UserDetails } from "types/user"; +import { hasStripeSubscription, isSubscriptionPastDue } from "utils/billing"; import { isFamilyAdmin, isPartOfFamily } from "utils/user/family"; import { MemberSubscriptionManage } from "../MemberSubscriptionManage"; import SubscriptionCard from "./SubscriptionCard"; @@ -50,9 +52,20 @@ export default function UserDetailsSection({ sidebarView }) { [userDetails], ); - const handleSubscriptionCardClick = isMemberSubscription - ? openMemberSubscriptionManage - : galleryContext.showPlanSelectorModal; + const handleSubscriptionCardClick = () => { + if (isMemberSubscription) { + openMemberSubscriptionManage(); + } else { + if ( + hasStripeSubscription(userDetails.subscription) && + isSubscriptionPastDue(userDetails.subscription) + ) { + billingService.redirectToCustomerPortal(); + } else { + galleryContext.showPlanSelectorModal(); + } + } + }; return ( <> diff --git a/web/apps/photos/src/utils/billing/index.ts b/web/apps/photos/src/utils/billing/index.ts index 5b8ee5dd0..8d18a823f 100644 --- a/web/apps/photos/src/utils/billing/index.ts +++ b/web/apps/photos/src/utils/billing/index.ts @@ -17,6 +17,7 @@ const PAYMENT_PROVIDER_STRIPE = "stripe"; const PAYMENT_PROVIDER_APPSTORE = "appstore"; const PAYMENT_PROVIDER_PLAYSTORE = "playstore"; const FREE_PLAN = "free"; +const THIRTY_DAYS_IN_MICROSECONDS = 30 * 24 * 60 * 60 * 1000 * 1000; enum FAILURE_REASON { AUTHENTICATION_FAILED = "authentication_failed", @@ -151,6 +152,14 @@ export function hasExceededStorageQuota(userDetails: UserDetails) { } } +export function isSubscriptionPastDue(subscription: Subscription) { + const currentTime = Date.now() * 1000; + return ( + subscription.expiryTime < currentTime && + subscription.expiryTime > currentTime - THIRTY_DAYS_IN_MICROSECONDS + ); +} + export function isPopularPlan(plan: Plan) { return plan.storage === 100 * ONE_GB; }