Merge branch 'main' into update-is-sentry-enabled

This commit is contained in:
Abhinav 2023-11-20 19:11:43 +05:30
commit 33a0c77dd4
24 changed files with 309 additions and 183 deletions

View file

@ -157,6 +157,7 @@
"RENEWAL_ACTIVE_SUBSCRIPTION_STATUS": "Erneuert am {{date, dateTime}}",
"RENEWAL_CANCELLED_SUBSCRIPTION_STATUS": "Endet am {{date, dateTime}}",
"RENEWAL_CANCELLED_SUBSCRIPTION_INFO": "Ihr Abo endet am {{date, dateTime}}",
"ADD_ON_AVAILABLE_TILL": "",
"STORAGE_QUOTA_EXCEEDED_SUBSCRIPTION_INFO": "Sie haben Ihr Speichervolumen überschritten, bitte <a>upgraden Sie</a>",
"SUBSCRIPTION_PURCHASE_SUCCESS": "",
"SUBSCRIPTION_PURCHASE_CANCELLED": "",
@ -171,6 +172,7 @@
"UPDATE_SUBSCRIPTION": "Plan ändern",
"CANCEL_SUBSCRIPTION": "Abonnement kündigen",
"CANCEL_SUBSCRIPTION_MESSAGE": "",
"CANCEL_SUBSCRIPTION_WITH_ADDON_MESSAGE": "",
"SUBSCRIPTION_CANCEL_FAILED": "",
"SUBSCRIPTION_CANCEL_SUCCESS": "",
"REACTIVATE_SUBSCRIPTION": "Abonnement reaktivieren",

View file

@ -157,6 +157,7 @@
"RENEWAL_ACTIVE_SUBSCRIPTION_STATUS": "Renews on {{date, dateTime}}",
"RENEWAL_CANCELLED_SUBSCRIPTION_STATUS": "Ends on {{date, dateTime}}",
"RENEWAL_CANCELLED_SUBSCRIPTION_INFO": "Your subscription will be cancelled on {{date, dateTime}}",
"ADD_ON_AVAILABLE_TILL": "Your {{storage, string}} add-on is valid till {{date, dateTime}}",
"STORAGE_QUOTA_EXCEEDED_SUBSCRIPTION_INFO": "You have exceeded your storage quota, please <a>upgrade</a>",
"SUBSCRIPTION_PURCHASE_SUCCESS": "<p>We've received your payment</p><p>Your subscription is valid till <strong>{{date, dateTime}}</strong></p>",
"SUBSCRIPTION_PURCHASE_CANCELLED": "Your purchase was canceled, please try again if you want to subscribe",
@ -171,6 +172,7 @@
"UPDATE_SUBSCRIPTION": "Change plan",
"CANCEL_SUBSCRIPTION": "Cancel subscription",
"CANCEL_SUBSCRIPTION_MESSAGE": "<p>All of your data will be deleted from our servers at the end of this billing period.</p><p>Are you sure that you want to cancel your subscription?</p>",
"CANCEL_SUBSCRIPTION_WITH_ADDON_MESSAGE": "<p>Are you sure you want to cancel your subscription?</p>",
"SUBSCRIPTION_CANCEL_FAILED": "Failed to cancel subscription",
"SUBSCRIPTION_CANCEL_SUCCESS": "Subscription canceled successfully",
"REACTIVATE_SUBSCRIPTION": "Reactivate subscription",

View file

@ -157,6 +157,7 @@
"RENEWAL_ACTIVE_SUBSCRIPTION_STATUS": "Se renueva en {{date, dateTime}}",
"RENEWAL_CANCELLED_SUBSCRIPTION_STATUS": "Termina el {{date, dateTime}}",
"RENEWAL_CANCELLED_SUBSCRIPTION_INFO": "Tu suscripción será cancelada el {{date, dateTime}}",
"ADD_ON_AVAILABLE_TILL": "",
"STORAGE_QUOTA_EXCEEDED_SUBSCRIPTION_INFO": "Ha excedido su cuota de almacenamiento, por favor <a>actualice</a>",
"SUBSCRIPTION_PURCHASE_SUCCESS": "<p>Hemos recibido tu pago</p><p>¡Tu suscripción es válida hasta <strong>{{date, dateTime}}</strong></p>",
"SUBSCRIPTION_PURCHASE_CANCELLED": "Tu compra ha sido cancelada, por favor inténtalo de nuevo si quieres suscribirte",
@ -171,6 +172,7 @@
"UPDATE_SUBSCRIPTION": "Cambiar de plan",
"CANCEL_SUBSCRIPTION": "Cancelar suscripción",
"CANCEL_SUBSCRIPTION_MESSAGE": "<p>Todos tus datos serán eliminados de nuestros servidores al final de este periodo de facturación.</p><p>¿Está seguro de que desea cancelar su suscripción?</p>",
"CANCEL_SUBSCRIPTION_WITH_ADDON_MESSAGE": "",
"SUBSCRIPTION_CANCEL_FAILED": "No se pudo cancelar la suscripción",
"SUBSCRIPTION_CANCEL_SUCCESS": "Suscripción cancelada correctamente",
"REACTIVATE_SUBSCRIPTION": "Reactivar la suscripción",

View file

@ -157,6 +157,7 @@
"RENEWAL_ACTIVE_SUBSCRIPTION_STATUS": "",
"RENEWAL_CANCELLED_SUBSCRIPTION_STATUS": "",
"RENEWAL_CANCELLED_SUBSCRIPTION_INFO": "",
"ADD_ON_AVAILABLE_TILL": "",
"STORAGE_QUOTA_EXCEEDED_SUBSCRIPTION_INFO": "",
"SUBSCRIPTION_PURCHASE_SUCCESS": "",
"SUBSCRIPTION_PURCHASE_CANCELLED": "",
@ -171,6 +172,7 @@
"UPDATE_SUBSCRIPTION": "",
"CANCEL_SUBSCRIPTION": "",
"CANCEL_SUBSCRIPTION_MESSAGE": "",
"CANCEL_SUBSCRIPTION_WITH_ADDON_MESSAGE": "",
"SUBSCRIPTION_CANCEL_FAILED": "",
"SUBSCRIPTION_CANCEL_SUCCESS": "",
"REACTIVATE_SUBSCRIPTION": "",

View file

@ -157,6 +157,7 @@
"RENEWAL_ACTIVE_SUBSCRIPTION_STATUS": "",
"RENEWAL_CANCELLED_SUBSCRIPTION_STATUS": "",
"RENEWAL_CANCELLED_SUBSCRIPTION_INFO": "",
"ADD_ON_AVAILABLE_TILL": "",
"STORAGE_QUOTA_EXCEEDED_SUBSCRIPTION_INFO": "",
"SUBSCRIPTION_PURCHASE_SUCCESS": "",
"SUBSCRIPTION_PURCHASE_CANCELLED": "",
@ -171,6 +172,7 @@
"UPDATE_SUBSCRIPTION": "",
"CANCEL_SUBSCRIPTION": "",
"CANCEL_SUBSCRIPTION_MESSAGE": "",
"CANCEL_SUBSCRIPTION_WITH_ADDON_MESSAGE": "",
"SUBSCRIPTION_CANCEL_FAILED": "",
"SUBSCRIPTION_CANCEL_SUCCESS": "",
"REACTIVATE_SUBSCRIPTION": "",

View file

@ -157,6 +157,7 @@
"RENEWAL_ACTIVE_SUBSCRIPTION_STATUS": "Renouveler le {{date, dateTime}}",
"RENEWAL_CANCELLED_SUBSCRIPTION_STATUS": "Pris fin le {{date, dateTime}}",
"RENEWAL_CANCELLED_SUBSCRIPTION_INFO": "Votre abonnement sera annulé le {{date, dateTime}}",
"ADD_ON_AVAILABLE_TILL": "",
"STORAGE_QUOTA_EXCEEDED_SUBSCRIPTION_INFO": "Vous avez dépassé votre quota de stockage, veuillez <a> mettre à niveau </a>",
"SUBSCRIPTION_PURCHASE_SUCCESS": "<p>Nous avons reçu votre paiement </p><p>Votre abonnement est valide jusqu'au <strong>{{date, dateTime}}</strong></p>",
"SUBSCRIPTION_PURCHASE_CANCELLED": "Votre achat est annulé, veuillez réessayer si vous souhaitez vous abonner",
@ -171,6 +172,7 @@
"UPDATE_SUBSCRIPTION": "Changer de plan",
"CANCEL_SUBSCRIPTION": "Annuler l'abonnement",
"CANCEL_SUBSCRIPTION_MESSAGE": "<p>Toutes vos données seront supprimées de nos serveurs à la fin de cette période d'abonnement.</p><p>Voulez-vous vraiment annuler votre abonnement?</p>",
"CANCEL_SUBSCRIPTION_WITH_ADDON_MESSAGE": "",
"SUBSCRIPTION_CANCEL_FAILED": "Échec lors de l'annulation de l'abonnement",
"SUBSCRIPTION_CANCEL_SUCCESS": "Votre abonnement a bien été annulé",
"REACTIVATE_SUBSCRIPTION": "Réactiver l'abonnement",
@ -211,7 +213,7 @@
"THING": "Chose",
"FILE_CAPTION": "Description",
"FILE_TYPE": "Type de fichier",
"CLIP": ""
"CLIP": "Magique"
},
"photos_count_zero": "Pas de souvenirs",
"photos_count_one": "1 souvenir",
@ -541,8 +543,8 @@
"EXPORT_PROGRESS": "<a>{{progress.success}} / {{progress.total}}</a> fichiers exportés",
"MIGRATING_EXPORT": "Préparations...",
"RENAMING_COLLECTION_FOLDERS": "Renommage des dossiers de l'album en cours...",
"TRASHING_DELETED_FILES": "",
"TRASHING_DELETED_COLLECTIONS": "",
"TRASHING_DELETED_FILES": "Mise à la corbeille des fichiers supprimés...",
"TRASHING_DELETED_COLLECTIONS": "Mise à la corbeille des albums supprimés...",
"EXPORT_NOTIFICATION": {
"START": "L'export a démarré",
"IN_PROGRESS": "Un export est déjà en cours",
@ -587,38 +589,38 @@
"DOWNLOAD_FAILED": "Échec du téléchargement",
"DOWNLOAD_PROGRESS": "{{progress.current}} / {{progress.total}} fichiers",
"CRASH_REPORTING": "Rapport de plantage",
"CHRISTMAS": "",
"CHRISTMAS_EVE": "",
"NEW_YEAR": "",
"NEW_YEAR_EVE": "",
"CHRISTMAS": "Noël",
"CHRISTMAS_EVE": "Réveillon de Noël",
"NEW_YEAR": "Nouvel an",
"NEW_YEAR_EVE": "Réveillon de Nouvel An",
"IMAGE": "Image",
"VIDEO": "Vidéo",
"LIVE_PHOTO": "",
"LIVE_PHOTO": "Photos en direct",
"CONVERT": "Convertir",
"CONFIRM_EDITOR_CLOSE_MESSAGE": "",
"CONFIRM_EDITOR_CLOSE_DESCRIPTION": "",
"BRIGHTNESS": "",
"CONTRAST": "",
"SATURATION": "",
"BLUR": "",
"INVERT_COLORS": "",
"ASPECT_RATIO": "",
"SQUARE": "",
"ROTATE_LEFT": "",
"ROTATE_RIGHT": "",
"FLIP_VERTICALLY": "",
"FLIP_HORIZONTALLY": "",
"DOWNLOAD_EDITED": "",
"SAVE_A_COPY_TO_ENTE": "",
"RESTORE_ORIGINAL": "",
"TRANSFORM": "",
"COLORS": "",
"FLIP": "",
"ROTATION": "",
"RESET": "",
"PHOTO_EDITOR": "",
"FASTER_UPLOAD": "",
"FASTER_UPLOAD_DESCRIPTION": "",
"STATUS": "",
"INDEXED_ITEMS": ""
"CONFIRM_EDITOR_CLOSE_MESSAGE": "Êtes-vous sûr de vouloir fermer l'éditeur ?",
"CONFIRM_EDITOR_CLOSE_DESCRIPTION": "Téléchargez votre image modifiée ou enregistrez une copie sur ente pour maintenir vos modifications.",
"BRIGHTNESS": "Luminosité",
"CONTRAST": "Contraste",
"SATURATION": "Saturation",
"BLUR": "Flou",
"INVERT_COLORS": "Inverser les couleurs",
"ASPECT_RATIO": "Ratio de l'image",
"SQUARE": "Carré",
"ROTATE_LEFT": "Pivoter vers la gauche",
"ROTATE_RIGHT": "Pivoter vers la droite",
"FLIP_VERTICALLY": "Basculer verticalement",
"FLIP_HORIZONTALLY": "Retourner horizontalement",
"DOWNLOAD_EDITED": "Téléchargement modifié",
"SAVE_A_COPY_TO_ENTE": "Enregistrer une copie dans ente",
"RESTORE_ORIGINAL": "Restaurer l'original",
"TRANSFORM": "Transformer",
"COLORS": "Couleurs",
"FLIP": "Retourner",
"ROTATION": "Rotation",
"RESET": "Réinitialiser",
"PHOTO_EDITOR": "Éditeur de photos",
"FASTER_UPLOAD": "Chargements plus rapides",
"FASTER_UPLOAD_DESCRIPTION": "Router les chargements vers les serveurs à proximité",
"STATUS": "État",
"INDEXED_ITEMS": "Éléments indexés"
}

View file

@ -157,6 +157,7 @@
"RENEWAL_ACTIVE_SUBSCRIPTION_STATUS": "Si rinnova il {{date, dateTime}}",
"RENEWAL_CANCELLED_SUBSCRIPTION_STATUS": "Termina il {{date, dateTime}}",
"RENEWAL_CANCELLED_SUBSCRIPTION_INFO": "Il tuo abbonamento verrà annullato il {{date, dateTime}}",
"ADD_ON_AVAILABLE_TILL": "",
"STORAGE_QUOTA_EXCEEDED_SUBSCRIPTION_INFO": "Hai superato la quota di archiviazione assegnata, si prega di aggiornare <a></a>",
"SUBSCRIPTION_PURCHASE_SUCCESS": "<p>Abbiamo ricevuto il tuo pagamento</p><p>Il tuo abbonamento è valido fino a <strong>{{date, dateTime}}</strong></p>",
"SUBSCRIPTION_PURCHASE_CANCELLED": "Il tuo acquisto è stato annullato, riprova se vuoi iscriverti",
@ -171,6 +172,7 @@
"UPDATE_SUBSCRIPTION": "Cambia piano",
"CANCEL_SUBSCRIPTION": "Annulla abbonamento",
"CANCEL_SUBSCRIPTION_MESSAGE": "<p>Tutti i tuoi dati saranno cancellati dai nostri server alla fine di questo periodo di fatturazione.</p><p>Sei sicuro di voler annullare il tuo abbonamento?</p>",
"CANCEL_SUBSCRIPTION_WITH_ADDON_MESSAGE": "",
"SUBSCRIPTION_CANCEL_FAILED": "Impossibile annullare l'abbonamento",
"SUBSCRIPTION_CANCEL_SUCCESS": "Abbonamento annullato con successo",
"REACTIVATE_SUBSCRIPTION": "Riattiva abbonamento",

View file

@ -157,6 +157,7 @@
"RENEWAL_ACTIVE_SUBSCRIPTION_STATUS": "Vernieuwt op {{date, dateTime}}",
"RENEWAL_CANCELLED_SUBSCRIPTION_STATUS": "Eindigt op {{date, dateTime}}",
"RENEWAL_CANCELLED_SUBSCRIPTION_INFO": "Uw abonnement loopt af op {{date, dateTime}}",
"ADD_ON_AVAILABLE_TILL": "",
"STORAGE_QUOTA_EXCEEDED_SUBSCRIPTION_INFO": "U heeft uw opslaglimiet overschreden, gelieve <a>upgraden</a>",
"SUBSCRIPTION_PURCHASE_SUCCESS": "<p>We hebben uw betaling ontvangen</p><p>Uw abonnement is geldig tot <strong>{{date, dateTime}}</strong></p>",
"SUBSCRIPTION_PURCHASE_CANCELLED": "Uw aankoop is geannuleerd, probeer het opnieuw als u zich wilt abonneren",
@ -171,6 +172,7 @@
"UPDATE_SUBSCRIPTION": "Abonnement wijzigen",
"CANCEL_SUBSCRIPTION": "Abonnement opzeggen",
"CANCEL_SUBSCRIPTION_MESSAGE": "<p>Al je gegevens zullen worden verwijderd van onze servers aan het einde van deze factureringsperiode.</p><p>Weet u zeker dat u uw abonnement wilt opzeggen?</p>",
"CANCEL_SUBSCRIPTION_WITH_ADDON_MESSAGE": "",
"SUBSCRIPTION_CANCEL_FAILED": "Abonnement opzeggen mislukt",
"SUBSCRIPTION_CANCEL_SUCCESS": "Abonnement succesvol geannuleerd",
"REACTIVATE_SUBSCRIPTION": "Abonnement opnieuw activeren",

View file

@ -157,6 +157,7 @@
"RENEWAL_ACTIVE_SUBSCRIPTION_STATUS": "",
"RENEWAL_CANCELLED_SUBSCRIPTION_STATUS": "",
"RENEWAL_CANCELLED_SUBSCRIPTION_INFO": "",
"ADD_ON_AVAILABLE_TILL": "",
"STORAGE_QUOTA_EXCEEDED_SUBSCRIPTION_INFO": "",
"SUBSCRIPTION_PURCHASE_SUCCESS": "",
"SUBSCRIPTION_PURCHASE_CANCELLED": "",
@ -171,6 +172,7 @@
"UPDATE_SUBSCRIPTION": "",
"CANCEL_SUBSCRIPTION": "",
"CANCEL_SUBSCRIPTION_MESSAGE": "",
"CANCEL_SUBSCRIPTION_WITH_ADDON_MESSAGE": "",
"SUBSCRIPTION_CANCEL_FAILED": "",
"SUBSCRIPTION_CANCEL_SUCCESS": "",
"REACTIVATE_SUBSCRIPTION": "",

View file

@ -157,6 +157,7 @@
"RENEWAL_ACTIVE_SUBSCRIPTION_STATUS": "",
"RENEWAL_CANCELLED_SUBSCRIPTION_STATUS": "",
"RENEWAL_CANCELLED_SUBSCRIPTION_INFO": "",
"ADD_ON_AVAILABLE_TILL": "",
"STORAGE_QUOTA_EXCEEDED_SUBSCRIPTION_INFO": "",
"SUBSCRIPTION_PURCHASE_SUCCESS": "",
"SUBSCRIPTION_PURCHASE_CANCELLED": "",
@ -171,6 +172,7 @@
"UPDATE_SUBSCRIPTION": "",
"CANCEL_SUBSCRIPTION": "",
"CANCEL_SUBSCRIPTION_MESSAGE": "",
"CANCEL_SUBSCRIPTION_WITH_ADDON_MESSAGE": "",
"SUBSCRIPTION_CANCEL_FAILED": "",
"SUBSCRIPTION_CANCEL_SUCCESS": "",
"REACTIVATE_SUBSCRIPTION": "",

View file

@ -157,6 +157,7 @@
"RENEWAL_ACTIVE_SUBSCRIPTION_STATUS": "",
"RENEWAL_CANCELLED_SUBSCRIPTION_STATUS": "",
"RENEWAL_CANCELLED_SUBSCRIPTION_INFO": "",
"ADD_ON_AVAILABLE_TILL": "",
"STORAGE_QUOTA_EXCEEDED_SUBSCRIPTION_INFO": "",
"SUBSCRIPTION_PURCHASE_SUCCESS": "",
"SUBSCRIPTION_PURCHASE_CANCELLED": "",
@ -171,6 +172,7 @@
"UPDATE_SUBSCRIPTION": "",
"CANCEL_SUBSCRIPTION": "",
"CANCEL_SUBSCRIPTION_MESSAGE": "",
"CANCEL_SUBSCRIPTION_WITH_ADDON_MESSAGE": "",
"SUBSCRIPTION_CANCEL_FAILED": "",
"SUBSCRIPTION_CANCEL_SUCCESS": "",
"REACTIVATE_SUBSCRIPTION": "",

View file

@ -157,6 +157,7 @@
"RENEWAL_ACTIVE_SUBSCRIPTION_STATUS": "于 {{date, dateTime}} 续费",
"RENEWAL_CANCELLED_SUBSCRIPTION_STATUS": "结束于 {{date, dateTime}}",
"RENEWAL_CANCELLED_SUBSCRIPTION_INFO": "您的订阅将于 {{date, dateTime}} 取消",
"ADD_ON_AVAILABLE_TILL": "",
"STORAGE_QUOTA_EXCEEDED_SUBSCRIPTION_INFO": "您已超过您的存储配额,请 <a>升级</a>",
"SUBSCRIPTION_PURCHASE_SUCCESS": "<p>我们已经收到您的付款</p><p>您的订阅有效期至 <strong>{{date, dateTime}}</strong></p>",
"SUBSCRIPTION_PURCHASE_CANCELLED": "您的购买已取消,如果您想订阅,请重试",
@ -171,6 +172,7 @@
"UPDATE_SUBSCRIPTION": "更改计划",
"CANCEL_SUBSCRIPTION": "取消订阅",
"CANCEL_SUBSCRIPTION_MESSAGE": "<p>您的所有数据将在此计费期结束时从我们的服务器中删除。</p><p>您确定要取消您的订阅吗?</p>",
"CANCEL_SUBSCRIPTION_WITH_ADDON_MESSAGE": "",
"SUBSCRIPTION_CANCEL_FAILED": "取消订阅失败",
"SUBSCRIPTION_CANCEL_SUCCESS": "订阅成功取消",
"REACTIVATE_SUBSCRIPTION": "重新激活订阅",

View file

@ -69,6 +69,48 @@ export default function SubscriptionStatus({
return <></>;
}
const messages = [];
if (!hasAddOnBonus(userDetails.bonusData)) {
if (isSubscriptionActive(userDetails.subscription)) {
if (isOnFreePlan(userDetails.subscription)) {
messages.push(
<Trans
i18nKey={'FREE_SUBSCRIPTION_INFO'}
values={{
date: userDetails.subscription?.expiryTime,
}}
/>
);
} else if (isSubscriptionCancelled(userDetails.subscription)) {
messages.push(
t('RENEWAL_CANCELLED_SUBSCRIPTION_INFO', {
date: userDetails.subscription?.expiryTime,
})
);
}
} else {
messages.push(
<Trans
i18nKey={'SUBSCRIPTION_EXPIRED_MESSAGE'}
components={{
a: <LinkButton onClick={handleClick} />,
}}
/>
);
}
}
if (hasExceededStorageQuota(userDetails) && messages.length === 0) {
messages.push(
<Trans
i18nKey={'STORAGE_QUOTA_EXCEEDED_SUBSCRIPTION_INFO'}
components={{
a: <LinkButton onClick={handleClick} />,
}}
/>
);
}
return (
<Box px={1} pt={0.5}>
<Typography
@ -76,42 +118,7 @@ export default function SubscriptionStatus({
color={'text.muted'}
onClick={handleClick && handleClick}
sx={{ cursor: handleClick && 'pointer' }}>
{isSubscriptionActive(userDetails.subscription) ? (
isOnFreePlan(userDetails.subscription) ? (
hasAddOnBonus(userDetails.bonusData) ? (
''
) : (
<Trans
i18nKey={'FREE_SUBSCRIPTION_INFO'}
values={{
date: userDetails.subscription?.expiryTime,
}}
/>
)
) : isSubscriptionCancelled(userDetails.subscription) ? (
t('RENEWAL_CANCELLED_SUBSCRIPTION_INFO', {
date: userDetails.subscription?.expiryTime,
})
) : (
hasExceededStorageQuota(userDetails) && (
<Trans
i18nKey={
'STORAGE_QUOTA_EXCEEDED_SUBSCRIPTION_INFO'
}
components={{
a: <LinkButton onClick={handleClick} />,
}}
/>
)
)
) : (
<Trans
i18nKey={'SUBSCRIPTION_EXPIRED_MESSAGE'}
components={{
a: <LinkButton onClick={handleClick} />,
}}
/>
)}
{messages}
</Typography>
</Box>
);

View file

@ -5,10 +5,13 @@ import React from 'react';
import { t } from 'i18next';
import { PeriodToggler } from '../periodToggler';
import Plans from '../plans';
import { hasAddOnBonus } from 'utils/billing';
import { BFAddOnRow } from '../plans/BfAddOnRow';
export default function FreeSubscriptionPlanSelectorCard({
plans,
subscription,
bonusData,
closeModal,
planPeriod,
togglePeriod,
@ -36,8 +39,15 @@ export default function FreeSubscriptionPlanSelectorCard({
planPeriod={planPeriod}
onPlanSelect={onPlanSelect}
subscription={subscription}
bonusData={bonusData}
closeModal={closeModal}
/>
{hasAddOnBonus(bonusData) && (
<BFAddOnRow
bonusData={bonusData}
closeModal={closeModal}
/>
)}
</Stack>
</Box>
</>

View file

@ -44,6 +44,13 @@ function PlanSelectorCard(props: Props) {
);
const galleryContext = useContext(GalleryContext);
const appContext = useContext(AppContext);
const bonusData = useMemo(() => {
const userDetails = getLocalUserDetails();
if (!userDetails) {
return null;
}
return userDetails.bonusData;
}, []);
const usage = useMemo(() => {
const userDetails = getLocalUserDetails();
@ -170,6 +177,7 @@ function PlanSelectorCard(props: Props) {
<PaidSubscriptionPlanSelectorCard
plans={plans}
subscription={subscription}
bonusData={bonusData}
closeModal={props.closeModal}
planPeriod={planPeriod}
togglePeriod={togglePeriod}
@ -181,6 +189,7 @@ function PlanSelectorCard(props: Props) {
<FreeSubscriptionPlanSelectorCard
plans={plans}
subscription={subscription}
bonusData={bonusData}
closeModal={props.closeModal}
planPeriod={planPeriod}
togglePeriod={togglePeriod}

View file

@ -5,15 +5,21 @@ import Typography from '@mui/material/Typography';
import { SpaceBetweenFlex } from '@ente/shared/components/Container';
import React from 'react';
import { t } from 'i18next';
import { convertBytesToGBs, isSubscriptionCancelled } from 'utils/billing';
import {
convertBytesToGBs,
hasAddOnBonus,
isSubscriptionCancelled,
} from 'utils/billing';
import { ManageSubscription } from '../manageSubscription';
import { PeriodToggler } from '../periodToggler';
import Plans from '../plans';
import { Trans } from 'react-i18next';
import { BFAddOnRow } from '../plans/BfAddOnRow';
export default function PaidSubscriptionPlanSelectorCard({
plans,
subscription,
bonusData,
closeModal,
usage,
planPeriod,
@ -71,6 +77,7 @@ export default function PaidSubscriptionPlanSelectorCard({
planPeriod={planPeriod}
onPlanSelect={onPlanSelect}
subscription={subscription}
bonusData={bonusData}
closeModal={closeModal}
/>
</Stack>
@ -85,11 +92,18 @@ export default function PaidSubscriptionPlanSelectorCard({
date: subscription.expiryTime,
})}
</Typography>
{hasAddOnBonus(bonusData) && (
<BFAddOnRow
bonusData={bonusData}
closeModal={closeModal}
/>
)}
</Box>
</Box>
<ManageSubscription
subscription={subscription}
bonusData={bonusData}
closeModal={closeModal}
setLoading={setLoading}
/>

View file

@ -12,16 +12,21 @@ import {
manageFamilyMethod,
hasStripeSubscription,
isSubscriptionCancelled,
hasAddOnBonus,
} from 'utils/billing';
import ManageSubscriptionButton from './button';
import { BonusData } from 'types/user';
interface Iprops {
subscription: Subscription;
bonusData?: BonusData;
closeModal: () => void;
setLoading: SetLoading;
}
export function ManageSubscription({
subscription,
bonusData,
closeModal,
setLoading,
}: Iprops) {
@ -34,6 +39,7 @@ export function ManageSubscription({
{hasStripeSubscription(subscription) && (
<StripeSubscriptionOptions
subscription={subscription}
bonusData={bonusData}
closeModal={closeModal}
setLoading={setLoading}
/>
@ -49,6 +55,7 @@ export function ManageSubscription({
function StripeSubscriptionOptions({
subscription,
bonusData,
setLoading,
closeModal,
}: Iprops) {
@ -77,7 +84,11 @@ function StripeSubscriptionOptions({
const confirmCancel = () =>
appContext.setDialogMessage({
title: t('CANCEL_SUBSCRIPTION'),
content: <Trans i18nKey={'CANCEL_SUBSCRIPTION_MESSAGE'} />,
content: hasAddOnBonus(bonusData) ? (
<Trans i18nKey={'CANCEL_SUBSCRIPTION_WITH_ADDON_MESSAGE'} />
) : (
<Trans i18nKey={'CANCEL_SUBSCRIPTION_MESSAGE'} />
),
proceed: {
text: t('CANCEL_SUBSCRIPTION'),
action: cancelSubscription.bind(

View file

@ -0,0 +1,43 @@
import { Box, styled, Typography } from '@mui/material';
import { SpaceBetweenFlex } from '@ente/shared/components/Container';
import React from 'react';
import { Trans } from 'react-i18next';
import { makeHumanReadableStorage } from 'utils/billing';
const RowContainer = styled(SpaceBetweenFlex)(({ theme }) => ({
// gap: theme.spacing(1.5),
padding: theme.spacing(1, 0),
cursor: 'pointer',
'&:hover .endIcon': {
backgroundColor: 'rgba(255,255,255,0.08)',
},
}));
export function BFAddOnRow({ bonusData, closeModal }) {
return (
<>
{bonusData.storageBonuses.map((bonus) => {
if (bonus.type.startsWith('ADD_ON')) {
return (
<RowContainer key={bonus.id} onClick={closeModal}>
<Box>
<Typography color="text.muted">
<Trans
i18nKey={'ADD_ON_AVAILABLE_TILL'}
values={{
storage: makeHumanReadableStorage(
bonus.storage
),
date: bonus.validTill,
}}
/>
</Typography>
</Box>
</RowContainer>
);
}
return null;
})}
</>
);
}

View file

@ -2,6 +2,7 @@ import { FreePlanRow } from './FreePlanRow';
import { Stack } from '@mui/material';
import React from 'react';
import {
hasAddOnBonus,
hasPaidSubscription,
isPopularPlan,
isUserSubscribedPlan,
@ -9,11 +10,13 @@ import {
import { PlanRow } from './planRow';
import { Plan, Subscription } from 'types/billing';
import { PLAN_PERIOD } from 'constants/gallery';
import { BonusData } from 'types/user';
interface Iprops {
plans: Plan[];
planPeriod: PLAN_PERIOD;
subscription: Subscription;
bonusData?: BonusData;
onPlanSelect: (plan: Plan) => void;
closeModal: () => void;
}
@ -22,6 +25,7 @@ const Plans = ({
plans,
planPeriod,
subscription,
bonusData,
onPlanSelect,
closeModal,
}: Iprops) => (
@ -38,7 +42,7 @@ const Plans = ({
onPlanSelect={onPlanSelect}
/>
))}
{!hasPaidSubscription(subscription) && (
{!hasPaidSubscription(subscription) && !hasAddOnBonus(bonusData) && (
<FreePlanRow closeModal={closeModal} />
)}
</Stack>

View file

@ -42,6 +42,11 @@ export const WHITELISTED_FILE_FORMATS: FileTypeInfo[] = [
exactType: 'crw',
mimeType: 'image/x-canon-crw',
},
{
fileType: FILE_TYPE.VIDEO,
exactType: 'mov',
mimeType: 'video/quicktime',
},
];
export const KNOWN_NON_MEDIA_FORMATS = ['xmp', 'html', 'txt'];

View file

@ -14,6 +14,8 @@ import HTTPService from '@ente/shared/network/HTTPService';
import { getToken } from '@ente/shared/storage/localStorage/helpers';
import { getLatestVersionEmbeddings } from 'utils/embedding';
import { getLocalTrashedFiles } from './trashService';
import { getLocalCollections } from './collectionService';
import { CustomError } from '@ente/shared/error';
const ENDPOINT = getEndpoint();
@ -42,6 +44,7 @@ export const syncEmbeddings = async () => {
try {
let embeddings = await getLocalEmbeddings();
const localFiles = await getAllLocalFiles();
const hiddenAlbums = await getLocalCollections('hidden');
const localTrashFiles = await getLocalTrashedFiles();
const fileIdToKeyMap = new Map<number, string>();
[...localFiles, ...localTrashFiles].forEach((file) => {
@ -67,7 +70,7 @@ export const syncEmbeddings = async () => {
const worker = await ComlinkCryptoWorker.getInstance();
const fileKey = fileIdToKeyMap.get(embedding.fileID);
if (!fileKey) {
throw Error('File key not found');
throw Error(CustomError.FILE_NOT_FOUND);
}
const decryptedData = await worker.decryptEmbedding(
encryptedEmbedding,
@ -80,7 +83,14 @@ export const syncEmbeddings = async () => {
embedding: decryptedData,
} as Embedding;
} catch (e) {
logError(e, 'decryptEmbedding failed for file');
let info: Record<string, unknown>;
if (e.message === CustomError.FILE_NOT_FOUND) {
const hasHiddenAlbums = hiddenAlbums?.length > 0;
info = {
hasHiddenAlbums,
};
}
logError(e, 'decryptEmbedding failed for file', info);
}
})
);

View file

@ -24,7 +24,6 @@ import { groupFilesBasedOnCollectionID } from 'utils/file';
import ElectronAPIs from '@ente/shared/electron';
class watchFolderService {
private allElectronAPIsExist: boolean = false;
private eventQueue: EventQueueItem[] = [];
private currentEvent: EventQueueItem;
private currentlySyncedMapping: WatchMapping;
@ -53,18 +52,16 @@ class watchFolderService {
syncWithRemote: () => void,
setWatchFolderServiceIsRunning: (isRunning: boolean) => void
) {
if (this.allElectronAPIsExist) {
try {
this.setElectronFiles = setElectronFiles;
this.setCollectionName = setCollectionName;
this.syncWithRemote = syncWithRemote;
this.setWatchFolderServiceIsRunning =
setWatchFolderServiceIsRunning;
this.setupWatcherFunctions();
await this.getAndSyncDiffOfFiles();
} catch (e) {
logError(e, 'error while initializing watch service');
}
try {
this.setElectronFiles = setElectronFiles;
this.setCollectionName = setCollectionName;
this.syncWithRemote = syncWithRemote;
this.setWatchFolderServiceIsRunning =
setWatchFolderServiceIsRunning;
this.setupWatcherFunctions();
await this.getAndSyncDiffOfFiles();
} catch (e) {
logError(e, 'error while initializing watch service');
}
}
@ -171,13 +168,11 @@ class watchFolderService {
}
private setupWatcherFunctions() {
if (this.allElectronAPIsExist) {
ElectronAPIs.registerWatcherFunctions(
diskFileAddedCallback,
diskFileRemovedCallback,
diskFolderRemovedCallback
);
}
ElectronAPIs.registerWatcherFunctions(
diskFileAddedCallback,
diskFileRemovedCallback,
diskFolderRemovedCallback
);
}
async addWatchMapping(
@ -185,38 +180,32 @@ class watchFolderService {
folderPath: string,
uploadStrategy: UPLOAD_STRATEGY
) {
if (this.allElectronAPIsExist) {
try {
await ElectronAPIs.addWatchMapping(
rootFolderName,
folderPath,
uploadStrategy
);
this.getAndSyncDiffOfFiles();
} catch (e) {
logError(e, 'error while adding watch mapping');
}
try {
await ElectronAPIs.addWatchMapping(
rootFolderName,
folderPath,
uploadStrategy
);
this.getAndSyncDiffOfFiles();
} catch (e) {
logError(e, 'error while adding watch mapping');
}
}
async removeWatchMapping(folderPath: string) {
if (this.allElectronAPIsExist) {
try {
await ElectronAPIs.removeWatchMapping(folderPath);
} catch (e) {
logError(e, 'error while removing watch mapping');
}
try {
await ElectronAPIs.removeWatchMapping(folderPath);
} catch (e) {
logError(e, 'error while removing watch mapping');
}
}
getWatchMappings(): WatchMapping[] {
if (this.allElectronAPIsExist) {
try {
return ElectronAPIs.getWatchMappings() ?? [];
} catch (e) {
logError(e, 'error while getting watch mappings');
return [];
}
try {
return ElectronAPIs.getWatchMappings() ?? [];
} catch (e) {
logError(e, 'error while getting watch mappings');
return [];
}
return [];
}
@ -344,71 +333,67 @@ class watchFolderService {
filesWithCollection: FileWithCollection[],
collections: Collection[]
) {
if (this.allElectronAPIsExist) {
try {
addLocalLog(
() =>
`allFileUploadsDone,${JSON.stringify(
filesWithCollection
)} ${JSON.stringify(collections)}`
);
const collection = collections.find(
(collection) =>
collection.id === filesWithCollection[0].collectionID
);
addLocalLog(() => `got collection ${!!collection}`);
addLocalLog(
() =>
`${this.isEventRunning} ${this.currentEvent.collectionName} ${collection?.name}`
);
if (
!this.isEventRunning ||
this.currentEvent.collectionName !== collection?.name
) {
return;
}
const syncedFiles: WatchMapping['syncedFiles'] = [];
const ignoredFiles: WatchMapping['ignoredFiles'] = [];
for (const fileWithCollection of filesWithCollection) {
this.handleUploadedFile(
fileWithCollection,
syncedFiles,
ignoredFiles
);
}
addLocalLog(() => `syncedFiles ${JSON.stringify(syncedFiles)}`);
addLocalLog(
() => `ignoredFiles ${JSON.stringify(ignoredFiles)}`
);
if (syncedFiles.length > 0) {
this.currentlySyncedMapping.syncedFiles = [
...this.currentlySyncedMapping.syncedFiles,
...syncedFiles,
];
ElectronAPIs.updateWatchMappingSyncedFiles(
this.currentlySyncedMapping.folderPath,
this.currentlySyncedMapping.syncedFiles
);
}
if (ignoredFiles.length > 0) {
this.currentlySyncedMapping.ignoredFiles = [
...this.currentlySyncedMapping.ignoredFiles,
...ignoredFiles,
];
ElectronAPIs.updateWatchMappingIgnoredFiles(
this.currentlySyncedMapping.folderPath,
this.currentlySyncedMapping.ignoredFiles
);
}
this.runPostUploadsAction();
} catch (e) {
logError(e, 'error while running all file uploads done');
try {
addLocalLog(
() =>
`allFileUploadsDone,${JSON.stringify(
filesWithCollection
)} ${JSON.stringify(collections)}`
);
const collection = collections.find(
(collection) =>
collection.id === filesWithCollection[0].collectionID
);
addLocalLog(() => `got collection ${!!collection}`);
addLocalLog(
() =>
`${this.isEventRunning} ${this.currentEvent.collectionName} ${collection?.name}`
);
if (
!this.isEventRunning ||
this.currentEvent.collectionName !== collection?.name
) {
return;
}
const syncedFiles: WatchMapping['syncedFiles'] = [];
const ignoredFiles: WatchMapping['ignoredFiles'] = [];
for (const fileWithCollection of filesWithCollection) {
this.handleUploadedFile(
fileWithCollection,
syncedFiles,
ignoredFiles
);
}
addLocalLog(() => `syncedFiles ${JSON.stringify(syncedFiles)}`);
addLocalLog(() => `ignoredFiles ${JSON.stringify(ignoredFiles)}`);
if (syncedFiles.length > 0) {
this.currentlySyncedMapping.syncedFiles = [
...this.currentlySyncedMapping.syncedFiles,
...syncedFiles,
];
ElectronAPIs.updateWatchMappingSyncedFiles(
this.currentlySyncedMapping.folderPath,
this.currentlySyncedMapping.syncedFiles
);
}
if (ignoredFiles.length > 0) {
this.currentlySyncedMapping.ignoredFiles = [
...this.currentlySyncedMapping.ignoredFiles,
...ignoredFiles,
];
ElectronAPIs.updateWatchMappingIgnoredFiles(
this.currentlySyncedMapping.folderPath,
this.currentlySyncedMapping.ignoredFiles
);
}
this.runPostUploadsAction();
} catch (e) {
logError(e, 'error while running all file uploads done');
}
}

View file

@ -3,6 +3,9 @@ import { Embedding } from 'types/embedding';
export const getLatestVersionEmbeddings = (embeddings: Embedding[]) => {
const latestVersionEntities = new Map<number, Embedding>();
embeddings.forEach((embedding) => {
if (!embedding?.fileID) {
return;
}
const existingEmbeddings = latestVersionEntities.get(embedding.fileID);
if (
!existingEmbeddings ||

View file

@ -84,6 +84,7 @@ export const CustomError = {
TWO_FACTOR_ENABLED: 'two factor enabled',
CLIENT_ERROR: 'client error',
ServerError: 'server error',
FILE_NOT_FOUND: 'file not found',
};
export function handleUploadError(error: any): Error {