1 import type { ReactNode } from 'react';
3 import { c } from 'ttag';
5 import { useSubscription } from '@proton/account/subscription/hooks';
6 import { useUser } from '@proton/account/user/hooks';
7 import SettingsLink from '@proton/components/components/link/SettingsLink';
8 import useConfig from '@proton/components/hooks/useConfig';
9 import type { PLANS } from '@proton/payments';
10 import type { APP_NAMES } from '@proton/shared/lib/constants';
17 } from '@proton/shared/lib/constants';
18 import { addUpsellPath, getUpgradePath, getUpsellRefFromApp } from '@proton/shared/lib/helpers/upsell';
19 import type { Subscription, UserModel } from '@proton/shared/lib/interfaces';
23 getCompleteSpaceDetails,
26 } from '@proton/shared/lib/user/storage';
28 import useLocalState from '../../hooks/useLocalState';
29 import LockedStateTopBanner from './LockedStateTopBanner';
30 import TopBanner from './TopBanner';
32 const IGNORE_STORAGE_LIMIT_KEY = 'ignore-storage-limit';
34 const getStr = (percentage: number, storage: ReactNode, cta: ReactNode) => {
35 if (percentage >= 100) {
36 // Translator: Your Drive storage is full. To upload or sync files, free up space or upgrade for more storage.
37 return c('storage_split: info').jt`Your ${storage} is full. ${cta}.`;
39 // Translator: Your Drive storage is 99% full. To upload or sync files, free up space or upgrade for more storage.
40 return c('storage_split: info').jt`Your ${storage} is ${percentage}% full. ${cta}.`;
43 const getStrFull = (percentage: number, storage: ReactNode, cta: ReactNode) => {
44 if (percentage >= 100) {
45 // Translator: Your storage is full. To upload or sync files, free up space or upgrade for more storage.
46 return c('storage_split: info').jt`Your storage is full. ${cta}.`;
48 // Translator: Your storage is 99% full. To upload or sync files, free up space or upgrade for more storage.
49 return c('storage_split: info').jt`Your storage is ${percentage}% full. ${cta}.`;
56 const getStorageFull = ({
66 subscription: Subscription | undefined;
68 mode: 'mail' | 'drive' | 'both';
70 upsellRef: string | undefined;
73 const upgrade = user.canPay ? (
76 className="color-inherit"
77 path={addUpsellPath(getUpgradePath({ user, plan, subscription }), upsellRef)}
80 // Translator: To upload or sync files, free up space or upgrade for more storage
81 c('storage_split: info').t`upgrade for more storage`
85 // Translator: To upload or sync files, contact your administrator
86 c('storage_split: info').t`contact your administrator`
89 const driveCta = c('storage_split: info').jt`To upload or sync files, free up space or ${upgrade}`;
90 const mailCta = c('storage_split: info').jt`To send or receive emails, free up space or ${upgrade}`;
92 if (mode === 'drive') {
93 return getStr(percentage, getAppStorage(DRIVE_SHORT_APP_NAME), driveCta);
95 if (mode === 'mail') {
96 return getStr(percentage, getAppStorage(MAIL_SHORT_APP_NAME), mailCta);
98 if (mode === 'both') {
99 if (app === APPS.PROTONDRIVE) {
100 return getStrFull(percentage, getAppStorage(DRIVE_SHORT_APP_NAME), driveCta);
102 return getStrFull(percentage, getAppStorage(DRIVE_SHORT_APP_NAME), mailCta);
106 const SplitStorageLimitTopBanner = ({
112 setIgnoreStorageLimit,
117 subscription: Subscription | undefined;
118 upsellRef: string | undefined;
119 ignoreStorageLimit: boolean;
120 setIgnoreStorageLimit: (value: boolean) => void;
121 space: ReturnType<typeof getSpace>;
123 const details = getCompleteSpaceDetails(space);
124 const plan = getPlanToUpsell({ storageDetails: details, app });
126 if (details.base.type === SpaceState.Danger && details.drive.type === SpaceState.Danger) {
128 <TopBanner className="bg-danger">
133 percentage: app === APPS.PROTONDRIVE ? details.drive.displayed : details.base.displayed,
142 if (details.base.type === SpaceState.Danger) {
144 <TopBanner className="bg-danger">
149 percentage: details.base.displayed,
157 if (details.drive.type === SpaceState.Danger && app === APPS.PROTONDRIVE) {
159 <TopBanner className="bg-danger">
164 percentage: details.drive.displayed,
172 if (ignoreStorageLimit) {
176 if (details.drive.type === SpaceState.Warning && details.base.type === SpaceState.Warning) {
178 <TopBanner className="bg-warning" onClose={() => setIgnoreStorageLimit(true)}>
183 percentage: app === APPS.PROTONDRIVE ? details.drive.displayed : details.base.displayed,
184 mode: app === APPS.PROTONDRIVE ? 'drive' : 'mail',
191 if (details.drive.type === SpaceState.Warning && app === APPS.PROTONDRIVE) {
193 <TopBanner className="bg-warning" onClose={() => setIgnoreStorageLimit(true)}>
198 percentage: details.drive.displayed,
206 if (details.base.type === SpaceState.Warning) {
208 <TopBanner className="bg-warning" onClose={() => setIgnoreStorageLimit(true)}>
213 percentage: details.base.displayed,
224 const PooledStorageLimitTopBanner = ({
230 setIgnoreStorageLimit,
235 subscription: Subscription | undefined;
236 upsellRef: string | undefined;
237 ignoreStorageLimit: boolean;
238 setIgnoreStorageLimit: (value: boolean) => void;
239 space: ReturnType<typeof getSpace>;
241 const details = getCompleteSpaceDetails(space);
242 const plan = getPlanToUpsell({ storageDetails: details, app });
244 if (details.pooled.type === SpaceState.Danger) {
246 <TopBanner className="bg-danger">
251 percentage: details.pooled.displayed,
252 mode: app === APPS.PROTONDRIVE ? 'drive' : 'mail',
259 if (ignoreStorageLimit) {
263 if (details.pooled.type === SpaceState.Warning) {
265 <TopBanner className="bg-warning" onClose={() => setIgnoreStorageLimit(true)}>
270 percentage: details.pooled.displayed,
271 mode: app === APPS.PROTONDRIVE ? 'drive' : 'mail',
281 const StorageLimitTopBanner = ({ app }: Props) => {
282 const [user] = useUser();
283 const [subscription] = useSubscription();
284 const { APP_NAME } = useConfig();
285 const [ignoreStorageLimit, setIgnoreStorageLimit] = useLocalState(false, `${IGNORE_STORAGE_LIMIT_KEY}${user.ID}`);
286 const space = getSpace(user);
288 const upsellRef = getUpsellRefFromApp({
290 feature: SHARED_UPSELL_PATHS.STORAGE_PERCENTAGE,
291 component: UPSELL_COMPONENT.MODAL,
295 if (user.LockedFlags) {
297 <LockedStateTopBanner
300 subscription={subscription}
301 upsellRef={upsellRef}
302 lockedFlags={user.LockedFlags}
307 return space.splitStorage ? (
308 <SplitStorageLimitTopBanner
312 subscription={subscription}
313 upsellRef={upsellRef}
314 ignoreStorageLimit={ignoreStorageLimit}
315 setIgnoreStorageLimit={setIgnoreStorageLimit}
318 <PooledStorageLimitTopBanner
321 subscription={subscription}
323 upsellRef={upsellRef}
324 ignoreStorageLimit={ignoreStorageLimit}
325 setIgnoreStorageLimit={setIgnoreStorageLimit}
330 export default StorageLimitTopBanner;