Update marketing packages and checkout copy
This commit is contained in:
@@ -252,7 +252,7 @@ export default function RegisterForm({ packageId, onSuccess, privacyHtml, locale
|
||||
<div className="space-y-6">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<div className="md:col-span-1">
|
||||
<label htmlFor="first_name" className="block text-sm font-medium text-gray-700 mb-1">
|
||||
<label htmlFor="first_name" className="block text-sm font-medium text-gray-700 dark:text-gray-100 mb-1">
|
||||
{t('register.first_name')} {t('common:required')}
|
||||
</label>
|
||||
<div className="relative">
|
||||
@@ -269,7 +269,7 @@ export default function RegisterForm({ packageId, onSuccess, privacyHtml, locale
|
||||
clearErrors('first_name');
|
||||
}
|
||||
}}
|
||||
className={`block w-full pl-10 pr-3 py-3 border rounded-md shadow-sm placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-[#FFB6C1] focus:border-[#FFB6C1] sm:text-sm ${errors.first_name ? 'border-red-500' : 'border-gray-300'}`}
|
||||
className={`block w-full pl-10 pr-3 py-3 border rounded-md shadow-sm placeholder-gray-400 dark:placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-[#FFB6C1] focus:border-[#FFB6C1] sm:text-sm dark:bg-gray-900 dark:text-gray-100 ${errors.first_name ? 'border-red-500' : 'border-gray-300 dark:border-gray-700'}`}
|
||||
placeholder={t('register.first_name_placeholder')}
|
||||
/>
|
||||
</div>
|
||||
@@ -277,7 +277,7 @@ export default function RegisterForm({ packageId, onSuccess, privacyHtml, locale
|
||||
</div>
|
||||
|
||||
<div className="md:col-span-1">
|
||||
<label htmlFor="last_name" className="block text-sm font-medium text-gray-700 mb-1">
|
||||
<label htmlFor="last_name" className="block text-sm font-medium text-gray-700 dark:text-gray-100 mb-1">
|
||||
{t('register.last_name')} {t('common:required')}
|
||||
</label>
|
||||
<div className="relative">
|
||||
@@ -294,7 +294,7 @@ export default function RegisterForm({ packageId, onSuccess, privacyHtml, locale
|
||||
clearErrors('last_name');
|
||||
}
|
||||
}}
|
||||
className={`block w-full pl-10 pr-3 py-3 border rounded-md shadow-sm placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-[#FFB6C1] focus:border-[#FFB6C1] sm:text-sm ${errors.last_name ? 'border-red-500' : 'border-gray-300'}`}
|
||||
className={`block w-full pl-10 pr-3 py-3 border rounded-md shadow-sm placeholder-gray-400 dark:placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-[#FFB6C1] focus:border-[#FFB6C1] sm:text-sm dark:bg-gray-900 dark:text-gray-100 ${errors.last_name ? 'border-red-500' : 'border-gray-300 dark:border-gray-700'}`}
|
||||
placeholder={t('register.last_name_placeholder')}
|
||||
/>
|
||||
</div>
|
||||
@@ -302,7 +302,7 @@ export default function RegisterForm({ packageId, onSuccess, privacyHtml, locale
|
||||
</div>
|
||||
|
||||
<div className="md:col-span-2">
|
||||
<label htmlFor="email" className="block text-sm font-medium text-gray-700 mb-1">
|
||||
<label htmlFor="email" className="block text-sm font-medium text-gray-700 dark:text-gray-100 mb-1">
|
||||
{t('register.email')} {t('common:required')}
|
||||
</label>
|
||||
<div className="relative">
|
||||
@@ -319,7 +319,7 @@ export default function RegisterForm({ packageId, onSuccess, privacyHtml, locale
|
||||
clearErrors('email');
|
||||
}
|
||||
}}
|
||||
className={`block w-full pl-10 pr-3 py-3 border rounded-md shadow-sm placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-[#FFB6C1] focus:border-[#FFB6C1] sm:text-sm ${errors.email ? 'border-red-500' : 'border-gray-300'}`}
|
||||
className={`block w-full pl-10 pr-3 py-3 border rounded-md shadow-sm placeholder-gray-400 dark:placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-[#FFB6C1] focus:border-[#FFB6C1] sm:text-sm dark:bg-gray-900 dark:text-gray-100 ${errors.email ? 'border-red-500' : 'border-gray-300 dark:border-gray-700'}`}
|
||||
placeholder={t('register.email_placeholder')}
|
||||
/>
|
||||
</div>
|
||||
@@ -327,7 +327,7 @@ export default function RegisterForm({ packageId, onSuccess, privacyHtml, locale
|
||||
</div>
|
||||
|
||||
<div className="md:col-span-1">
|
||||
<label htmlFor="password" className="block text-sm font-medium text-gray-700 mb-1">
|
||||
<label htmlFor="password" className="block text-sm font-medium text-gray-700 dark:text-gray-100 mb-1">
|
||||
{t('register.password')} {t('common:required')}
|
||||
</label>
|
||||
<div className="relative">
|
||||
@@ -347,7 +347,7 @@ export default function RegisterForm({ packageId, onSuccess, privacyHtml, locale
|
||||
clearErrors('password_confirmation');
|
||||
}
|
||||
}}
|
||||
className={`block w-full pl-10 pr-3 py-3 border rounded-md shadow-sm placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-[#FFB6C1] focus:border-[#FFB6C1] sm:text-sm ${errors.password ? 'border-red-500' : 'border-gray-300'}`}
|
||||
className={`block w-full pl-10 pr-3 py-3 border rounded-md shadow-sm placeholder-gray-400 dark:placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-[#FFB6C1] focus:border-[#FFB6C1] sm:text-sm dark:bg-gray-900 dark:text-gray-100 ${errors.password ? 'border-red-500' : 'border-gray-300 dark:border-gray-700'}`}
|
||||
placeholder={t('register.password_placeholder')}
|
||||
/>
|
||||
</div>
|
||||
@@ -355,7 +355,7 @@ export default function RegisterForm({ packageId, onSuccess, privacyHtml, locale
|
||||
</div>
|
||||
|
||||
<div className="md:col-span-1">
|
||||
<label htmlFor="password_confirmation" className="block text-sm font-medium text-gray-700 mb-1">
|
||||
<label htmlFor="password_confirmation" className="block text-sm font-medium text-gray-700 dark:text-gray-100 mb-1">
|
||||
{t('register.password_confirmation')} {t('common:required')}
|
||||
</label>
|
||||
<div className="relative">
|
||||
@@ -375,7 +375,7 @@ export default function RegisterForm({ packageId, onSuccess, privacyHtml, locale
|
||||
clearErrors('password_confirmation');
|
||||
}
|
||||
}}
|
||||
className={`block w-full pl-10 pr-3 py-3 border rounded-md shadow-sm placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-[#FFB6C1] focus:border-[#FFB6C1] sm:text-sm ${errors.password_confirmation ? 'border-red-500' : 'border-gray-300'}`}
|
||||
className={`block w-full pl-10 pr-3 py-3 border rounded-md shadow-sm placeholder-gray-400 dark:placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-[#FFB6C1] focus:border-[#FFB6C1] sm:text-sm dark:bg-gray-900 dark:text-gray-100 ${errors.password_confirmation ? 'border-red-500' : 'border-gray-300 dark:border-gray-700'}`}
|
||||
placeholder={t('register.password_confirmation_placeholder')}
|
||||
/>
|
||||
</div>
|
||||
@@ -399,14 +399,14 @@ export default function RegisterForm({ packageId, onSuccess, privacyHtml, locale
|
||||
clearErrors('terms');
|
||||
}
|
||||
}}
|
||||
className="h-4 w-4 text-[#FFB6C1] focus:ring-[#FFB6C1] border-gray-300 rounded"
|
||||
className="h-4 w-4 text-[#FFB6C1] focus:ring-[#FFB6C1] border-gray-300 dark:border-gray-600 rounded"
|
||||
/>
|
||||
<label htmlFor="privacy_consent" className="ml-2 block text-sm text-gray-900">
|
||||
<label htmlFor="privacy_consent" className="ml-2 block text-sm text-gray-900 dark:text-gray-100">
|
||||
{t('register.privacy_consent')}{' '}
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setPrivacyOpen(true)}
|
||||
className="text-[#FFB6C1] hover:underline inline bg-transparent border-none cursor-pointer p-0 font-medium"
|
||||
className="text-[#FFB6C1] hover:underline inline bg-transparent border-none cursor-pointer p-0 font-medium dark:text-pink-300"
|
||||
>
|
||||
{t('register.privacy_policy_link')}
|
||||
</button>.
|
||||
|
||||
@@ -664,7 +664,7 @@ const resolveServiceTierLabel = (slug: string | null | undefined): string => {
|
||||
}
|
||||
|
||||
if (slug === 'standard') {
|
||||
return 'Standard';
|
||||
return 'Classic';
|
||||
}
|
||||
|
||||
if (slug === 'pro') {
|
||||
@@ -784,7 +784,7 @@ function PackageCard({
|
||||
: null;
|
||||
|
||||
const displayFeatures = buildDisplayFeatures(pkg, variant);
|
||||
const visibleFeatures = compact ? displayFeatures.slice(0, 3) : displayFeatures.slice(0, 5);
|
||||
const visibleFeatures = displayFeatures.slice(0, 5);
|
||||
const metrics = resolvePackageMetrics(pkg, variant, t, tCommon);
|
||||
|
||||
const metricList = (
|
||||
@@ -1200,18 +1200,6 @@ const PackageDetailGrid: React.FC<PackageDetailGridProps> = ({
|
||||
{t('packages.hero_description')}
|
||||
</p>
|
||||
</motion.div>
|
||||
<motion.div className="flex justify-center md:justify-end" variants={revealUp}>
|
||||
<Link
|
||||
href={localizedPath(locale === 'en' ? '/gift-card' : '/gutschein')}
|
||||
className="group inline-flex items-center gap-3 rounded-full border border-white/50 bg-white/70 px-4 py-2 text-xs font-semibold uppercase tracking-[0.2em] text-gray-700 shadow-sm backdrop-blur transition hover:bg-white/90 dark:border-gray-800 dark:bg-gray-900/70 dark:text-gray-100"
|
||||
>
|
||||
<span className="flex h-8 w-8 items-center justify-center rounded-full bg-pink-500/15 text-pink-600 dark:text-pink-300">
|
||||
<Gift className="h-4 w-4" aria-hidden />
|
||||
</span>
|
||||
<span>{t('packages.gift_cta')}</span>
|
||||
<ArrowRight className="h-3.5 w-3.5 text-gray-400 transition group-hover:translate-x-1" aria-hidden />
|
||||
</Link>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
</section>
|
||||
|
||||
@@ -1238,26 +1226,24 @@ const PackageDetailGrid: React.FC<PackageDetailGridProps> = ({
|
||||
<TabsContent value="endcustomer" className="space-y-8 pt-8">
|
||||
<div className="md:hidden">
|
||||
<div className="relative">
|
||||
<div className="pointer-events-none absolute inset-y-0 left-0 w-6 bg-gradient-to-r from-white to-transparent dark:from-gray-950" />
|
||||
<div className="pointer-events-none absolute inset-y-0 right-0 w-6 bg-gradient-to-l from-white to-transparent dark:from-gray-950" />
|
||||
<div className="pointer-events-none absolute inset-y-0 left-0 w-4 bg-gradient-to-r from-white/70 to-transparent dark:from-gray-950/70" />
|
||||
<div className="pointer-events-none absolute inset-y-0 right-0 w-4 bg-gradient-to-l from-white/70 to-transparent dark:from-gray-950/70" />
|
||||
<div
|
||||
ref={mobileEndcustomerRef}
|
||||
className="flex snap-x snap-mandatory gap-4 overflow-x-auto pb-6"
|
||||
style={{ scrollPaddingLeft: '16px', scrollBehavior: 'smooth' }}
|
||||
style={{ scrollPaddingLeft: '16px', scrollPaddingRight: '16px', scrollBehavior: 'smooth' }}
|
||||
>
|
||||
{orderedEndcustomerPackages.map((pkg) => (
|
||||
<div key={pkg.id} className="snap-start basis-[72vw] shrink-0 sm:basis-[60vw]">
|
||||
<motion.div variants={revealUp} initial="hidden" whileInView="visible" viewport={viewportOnce}>
|
||||
<PackageCard
|
||||
pkg={pkg}
|
||||
variant="endcustomer"
|
||||
highlight={pkg.id === highlightEndcustomerId}
|
||||
onSelect={(selected) => handleCardClick(selected, 'endcustomer')}
|
||||
onCtaClick={handleCtaClick}
|
||||
className="h-full"
|
||||
compact
|
||||
/>
|
||||
</motion.div>
|
||||
<div key={pkg.id} className="snap-center basis-[64vw] shrink-0 sm:basis-[56vw]">
|
||||
<PackageCard
|
||||
pkg={pkg}
|
||||
variant="endcustomer"
|
||||
highlight={pkg.id === highlightEndcustomerId}
|
||||
onSelect={(selected) => handleCardClick(selected, 'endcustomer')}
|
||||
onCtaClick={handleCtaClick}
|
||||
className="h-full"
|
||||
compact
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
@@ -1319,26 +1305,24 @@ const PackageDetailGrid: React.FC<PackageDetailGridProps> = ({
|
||||
</motion.div>
|
||||
<div className="md:hidden">
|
||||
<div className="relative">
|
||||
<div className="pointer-events-none absolute inset-y-0 left-0 w-6 bg-gradient-to-r from-white to-transparent dark:from-gray-950" />
|
||||
<div className="pointer-events-none absolute inset-y-0 right-0 w-6 bg-gradient-to-l from-white to-transparent dark:from-gray-950" />
|
||||
<div className="pointer-events-none absolute inset-y-0 left-0 w-4 bg-gradient-to-r from-white/70 to-transparent dark:from-gray-950/70" />
|
||||
<div className="pointer-events-none absolute inset-y-0 right-0 w-4 bg-gradient-to-l from-white/70 to-transparent dark:from-gray-950/70" />
|
||||
<div
|
||||
ref={mobileResellerRef}
|
||||
className="flex snap-x snap-mandatory gap-4 overflow-x-auto pb-6"
|
||||
style={{ scrollPaddingLeft: '16px', scrollBehavior: 'smooth' }}
|
||||
style={{ scrollPaddingLeft: '16px', scrollPaddingRight: '16px', scrollBehavior: 'smooth' }}
|
||||
>
|
||||
{orderedResellerPackages.map((pkg) => (
|
||||
<div key={pkg.id} className="snap-start basis-[72vw] shrink-0 sm:basis-[60vw]">
|
||||
<motion.div variants={revealUp} initial="hidden" whileInView="visible" viewport={viewportOnce}>
|
||||
<PackageCard
|
||||
pkg={pkg}
|
||||
variant="reseller"
|
||||
highlight={pkg.id === highlightResellerId}
|
||||
onSelect={(selected) => handleCardClick(selected, 'reseller')}
|
||||
onCtaClick={handleCtaClick}
|
||||
className="h-full"
|
||||
compact
|
||||
/>
|
||||
</motion.div>
|
||||
<div key={pkg.id} className="snap-center basis-[64vw] shrink-0 sm:basis-[56vw]">
|
||||
<PackageCard
|
||||
pkg={pkg}
|
||||
variant="reseller"
|
||||
highlight={pkg.id === highlightResellerId}
|
||||
onSelect={(selected) => handleCardClick(selected, 'reseller')}
|
||||
onCtaClick={handleCtaClick}
|
||||
className="h-full"
|
||||
compact
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
@@ -1386,6 +1370,19 @@ const PackageDetailGrid: React.FC<PackageDetailGridProps> = ({
|
||||
<PackageComparison packages={orderedResellerPackages} variant="reseller" serviceTierNames={serviceTierNames} />
|
||||
</motion.div>
|
||||
</TabsContent>
|
||||
|
||||
<div className="flex justify-center pt-2 md:pt-6">
|
||||
<Link
|
||||
href={localizedPath(locale === 'en' ? '/gift-card' : '/gutschein')}
|
||||
className="group inline-flex items-center gap-3 rounded-full border border-gray-200 bg-white px-4 py-2 text-xs font-semibold uppercase tracking-[0.2em] text-gray-700 shadow-sm transition hover:bg-gray-50 dark:border-gray-800 dark:bg-gray-900 dark:text-gray-100 dark:hover:bg-gray-900/80"
|
||||
>
|
||||
<span className="flex h-8 w-8 items-center justify-center rounded-full bg-pink-500/15 text-pink-600 dark:text-pink-300">
|
||||
<Gift className="h-4 w-4" aria-hidden />
|
||||
</span>
|
||||
<span>{t('packages.gift_cta')}</span>
|
||||
<ArrowRight className="h-3.5 w-3.5 text-gray-400 transition group-hover:translate-x-1" aria-hidden />
|
||||
</Link>
|
||||
</div>
|
||||
</Tabs>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -72,7 +72,7 @@ describe('Home', () => {
|
||||
<Home
|
||||
packages={[
|
||||
{ id: 1, name: 'Starter', description: 'Desc', price: 29 },
|
||||
{ id: 2, name: 'Standard', description: 'Desc', price: 59 },
|
||||
{ id: 2, name: 'Classic', description: 'Desc', price: 59 },
|
||||
]}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -104,7 +104,7 @@ describe('Packages', () => {
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'Standard',
|
||||
name: 'Classic',
|
||||
slug: 'standard',
|
||||
description: 'Desc',
|
||||
description_breakdown: [],
|
||||
|
||||
Reference in New Issue
Block a user