diff --git a/next.config.js b/next.config.js
index 09bf62087..27ceae63f 100644
--- a/next.config.js
+++ b/next.config.js
@@ -257,6 +257,11 @@ module.exports = {
destination: '/:path*',
permanent: true,
},
+ {
+ source: '/webdav',
+ destination: '/webdav-rclone',
+ permanent: true,
+ },
];
},
images: {
diff --git a/src/components/shared/pricing/PricingSection.tsx b/src/components/shared/pricing/PricingSection.tsx
index 664f0f455..0414b9dd0 100644
--- a/src/components/shared/pricing/PricingSection.tsx
+++ b/src/components/shared/pricing/PricingSection.tsx
@@ -49,6 +49,8 @@ interface PriceTableProps {
onBusinessPlansSelected?: (isBusiness: boolean) => void;
differentRecommended?: boolean;
isValentinesMode?: boolean;
+ onlyUltimatePlan?: boolean;
+ premiumAndUltimatePlan?: boolean;
}
export const PricingSection = ({
@@ -81,6 +83,8 @@ export const PricingSection = ({
showPromo,
isAffiliate,
isValentinesMode = false,
+ onlyUltimatePlan = false,
+ premiumAndUltimatePlan = false,
}: PriceTableProps): JSX.Element => {
const banner = require('@/assets/lang/en/banners.json');
@@ -183,28 +187,40 @@ export const PricingSection = ({
enterTo="scale-100 translate-y-0 opacity-100"
className="flex flex-col gap-4"
>
-
+
{products?.individuals
- ? products.individuals[billingFrequency].map((product, cardIndex) => (
-
{
+ if (premiumAndUltimatePlan) {
+ return product.storage === '5TB' || product.storage === '3TB';
}
- lang={lang}
- darkMode={darkMode}
- isAffiliate={isAffiliate}
- cardIndex={cardIndex}
- showGift={showPromo}
- isValentinesMode={isValentinesMode}
- />
- ))
+ if (onlyUltimatePlan) {
+ return product.storage === '5TB';
+ }
+ return true;
+ })
+ .map((product, cardIndex) => (
+
+ ))
: undefined}
diff --git a/src/components/shared/pricing/PricingSectionWrapper.tsx b/src/components/shared/pricing/PricingSectionWrapper.tsx
index fb23e597a..6be921e38 100644
--- a/src/components/shared/pricing/PricingSectionWrapper.tsx
+++ b/src/components/shared/pricing/PricingSectionWrapper.tsx
@@ -71,6 +71,8 @@ interface PricingSectionWrapperProps {
overrideOnBusinessSwitchToggled?: (interval: Interval) => void;
differentRecommended?: boolean;
SectionTag?: React.ElementType;
+ onlyUltimatePlan?: boolean;
+ premiumAndUltimatePlan?: boolean;
}
const calculateDiscountPercentage = (decimalValue?: number) => {
@@ -194,6 +196,8 @@ export const PricingSectionWrapper = ({
overrideOnBusinessSwitchToggled,
differentRecommended,
SectionTag = DEFAULTS.SectionTag,
+ onlyUltimatePlan = false,
+ premiumAndUltimatePlan = false,
}: PricingSectionWrapperProps): JSX.Element => {
const localPlanSelection = usePlanSelection(
startFromPlan,
@@ -280,6 +284,8 @@ export const PricingSectionWrapper = ({
differentRecommended={differentRecommended}
showPromo={showPromo}
isValentinesMode={isValentinesMode}
+ onlyUltimatePlan={onlyUltimatePlan}
+ premiumAndUltimatePlan={premiumAndUltimatePlan}
/>
diff --git a/src/hooks/useSpecialOfferConfig.ts b/src/hooks/useSpecialOfferConfig.ts
index 1e8b2ab8b..5b698ad76 100644
--- a/src/hooks/useSpecialOfferConfig.ts
+++ b/src/hooks/useSpecialOfferConfig.ts
@@ -26,10 +26,18 @@ export const ALLOWED_PATHS = [
'simon42',
'devopstoolbox',
'heisect',
+ 'bjoern',
+ 'lefiltre',
+ 'ultimate',
+ 'annual',
];
export const ALTERNATE_RECOMENDATED_PLAN_PATHS = new Set([]);
export const DARK_MODE_PATHS = new Set(['baity', 'xavier', 'oscar', 'rimembah', 'believemy', 'ghareeb']);
export const ALTERNATIVE_IMAGES_PATHS = new Set(['baity']);
+export const ONLY_ULTIMATE_PLANS_PATHS = new Set(['ultimate']);
+export const ULTIMATE_PREMIUM_PLANS_PATHS = new Set(['annual']);
+export const ANNUAL_PLANS_PATHS = new Set(['annual', 'ultimate']);
+
export const COUPON_CODES = {
baity: PromoCodeName.BaityBait,
xavier: PromoCodeName.Xavier,
@@ -54,6 +62,10 @@ export const COUPON_CODES = {
simon42: PromoCodeName.simon42,
devopstoolbox: PromoCodeName.devopstoolbox,
heisect: PromoCodeName.heisect,
+ bjoern: PromoCodeName.bjoern,
+ lefiltre: PromoCodeName.lefiltre,
+ ultimate: PromoCodeName.cloudoff,
+ annual: PromoCodeName.cloudoff,
};
interface OfferConfig {
@@ -62,6 +74,9 @@ interface OfferConfig {
alternateRecommendedPlan: boolean;
couponCode: PromoCodeName | undefined;
alternativeImages: string | null;
+ onlyUltimatePlan: boolean;
+ ultimateAndPremiumPlans: boolean;
+ annualPlans: boolean;
}
export const useOfferConfig = (pathname: string): OfferConfig => {
@@ -75,12 +90,18 @@ export const useOfferConfig = (pathname: string): OfferConfig => {
alternateRecommendedPlan: false,
couponCode: undefined,
alternativeImages: null,
+ onlyUltimatePlan: false,
+ ultimateAndPremiumPlans: false,
+ annualPlans: false,
};
}
const isDarkMode = DARK_MODE_PATHS.has(selectedPathname);
const alternateRecommendedPlan = !ALTERNATE_RECOMENDATED_PLAN_PATHS.has(selectedPathname);
const couponCode = COUPON_CODES[selectedPathname as keyof typeof COUPON_CODES];
+ const onlyUltimatePlan = ONLY_ULTIMATE_PLANS_PATHS.has(selectedPathname);
+ const ultimateAndPremiumPlans = ULTIMATE_PREMIUM_PLANS_PATHS.has(selectedPathname);
+ const annualPlans = ANNUAL_PLANS_PATHS.has(selectedPathname);
const alternativeImages = ALTERNATIVE_IMAGES_PATHS.has(selectedPathname)
? selectedPathname
@@ -92,6 +113,9 @@ export const useOfferConfig = (pathname: string): OfferConfig => {
alternateRecommendedPlan,
couponCode,
alternativeImages,
+ onlyUltimatePlan,
+ ultimateAndPremiumPlans,
+ annualPlans,
};
}, [pathname]);
};
diff --git a/src/lib/types/index.ts b/src/lib/types/index.ts
index 0877dc0be..f0de32223 100644
--- a/src/lib/types/index.ts
+++ b/src/lib/types/index.ts
@@ -206,6 +206,9 @@ export enum PromoCodeName {
love = 'LOVE88',
heisect = 'HEISECT',
devopstoolbox = 'DEVOPSTOOLBOX',
+ bjoern = 'BJOERN',
+ lefiltre = 'LEFILTRE',
+ cloudoff = 'CLOUDOFF',
}
export interface PromoCodeProps {
diff --git a/src/pages/[filename].tsx b/src/pages/[filename].tsx
index 1c305e5b0..e31187e6d 100644
--- a/src/pages/[filename].tsx
+++ b/src/pages/[filename].tsx
@@ -10,7 +10,7 @@ import TrustedSection from '@/components/home/TrustedSection';
import HorizontalScrollableSection from '@/components/home/HorizontalScrollableSection';
import FloatingCtaSectionv2 from '@/components/shared/FloatingCtaSectionV2';
import { PricingSectionWrapper } from '@/components/shared/pricing/PricingSectionWrapper';
-import { stripeService } from '@/services/stripe.service';
+import { Interval, stripeService } from '@/services/stripe.service';
import { SpecialOfferText } from '@/assets/types/specialOfferTemplate';
import { useOfferConfig, usePathRedirect } from '@/hooks/useSpecialOfferConfig';
import FeaturesSection from '@/components/drive/FeaturesSection';
@@ -72,6 +72,10 @@ const LANG_MAP = {
simon42: 'de',
heisect: 'de',
devopstoolbox: 'en',
+ bjoern: 'de',
+ lefiltre: 'fr',
+ annual: 'en',
+ ultimate: 'en',
};
function CombinedSpecialOffer({
@@ -82,8 +86,16 @@ function CombinedSpecialOffer({
navbarLang,
pathname,
}: CombinedSpecialOfferProps): JSX.Element {
- const { selectedPathname, isDarkMode, alternateRecommendedPlan, couponCode, alternativeImages } =
- useOfferConfig(pathname);
+ const {
+ selectedPathname,
+ isDarkMode,
+ alternateRecommendedPlan,
+ couponCode,
+ alternativeImages,
+ onlyUltimatePlan,
+ ultimateAndPremiumPlans,
+ annualPlans,
+ } = useOfferConfig(pathname);
const {
products,
loadingCards,
@@ -107,7 +119,7 @@ function CombinedSpecialOffer({
const decimalDiscountForLifetime = lifetimeCoupon?.percentOff && 100 - lifetimeCoupon.percentOff;
const percentOff = individualCoupon?.percentOff !== undefined ? String(individualCoupon.percentOff) : '0';
const themeClasses = getThemeClasses(isDarkMode);
-
+ const openerInterval = annualPlans ? Interval.Year : Interval.Lifetime;
const parsePercentText = (text: string) => {
if (!individualCoupon?.percentOff) {
return ;
@@ -145,7 +157,7 @@ function CombinedSpecialOffer({
return (
-
+