Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,11 @@ module.exports = {
destination: '/:path*',
permanent: true,
},
{
source: '/webdav',
destination: '/webdav-rclone',
permanent: true,
},
];
},
images: {
Expand Down
56 changes: 36 additions & 20 deletions src/components/shared/pricing/PricingSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ interface PriceTableProps {
onBusinessPlansSelected?: (isBusiness: boolean) => void;
differentRecommended?: boolean;
isValentinesMode?: boolean;
onlyUltimatePlan?: boolean;
premiumAndUltimatePlan?: boolean;
}

export const PricingSection = ({
Expand Down Expand Up @@ -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');

Expand Down Expand Up @@ -183,28 +187,40 @@ export const PricingSection = ({
enterTo="scale-100 translate-y-0 opacity-100"
className="flex flex-col gap-4"
>
<div className="content grid w-full grid-cols-3 items-stretch gap-6 ">
<div className="content flex w-full flex-wrap items-stretch justify-center gap-6">
{products?.individuals
? products.individuals[billingFrequency].map((product, cardIndex) => (
<PriceCard
isCheckoutForLifetime={billingFrequency === Interval.Lifetime}
product={product}
onCheckoutButtonClicked={onCheckoutButtonClicked}
label={product.storage}
key={product.storage}
popular={product.storage === popularPlan}
productCardPlan="individuals"
decimalDiscountValue={
product.interval === Interval.Lifetime ? decimalDiscount?.lifetime : decimalDiscount?.subscriptions
? products.individuals[billingFrequency]
.filter((product) => {
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) => (
<PriceCard
isCheckoutForLifetime={billingFrequency === Interval.Lifetime}
product={product}
onCheckoutButtonClicked={onCheckoutButtonClicked}
label={product.storage}
key={product.storage}
popular={product.storage === popularPlan}
productCardPlan="individuals"
decimalDiscountValue={
product.interval === Interval.Lifetime
? decimalDiscount?.lifetime
: decimalDiscount?.subscriptions
}
lang={lang}
darkMode={darkMode}
isAffiliate={isAffiliate}
cardIndex={cardIndex}
showGift={showPromo}
isValentinesMode={isValentinesMode}
/>
))
: undefined}
</div>
</Transition>
Expand Down
6 changes: 6 additions & 0 deletions src/components/shared/pricing/PricingSectionWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ interface PricingSectionWrapperProps {
overrideOnBusinessSwitchToggled?: (interval: Interval) => void;
differentRecommended?: boolean;
SectionTag?: React.ElementType;
onlyUltimatePlan?: boolean;
premiumAndUltimatePlan?: boolean;
}

const calculateDiscountPercentage = (decimalValue?: number) => {
Expand Down Expand Up @@ -194,6 +196,8 @@ export const PricingSectionWrapper = ({
overrideOnBusinessSwitchToggled,
differentRecommended,
SectionTag = DEFAULTS.SectionTag,
onlyUltimatePlan = false,
premiumAndUltimatePlan = false,
}: PricingSectionWrapperProps): JSX.Element => {
const localPlanSelection = usePlanSelection(
startFromPlan,
Expand Down Expand Up @@ -280,6 +284,8 @@ export const PricingSectionWrapper = ({
differentRecommended={differentRecommended}
showPromo={showPromo}
isValentinesMode={isValentinesMode}
onlyUltimatePlan={onlyUltimatePlan}
premiumAndUltimatePlan={premiumAndUltimatePlan}
/>
</div>

Expand Down
24 changes: 24 additions & 0 deletions src/hooks/useSpecialOfferConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,18 @@ export const ALLOWED_PATHS = [
'simon42',
'devopstoolbox',
'heisect',
'bjoern',
'lefiltre',
'ultimate',
'annual',
];
export const ALTERNATE_RECOMENDATED_PLAN_PATHS = new Set<string>([]);
export const DARK_MODE_PATHS = new Set<string>(['baity', 'xavier', 'oscar', 'rimembah', 'believemy', 'ghareeb']);
export const ALTERNATIVE_IMAGES_PATHS = new Set<string>(['baity']);
export const ONLY_ULTIMATE_PLANS_PATHS = new Set<string>(['ultimate']);
export const ULTIMATE_PREMIUM_PLANS_PATHS = new Set<string>(['annual']);
export const ANNUAL_PLANS_PATHS = new Set<string>(['annual', 'ultimate']);

export const COUPON_CODES = {
baity: PromoCodeName.BaityBait,
xavier: PromoCodeName.Xavier,
Expand All @@ -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 {
Expand All @@ -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 => {
Expand All @@ -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
Expand All @@ -92,6 +113,9 @@ export const useOfferConfig = (pathname: string): OfferConfig => {
alternateRecommendedPlan,
couponCode,
alternativeImages,
onlyUltimatePlan,
ultimateAndPremiumPlans,
annualPlans,
};
}, [pathname]);
};
Expand Down
3 changes: 3 additions & 0 deletions src/lib/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,9 @@ export enum PromoCodeName {
love = 'LOVE88',
heisect = 'HEISECT',
devopstoolbox = 'DEVOPSTOOLBOX',
bjoern = 'BJOERN',
lefiltre = 'LEFILTRE',
cloudoff = 'CLOUDOFF',
}

export interface PromoCodeProps {
Expand Down
28 changes: 22 additions & 6 deletions src/pages/[filename].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -72,6 +72,10 @@ const LANG_MAP = {
simon42: 'de',
heisect: 'de',
devopstoolbox: 'en',
bjoern: 'de',
lefiltre: 'fr',
annual: 'en',
ultimate: 'en',
};

function CombinedSpecialOffer({
Expand All @@ -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,
Expand All @@ -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 <div className="bg-gray-200 h-4 w-16 animate-pulse rounded"></div>;
Expand Down Expand Up @@ -145,7 +157,7 @@ function CombinedSpecialOffer({

return (
<Layout title={metatags!.title} description={metatags!.description} segmentName="Partners" lang={lang}>
<Navbar lang={lang} textContent={navbarLang} cta={['payment']} isLinksHidden hideCTA />
<Navbar lang={lang} textContent={navbarLang} cta={['payment']} isLinksHidden hideCTA hideLogoLink />

<HeroSection
textContent={langJson.HeroSection}
Expand All @@ -169,11 +181,15 @@ function CombinedSpecialOffer({
onCheckoutButtonClicked={onCheckoutButtonClicked}
hideBusinessCards
hideBusinessSelector
popularPlanBySize="3TB"
popularPlanBySize="5TB"
sectionDetails={`${themeClasses.sectionBg} lg:py-20`}
hideFreeCard
darkMode={isDarkMode}
differentRecommended={alternateRecommendedPlan}
onlyUltimatePlan={onlyUltimatePlan}
premiumAndUltimatePlan={ultimateAndPremiumPlans}
startIndividualPlansFromInterval={openerInterval}
hidePlanSelectorComponent={annualPlans}
/>

<FeaturesSection
Expand Down
Loading