Add order CTA links on packages overview

This commit is contained in:
Codex Agent
2026-01-21 22:07:46 +01:00
parent 80dd12bb92
commit ff34175dc3
4 changed files with 75 additions and 13 deletions

View File

@@ -673,6 +673,7 @@ interface PackageCardProps {
variant: 'endcustomer' | 'reseller'; variant: 'endcustomer' | 'reseller';
highlight?: boolean; highlight?: boolean;
onSelect?: (pkg: Package) => void; onSelect?: (pkg: Package) => void;
onCtaClick?: (pkg: Package, variant: 'endcustomer' | 'reseller') => void;
className?: string; className?: string;
showCTA?: boolean; showCTA?: boolean;
ctaLabel?: string; ctaLabel?: string;
@@ -684,6 +685,7 @@ function PackageCard({
variant, variant,
highlight = false, highlight = false,
onSelect, onSelect,
onCtaClick,
className, className,
showCTA = true, showCTA = true,
ctaLabel, ctaLabel,
@@ -691,9 +693,12 @@ function PackageCard({
}: PackageCardProps) { }: PackageCardProps) {
const { t } = useTranslation('marketing'); const { t } = useTranslation('marketing');
const { t: tCommon } = useTranslation('common'); const { t: tCommon } = useTranslation('common');
const { localizedPath } = useLocalizedRoutes();
const accent = getAccentTheme(variant); const accent = getAccentTheme(variant);
const purchaseUrl = localizedPath(`/bestellen/${pkg.id}`);
const numericPrice = Number(pkg.price); const numericPrice = Number(pkg.price);
const priceLabel = const priceLabel =
numericPrice === 0 numericPrice === 0
@@ -806,18 +811,41 @@ function PackageCard({
</CardContent> </CardContent>
{showCTA && onSelect && ( {showCTA && onSelect && (
<CardFooter className={cn('mt-auto', compact && 'pt-4')}> <CardFooter className={cn('mt-auto', compact && 'pt-4')}>
<Button <div className="grid w-full grid-cols-[2fr_1fr] gap-2">
onClick={() => onSelect(pkg)} <Button
className={cn( asChild
'w-full justify-center rounded-full text-sm font-semibold', className={cn(
highlight ? accent.buttonHighlight : accent.buttonDefault, 'w-full justify-center rounded-full text-sm font-semibold',
compact && 'py-4 text-base', highlight
)} ? accent.buttonHighlight
variant={highlight ? 'default' : 'outline'} : 'bg-gray-900 text-white hover:bg-gray-800 dark:bg-gray-100 dark:text-gray-900 dark:hover:bg-white',
> compact && 'py-4 text-base',
{ctaLabel ?? t('packages.view_details')} )}
<ArrowRight className="h-4 w-4" aria-hidden /> variant="default"
</Button> >
<Link
href={purchaseUrl}
onClick={() => {
onCtaClick?.(pkg, variant);
localStorage.setItem('preferred_package', JSON.stringify(pkg));
}}
>
{t('packages.to_order')}
</Link>
</Button>
<Button
onClick={() => onSelect(pkg)}
className={cn(
'w-full justify-center rounded-full text-sm font-semibold',
accent.buttonDefault,
compact && 'py-4 text-base',
)}
variant="outline"
>
{ctaLabel ?? t('packages.view_details')}
<ArrowRight className="h-4 w-4" aria-hidden />
</Button>
</div>
</CardFooter> </CardFooter>
)} )}
</Card> </Card>
@@ -1072,6 +1100,7 @@ const PackageDetailGrid: React.FC<PackageDetailGridProps> = ({
variant="endcustomer" variant="endcustomer"
highlight={pkg.id === highlightEndcustomerId} highlight={pkg.id === highlightEndcustomerId}
onSelect={(selected) => handleCardClick(selected, 'endcustomer')} onSelect={(selected) => handleCardClick(selected, 'endcustomer')}
onCtaClick={handleCtaClick}
className="h-full" className="h-full"
compact compact
/> />
@@ -1095,6 +1124,7 @@ const PackageDetailGrid: React.FC<PackageDetailGridProps> = ({
variant="endcustomer" variant="endcustomer"
highlight={pkg.id === highlightEndcustomerId} highlight={pkg.id === highlightEndcustomerId}
onSelect={(selected) => handleCardClick(selected, 'endcustomer')} onSelect={(selected) => handleCardClick(selected, 'endcustomer')}
onCtaClick={handleCtaClick}
className="h-full" className="h-full"
compact compact
/> />
@@ -1124,6 +1154,7 @@ const PackageDetailGrid: React.FC<PackageDetailGridProps> = ({
variant="reseller" variant="reseller"
highlight={pkg.id === highlightResellerId} highlight={pkg.id === highlightResellerId}
onSelect={(selected) => handleCardClick(selected, 'reseller')} onSelect={(selected) => handleCardClick(selected, 'reseller')}
onCtaClick={handleCtaClick}
className="h-full" className="h-full"
compact compact
/> />
@@ -1147,6 +1178,7 @@ const PackageDetailGrid: React.FC<PackageDetailGridProps> = ({
variant="reseller" variant="reseller"
highlight={pkg.id === highlightResellerId} highlight={pkg.id === highlightResellerId}
onSelect={(selected) => handleCardClick(selected, 'reseller')} onSelect={(selected) => handleCardClick(selected, 'reseller')}
onCtaClick={handleCtaClick}
className="h-full" className="h-full"
compact compact
/> />

View File

@@ -71,6 +71,7 @@
"gallery_days": "Tage Galerie", "gallery_days": "Tage Galerie",
"max_events_year": "Events enthalten", "max_events_year": "Events enthalten",
"recommended_usage_window": "Empfohlen innerhalb von 24 Monaten zu nutzen.", "recommended_usage_window": "Empfohlen innerhalb von 24 Monaten zu nutzen.",
"to_order": "Bestellen",
"buy_now": "Jetzt kaufen", "buy_now": "Jetzt kaufen",
"subscribe_now": "Jetzt kaufen", "subscribe_now": "Jetzt kaufen",
"register_buy": "Registrieren und kaufen", "register_buy": "Registrieren und kaufen",

View File

@@ -71,6 +71,7 @@
"gallery_days": "Gallery Days", "gallery_days": "Gallery Days",
"max_events_year": "Events included", "max_events_year": "Events included",
"recommended_usage_window": "Recommended to use within 24 months.", "recommended_usage_window": "Recommended to use within 24 months.",
"to_order": "Order now",
"buy_now": "Buy Now", "buy_now": "Buy Now",
"subscribe_now": "Buy Now", "subscribe_now": "Buy Now",
"register_buy": "Register and Buy", "register_buy": "Register and Buy",

View File

@@ -0,0 +1,28 @@
<?php
namespace Tests\Feature\Marketing;
use App\Models\Package;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Inertia\Testing\AssertableInertia as Assert;
use Tests\TestCase;
class PackagesPageTest extends TestCase
{
use RefreshDatabase;
public function test_packages_page_renders_available_packages(): void
{
Package::factory()->count(2)->endcustomer()->create();
Package::factory()->count(1)->reseller()->create();
$response = $this->get('/de/packages');
$response->assertOk();
$response->assertInertia(fn (Assert $page) => $page
->component('marketing/Packages')
->has('endcustomerPackages', 2)
->has('resellerPackages', 1)
);
}
}