Update marketing packages and checkout copy
This commit is contained in:
@@ -38,6 +38,9 @@ This repository hosts a multi-tenant event photo platform (Laravel 12, PHP 8.3,
|
|||||||
- resources/js/admin/ — Tenant Admin PWA source (React 19, Capacitor/TWA ready).
|
- resources/js/admin/ — Tenant Admin PWA source (React 19, Capacitor/TWA ready).
|
||||||
- resources/js/pages/ — Inertia pages (React).
|
- resources/js/pages/ — Inertia pages (React).
|
||||||
- docs/archive/README.md — historical PRP context.
|
- docs/archive/README.md — historical PRP context.
|
||||||
|
- Marketing frontend language files:
|
||||||
|
- Source translations: `resources/lang/{de,en}/marketing.php` and `resources/lang/{de,en}/marketing.json`.
|
||||||
|
- Runtime i18next JSON served to the frontend: `public/lang/{de,en}/marketing.json` (must stay in sync with the source files).
|
||||||
|
|
||||||
## Standard Workflows
|
## Standard Workflows
|
||||||
- Coding tasks (Codegen Agent):
|
- Coding tasks (Codegen Agent):
|
||||||
|
|||||||
@@ -30,21 +30,21 @@ return [
|
|||||||
],
|
],
|
||||||
[
|
[
|
||||||
'key' => 'gift-standard',
|
'key' => 'gift-standard',
|
||||||
'label' => 'Geschenk Standard',
|
'label' => 'Geschenk Classic',
|
||||||
'amount' => 59.00,
|
'amount' => 59.00,
|
||||||
'currency' => 'EUR',
|
'currency' => 'EUR',
|
||||||
'paddle_price_id' => env('PADDLE_GIFT_PRICE_STANDARD', 'pri_01kbwccfvzrf4z2f1r62vns7gh'),
|
'paddle_price_id' => env('PADDLE_GIFT_PRICE_STANDARD', 'pri_01kbwccfvzrf4z2f1r62vns7gh'),
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'key' => 'gift-standard-usd',
|
'key' => 'gift-standard-usd',
|
||||||
'label' => 'Gift Standard (USD)',
|
'label' => 'Gift Classic (USD)',
|
||||||
'amount' => 65.00,
|
'amount' => 65.00,
|
||||||
'currency' => 'USD',
|
'currency' => 'USD',
|
||||||
'paddle_price_id' => env('PADDLE_GIFT_PRICE_STANDARD_USD'),
|
'paddle_price_id' => env('PADDLE_GIFT_PRICE_STANDARD_USD'),
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'key' => 'gift-standard-gbp',
|
'key' => 'gift-standard-gbp',
|
||||||
'label' => 'Gift Standard (GBP)',
|
'label' => 'Gift Classic (GBP)',
|
||||||
'amount' => 55.00,
|
'amount' => 55.00,
|
||||||
'currency' => 'GBP',
|
'currency' => 'GBP',
|
||||||
'paddle_price_id' => env('PADDLE_GIFT_PRICE_STANDARD_GBP'),
|
'paddle_price_id' => env('PADDLE_GIFT_PRICE_STANDARD_GBP'),
|
||||||
@@ -70,27 +70,6 @@ return [
|
|||||||
'currency' => 'GBP',
|
'currency' => 'GBP',
|
||||||
'paddle_price_id' => env('PADDLE_GIFT_PRICE_PREMIUM_GBP'),
|
'paddle_price_id' => env('PADDLE_GIFT_PRICE_PREMIUM_GBP'),
|
||||||
],
|
],
|
||||||
[
|
|
||||||
'key' => 'gift-premium-plus',
|
|
||||||
'label' => 'Geschenk Premium Plus',
|
|
||||||
'amount' => 149.00,
|
|
||||||
'currency' => 'EUR',
|
|
||||||
'paddle_price_id' => env('PADDLE_GIFT_PRICE_PREMIUM_PLUS', 'pri_01kbwccgnjzwrjy5xg1yp981p6'),
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'key' => 'gift-premium-plus-usd',
|
|
||||||
'label' => 'Gift Premium Plus (USD)',
|
|
||||||
'amount' => 159.00,
|
|
||||||
'currency' => 'USD',
|
|
||||||
'paddle_price_id' => env('PADDLE_GIFT_PRICE_PREMIUM_PLUS_USD'),
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'key' => 'gift-premium-plus-gbp',
|
|
||||||
'label' => 'Gift Premium Plus (GBP)',
|
|
||||||
'amount' => 139.00,
|
|
||||||
'currency' => 'GBP',
|
|
||||||
'paddle_price_id' => env('PADDLE_GIFT_PRICE_PREMIUM_PLUS_GBP'),
|
|
||||||
],
|
|
||||||
],
|
],
|
||||||
|
|
||||||
// Package types a voucher coupon should apply to.
|
// Package types a voucher coupon should apply to.
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ class CouponSeeder extends Seeder
|
|||||||
[
|
[
|
||||||
'code' => 'UPGRADE30',
|
'code' => 'UPGRADE30',
|
||||||
'name' => 'Upgrade 30 €',
|
'name' => 'Upgrade 30 €',
|
||||||
'description' => '30 € Nachlass als Upgrade-Anreiz von Starter auf Standard/Premium.',
|
'description' => '30 € Nachlass als Upgrade-Anreiz von Starter auf Classic/Premium.',
|
||||||
'type' => CouponType::FLAT,
|
'type' => CouponType::FLAT,
|
||||||
'amount' => 30.00,
|
'amount' => 30.00,
|
||||||
'currency' => 'EUR',
|
'currency' => 'EUR',
|
||||||
@@ -77,7 +77,7 @@ class CouponSeeder extends Seeder
|
|||||||
[
|
[
|
||||||
'code' => 'SEASON50',
|
'code' => 'SEASON50',
|
||||||
'name' => 'Hochzeits-Saison 50 €',
|
'name' => 'Hochzeits-Saison 50 €',
|
||||||
'description' => 'Saisonaler 50 € Rabatt für die Hochzeitssaison auf Standard/Premium.',
|
'description' => 'Saisonaler 50 € Rabatt für die Hochzeitssaison auf Classic/Premium.',
|
||||||
'type' => CouponType::FLAT,
|
'type' => CouponType::FLAT,
|
||||||
'amount' => 50.00,
|
'amount' => 50.00,
|
||||||
'currency' => 'EUR',
|
'currency' => 'EUR',
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ class PackageSeeder extends Seeder
|
|||||||
'max_events_per_year' => 1,
|
'max_events_per_year' => 1,
|
||||||
'watermark_allowed' => false,
|
'watermark_allowed' => false,
|
||||||
'branding_allowed' => false,
|
'branding_allowed' => false,
|
||||||
'features' => ['basic_uploads', 'limited_sharing', 'custom_tasks'],
|
'features' => ['basic_uploads', 'limited_sharing', 'custom_tasks', 'live_slideshow'],
|
||||||
'paddle_product_id' => 'pro_01k8jcxx2g1vj9snqbga4283ej',
|
'paddle_product_id' => 'pro_01k8jcxx2g1vj9snqbga4283ej',
|
||||||
'paddle_price_id' => 'pri_01k8jcxx8qktxvqzzv0nkjjj27',
|
'paddle_price_id' => 'pri_01k8jcxx8qktxvqzzv0nkjjj27',
|
||||||
'description' => <<<'TEXT'
|
'description' => <<<'TEXT'
|
||||||
@@ -51,10 +51,10 @@ TEXT,
|
|||||||
],
|
],
|
||||||
[
|
[
|
||||||
'slug' => 'standard',
|
'slug' => 'standard',
|
||||||
'name' => 'Standard',
|
'name' => 'Classic',
|
||||||
'name_translations' => [
|
'name_translations' => [
|
||||||
'de' => 'Standard',
|
'de' => 'Classic',
|
||||||
'en' => 'Standard',
|
'en' => 'Classic',
|
||||||
],
|
],
|
||||||
'type' => PackageType::ENDCUSTOMER,
|
'type' => PackageType::ENDCUSTOMER,
|
||||||
'price' => 59.00,
|
'price' => 59.00,
|
||||||
@@ -151,10 +151,10 @@ TEXT,
|
|||||||
],
|
],
|
||||||
[
|
[
|
||||||
'slug' => 'm-medium-reseller',
|
'slug' => 'm-medium-reseller',
|
||||||
'name' => 'Partner Standard',
|
'name' => 'Partner Classic',
|
||||||
'name_translations' => [
|
'name_translations' => [
|
||||||
'de' => 'Partner Standard',
|
'de' => 'Partner Classic',
|
||||||
'en' => 'Partner Standard',
|
'en' => 'Partner Classic',
|
||||||
],
|
],
|
||||||
'type' => PackageType::RESELLER,
|
'type' => PackageType::RESELLER,
|
||||||
'included_package_slug' => 'standard',
|
'included_package_slug' => 'standard',
|
||||||
@@ -171,15 +171,15 @@ TEXT,
|
|||||||
'paddle_product_id' => 'pro_01k8jcxtrxw7jsew52jnax901q',
|
'paddle_product_id' => 'pro_01k8jcxtrxw7jsew52jnax901q',
|
||||||
'paddle_price_id' => 'pri_01k8jcxv06nsgy8ym8mnfrfm5v',
|
'paddle_price_id' => 'pri_01k8jcxv06nsgy8ym8mnfrfm5v',
|
||||||
'description' => <<<'TEXT'
|
'description' => <<<'TEXT'
|
||||||
Event-Kontingent für Partner / Agenturen: {{max_events_per_year}} Events auf Standard‑Niveau. Empfohlen innerhalb von 24 Monaten zu nutzen.
|
Event-Kontingent für Partner / Agenturen: {{max_events_per_year}} Events auf Classic‑Niveau. Empfohlen innerhalb von 24 Monaten zu nutzen.
|
||||||
TEXT,
|
TEXT,
|
||||||
'description_translations' => [
|
'description_translations' => [
|
||||||
'de' => 'Event-Kontingent für Partner / Agenturen: {{max_events_per_year}} Events auf Standard‑Niveau. Empfohlen innerhalb von 24 Monaten zu nutzen.',
|
'de' => 'Event-Kontingent für Partner / Agenturen: {{max_events_per_year}} Events auf Classic‑Niveau. Empfohlen innerhalb von 24 Monaten zu nutzen.',
|
||||||
'en' => 'Event-Kontingent for Partner / Agencies: {{max_events_per_year}} events at Standard level. Recommended to use within 24 months.',
|
'en' => 'Event-Kontingent for Partner / Agencies: {{max_events_per_year}} events at Classic level. Recommended to use within 24 months.',
|
||||||
],
|
],
|
||||||
'description_table' => [
|
'description_table' => [
|
||||||
['title' => 'Events', 'value' => '{{max_events_per_year}} Events'],
|
['title' => 'Events', 'value' => '{{max_events_per_year}} Events'],
|
||||||
['title' => 'Inklusive Event-Level', 'value' => 'Standard'],
|
['title' => 'Inklusive Event-Level', 'value' => 'Classic'],
|
||||||
['title' => 'Empfehlung', 'value' => 'Empfohlen innerhalb von 24 Monaten zu nutzen.'],
|
['title' => 'Empfehlung', 'value' => 'Empfohlen innerhalb von 24 Monaten zu nutzen.'],
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
@@ -273,15 +273,15 @@ TEXT,
|
|||||||
'paddle_product_id' => 'pro_01k8jct3gz9ks5mg6z61q6nrxb',
|
'paddle_product_id' => 'pro_01k8jct3gz9ks5mg6z61q6nrxb',
|
||||||
'paddle_price_id' => 'pri_01k8jcxsa8axwpjnybhjbcrb06',
|
'paddle_price_id' => 'pri_01k8jcxsa8axwpjnybhjbcrb06',
|
||||||
'description' => <<<'TEXT'
|
'description' => <<<'TEXT'
|
||||||
Event-Kontingent für Partner / Agenturen: {{max_events_per_year}} Events auf Standard‑Niveau. Empfohlen innerhalb von 24 Monaten zu nutzen.
|
Event-Kontingent für Partner / Agenturen: {{max_events_per_year}} Events auf Classic‑Niveau. Empfohlen innerhalb von 24 Monaten zu nutzen.
|
||||||
TEXT,
|
TEXT,
|
||||||
'description_translations' => [
|
'description_translations' => [
|
||||||
'de' => 'Event-Kontingent für Partner / Agenturen: {{max_events_per_year}} Events auf Standard‑Niveau. Empfohlen innerhalb von 24 Monaten zu nutzen.',
|
'de' => 'Event-Kontingent für Partner / Agenturen: {{max_events_per_year}} Events auf Classic‑Niveau. Empfohlen innerhalb von 24 Monaten zu nutzen.',
|
||||||
'en' => 'Event-Kontingent for Partner / Agencies: {{max_events_per_year}} events at Standard level. Recommended to use within 24 months.',
|
'en' => 'Event-Kontingent for Partner / Agencies: {{max_events_per_year}} events at Classic level. Recommended to use within 24 months.',
|
||||||
],
|
],
|
||||||
'description_table' => [
|
'description_table' => [
|
||||||
['title' => 'Events', 'value' => '{{max_events_per_year}} Events'],
|
['title' => 'Events', 'value' => '{{max_events_per_year}} Events'],
|
||||||
['title' => 'Inklusive Event-Level', 'value' => 'Standard'],
|
['title' => 'Inklusive Event-Level', 'value' => 'Classic'],
|
||||||
['title' => 'Empfehlung', 'value' => 'Empfohlen innerhalb von 24 Monaten zu nutzen.'],
|
['title' => 'Empfehlung', 'value' => 'Empfohlen innerhalb von 24 Monaten zu nutzen.'],
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -109,7 +109,7 @@
|
|||||||
"priority_support": "Priorisierter Support",
|
"priority_support": "Priorisierter Support",
|
||||||
"cancel_link": "Paket verwalten: :link",
|
"cancel_link": "Paket verwalten: :link",
|
||||||
"hero_kicker": "Pakete, die mit eurem Event mitwachsen",
|
"hero_kicker": "Pakete, die mit eurem Event mitwachsen",
|
||||||
"hero_title": "Entdecken Sie unsere flexiblen Packages",
|
"hero_title": "Entdecken Sie unsere flexiblen Event-Pakete",
|
||||||
"hero_description": "Von kostenlosem Einstieg bis Premium-Features: Passen Sie Ihr Event-Paket an Ihre Bedürfnisse an. Einfach, sicher und skalierbar.",
|
"hero_description": "Von kostenlosem Einstieg bis Premium-Features: Passen Sie Ihr Event-Paket an Ihre Bedürfnisse an. Einfach, sicher und skalierbar.",
|
||||||
"hero_secondary": "Teste den kompletten Gäste-Flow in unserer Live-Demo – kein Login, kein App-Store.",
|
"hero_secondary": "Teste den kompletten Gäste-Flow in unserer Live-Demo – kein Login, kein App-Store.",
|
||||||
"cta_demo": "Demo ansehen",
|
"cta_demo": "Demo ansehen",
|
||||||
@@ -117,7 +117,7 @@
|
|||||||
"cta_explore_highlight": "Lieblingspaket sichern",
|
"cta_explore_highlight": "Lieblingspaket sichern",
|
||||||
"gift_cta": "Paket verschenken",
|
"gift_cta": "Paket verschenken",
|
||||||
"tab_endcustomer": "Einzel-Events",
|
"tab_endcustomer": "Einzel-Events",
|
||||||
"tab_reseller": "Partner / Agentur",
|
"tab_reseller": "mehrere Events",
|
||||||
"section_endcustomer": "Packages für Endkunden (Einmalkauf pro Event)",
|
"section_endcustomer": "Packages für Endkunden (Einmalkauf pro Event)",
|
||||||
"section_reseller": "Packages für Partner / Agenturen (Event-Kontingent)",
|
"section_reseller": "Packages für Partner / Agenturen (Event-Kontingent)",
|
||||||
"bundles_title": "Partner & Agentur Bundles",
|
"bundles_title": "Partner & Agentur Bundles",
|
||||||
@@ -156,7 +156,7 @@
|
|||||||
"feature_watermark_custom": "Eigenes Wasserzeichen",
|
"feature_watermark_custom": "Eigenes Wasserzeichen",
|
||||||
"feature_branding": "Branding",
|
"feature_branding": "Branding",
|
||||||
"feature_support": "Support",
|
"feature_support": "Support",
|
||||||
"feature_basic_uploads": "Basis-Uploads",
|
"feature_basic_uploads": "Download aller Fotos",
|
||||||
"feature_unlimited_sharing": "Unbegrenztes Teilen",
|
"feature_unlimited_sharing": "Unbegrenztes Teilen",
|
||||||
"feature_no_watermark": "Kein Wasserzeichen",
|
"feature_no_watermark": "Kein Wasserzeichen",
|
||||||
"feature_custom_tasks": "Benutzerdefinierte Tasks",
|
"feature_custom_tasks": "Benutzerdefinierte Tasks",
|
||||||
@@ -523,9 +523,9 @@
|
|||||||
"family": "Familienfeiern"
|
"family": "Familienfeiern"
|
||||||
},
|
},
|
||||||
"blog": "Blog",
|
"blog": "Blog",
|
||||||
"packages": "Packages",
|
"packages": "Pakete",
|
||||||
"contact": "Kontakt",
|
"contact": "Kontakt",
|
||||||
"discover_packages": "Packages entdecken",
|
"discover_packages": "Pakete entdecken",
|
||||||
"language": "Sprache",
|
"language": "Sprache",
|
||||||
"language_de": "Deutsch",
|
"language_de": "Deutsch",
|
||||||
"language_en": "English",
|
"language_en": "English",
|
||||||
@@ -837,7 +837,7 @@
|
|||||||
"label": "Setup vom Account zur Galerie"
|
"label": "Setup vom Account zur Galerie"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"value": "0 Apps",
|
"value": "keine App-Installation erforderlich",
|
||||||
"label": "Gäste nutzen nur ihren Browser"
|
"label": "Gäste nutzen nur ihren Browser"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -104,7 +104,7 @@
|
|||||||
"cta_explore_highlight": "Explore top packages",
|
"cta_explore_highlight": "Explore top packages",
|
||||||
"gift_cta": "Gift a package",
|
"gift_cta": "Gift a package",
|
||||||
"tab_endcustomer": "End Customers",
|
"tab_endcustomer": "End Customers",
|
||||||
"tab_reseller": "Partner / Agency",
|
"tab_reseller": "Bundles",
|
||||||
"section_endcustomer": "Packages for End Customers (One-time purchase per event)",
|
"section_endcustomer": "Packages for End Customers (One-time purchase per event)",
|
||||||
"section_reseller": "Packages for Partner / Agencies (Event bundle)",
|
"section_reseller": "Packages for Partner / Agencies (Event bundle)",
|
||||||
"bundles_title": "Partner & Agency Bundles",
|
"bundles_title": "Partner & Agency Bundles",
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { useTheme } from '@tamagui/core';
|
|||||||
|
|
||||||
const DEV_TENANT_KEYS = [
|
const DEV_TENANT_KEYS = [
|
||||||
{ key: 'cust-standard-empty', label: 'Endkunde – Starter (kein Event)' },
|
{ key: 'cust-standard-empty', label: 'Endkunde – Starter (kein Event)' },
|
||||||
{ key: 'cust-starter-wedding', label: 'Endkunde – Standard (Hochzeit)' },
|
{ key: 'cust-starter-wedding', label: 'Endkunde – Classic (Hochzeit)' },
|
||||||
{ key: 'reseller-s-active', label: 'Reseller S – 3 aktive Events' },
|
{ key: 'reseller-s-active', label: 'Reseller S – 3 aktive Events' },
|
||||||
{ key: 'reseller-s-full', label: 'Reseller S – voll belegt (5/5)' },
|
{ key: 'reseller-s-full', label: 'Reseller S – voll belegt (5/5)' },
|
||||||
] as const;
|
] as const;
|
||||||
|
|||||||
@@ -200,7 +200,7 @@
|
|||||||
"plans": {
|
"plans": {
|
||||||
"title": "Pakete im Überblick",
|
"title": "Pakete im Überblick",
|
||||||
"subtitle": "Wähle das passende Kontingent",
|
"subtitle": "Wähle das passende Kontingent",
|
||||||
"hint": "Starter, Standard oder Partner – alles mit Moderation & QR-Codes.",
|
"hint": "Starter, Classic oder Partner – alles mit Moderation & QR-Codes.",
|
||||||
"starter": {
|
"starter": {
|
||||||
"title": "Starter",
|
"title": "Starter",
|
||||||
"badge": "Für ein Event",
|
"badge": "Für ein Event",
|
||||||
@@ -209,7 +209,7 @@
|
|||||||
"p3": "Moderation & Galerie-Link"
|
"p3": "Moderation & Galerie-Link"
|
||||||
},
|
},
|
||||||
"standard": {
|
"standard": {
|
||||||
"title": "Standard",
|
"title": "Classic",
|
||||||
"badge": "Beliebt",
|
"badge": "Beliebt",
|
||||||
"highlight": "Mehr Kontingent & Branding",
|
"highlight": "Mehr Kontingent & Branding",
|
||||||
"p1": "Mehr Events pro Jahr",
|
"p1": "Mehr Events pro Jahr",
|
||||||
|
|||||||
@@ -763,7 +763,7 @@
|
|||||||
"surface": "Fläche",
|
"surface": "Fläche",
|
||||||
"lockedBranding": "Branding ist in diesem Paket gesperrt.",
|
"lockedBranding": "Branding ist in diesem Paket gesperrt.",
|
||||||
"lockedTitle": "Branding freischalten",
|
"lockedTitle": "Branding freischalten",
|
||||||
"lockedBody": "Upgrade auf Standard oder Premium, um Event-Branding zu nutzen.",
|
"lockedBody": "Upgrade auf Classic oder Premium, um Event-Branding zu nutzen.",
|
||||||
"upgradeAction": "Paket upgraden",
|
"upgradeAction": "Paket upgraden",
|
||||||
"source": "Branding-Quelle",
|
"source": "Branding-Quelle",
|
||||||
"sourceHint": "Nutze das Standard-Branding oder passe nur dieses Event an.",
|
"sourceHint": "Nutze das Standard-Branding oder passe nur dieses Event an.",
|
||||||
@@ -2934,7 +2934,7 @@
|
|||||||
"recommendedUsage": "Empfohlen innerhalb von 24 Monaten zu nutzen.",
|
"recommendedUsage": "Empfohlen innerhalb von 24 Monaten zu nutzen.",
|
||||||
"tiers": {
|
"tiers": {
|
||||||
"starter": "Starter",
|
"starter": "Starter",
|
||||||
"standard": "Standard",
|
"standard": "Classic",
|
||||||
"premium": "Premium"
|
"premium": "Premium"
|
||||||
},
|
},
|
||||||
"compare": {
|
"compare": {
|
||||||
|
|||||||
@@ -200,7 +200,7 @@
|
|||||||
"plans": {
|
"plans": {
|
||||||
"title": "Packages at a glance",
|
"title": "Packages at a glance",
|
||||||
"subtitle": "Choose the right quota",
|
"subtitle": "Choose the right quota",
|
||||||
"hint": "Starter, Standard or Partner – all include moderation & invites.",
|
"hint": "Starter, Classic or Partner – all include moderation & invites.",
|
||||||
"starter": {
|
"starter": {
|
||||||
"title": "Starter",
|
"title": "Starter",
|
||||||
"badge": "For one event",
|
"badge": "For one event",
|
||||||
@@ -209,7 +209,7 @@
|
|||||||
"p3": "Moderation & gallery link"
|
"p3": "Moderation & gallery link"
|
||||||
},
|
},
|
||||||
"standard": {
|
"standard": {
|
||||||
"title": "Standard",
|
"title": "Classic",
|
||||||
"badge": "Popular",
|
"badge": "Popular",
|
||||||
"highlight": "More quota & branding",
|
"highlight": "More quota & branding",
|
||||||
"p1": "More events per year",
|
"p1": "More events per year",
|
||||||
|
|||||||
@@ -759,7 +759,7 @@
|
|||||||
"surface": "Surface",
|
"surface": "Surface",
|
||||||
"lockedBranding": "Branding is locked for this package.",
|
"lockedBranding": "Branding is locked for this package.",
|
||||||
"lockedTitle": "Unlock branding",
|
"lockedTitle": "Unlock branding",
|
||||||
"lockedBody": "Upgrade to Standard or Premium to unlock event branding.",
|
"lockedBody": "Upgrade to Classic or Premium to unlock event branding.",
|
||||||
"upgradeAction": "Upgrade package",
|
"upgradeAction": "Upgrade package",
|
||||||
"source": "Branding source",
|
"source": "Branding source",
|
||||||
"sourceHint": "Use the default branding or customize this event only.",
|
"sourceHint": "Use the default branding or customize this event only.",
|
||||||
@@ -2936,7 +2936,7 @@
|
|||||||
"recommendedUsage": "Recommended to use within 24 months.",
|
"recommendedUsage": "Recommended to use within 24 months.",
|
||||||
"tiers": {
|
"tiers": {
|
||||||
"starter": "Starter",
|
"starter": "Starter",
|
||||||
"standard": "Standard",
|
"standard": "Classic",
|
||||||
"premium": "Premium"
|
"premium": "Premium"
|
||||||
},
|
},
|
||||||
"compare": {
|
"compare": {
|
||||||
|
|||||||
@@ -524,7 +524,7 @@ function PackageCard({
|
|||||||
pkg.included_package_slug === 'starter'
|
pkg.included_package_slug === 'starter'
|
||||||
? t('shop.partner.tiers.starter', 'Starter')
|
? t('shop.partner.tiers.starter', 'Starter')
|
||||||
: pkg.included_package_slug === 'standard'
|
: pkg.included_package_slug === 'standard'
|
||||||
? t('shop.partner.tiers.standard', 'Standard')
|
? t('shop.partner.tiers.standard', 'Classic')
|
||||||
: pkg.included_package_slug === 'pro'
|
: pkg.included_package_slug === 'pro'
|
||||||
? t('shop.partner.tiers.premium', 'Premium')
|
? t('shop.partner.tiers.premium', 'Premium')
|
||||||
: pkg.included_package_slug;
|
: pkg.included_package_slug;
|
||||||
|
|||||||
@@ -694,7 +694,7 @@ export default function MobileBrandingPage() {
|
|||||||
{!brandingAllowed ? (
|
{!brandingAllowed ? (
|
||||||
<UpgradeCard
|
<UpgradeCard
|
||||||
title={t('events.branding.lockedTitle', 'Unlock branding')}
|
title={t('events.branding.lockedTitle', 'Unlock branding')}
|
||||||
body={t('events.branding.lockedBody', 'Upgrade to Standard or Premium to unlock event branding.')}
|
body={t('events.branding.lockedBody', 'Upgrade to Classic or Premium to unlock event branding.')}
|
||||||
actionLabel={t('events.branding.upgradeAction', 'Upgrade package')}
|
actionLabel={t('events.branding.upgradeAction', 'Upgrade package')}
|
||||||
onPress={() => navigate(adminPath('/mobile/billing/shop?feature=custom_branding'))}
|
onPress={() => navigate(adminPath('/mobile/billing/shop?feature=custom_branding'))}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -245,7 +245,7 @@ export default function MobileEventFormPage() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (slugValue === 'standard') {
|
if (slugValue === 'standard') {
|
||||||
return 'Standard';
|
return 'Classic';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (slugValue === 'pro') {
|
if (slugValue === 'pro') {
|
||||||
|
|||||||
@@ -704,7 +704,7 @@ function resolveIncludedTierLabel(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (slug === 'standard') {
|
if (slug === 'standard') {
|
||||||
return t('shop.partner.tiers.standard', 'Standard');
|
return t('shop.partner.tiers.standard', 'Classic');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (slug === 'pro') {
|
if (slug === 'pro') {
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ const fixtures = vi.hoisted(() => ({
|
|||||||
activePackage: {
|
activePackage: {
|
||||||
id: 1,
|
id: 1,
|
||||||
package_id: 1,
|
package_id: 1,
|
||||||
package_name: 'Standard',
|
package_name: 'Classic',
|
||||||
package_type: 'reseller',
|
package_type: 'reseller',
|
||||||
included_package_slug: null,
|
included_package_slug: null,
|
||||||
active: true,
|
active: true,
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ vi.mock('../../api', () => ({
|
|||||||
{
|
{
|
||||||
id: 1,
|
id: 1,
|
||||||
package_id: 1,
|
package_id: 1,
|
||||||
package_name: 'Standard',
|
package_name: 'Classic',
|
||||||
package_type: 'endcustomer',
|
package_type: 'endcustomer',
|
||||||
included_package_slug: null,
|
included_package_slug: null,
|
||||||
active: true,
|
active: true,
|
||||||
@@ -84,7 +84,7 @@ vi.mock('../../api', () => ({
|
|||||||
activePackage: {
|
activePackage: {
|
||||||
id: 1,
|
id: 1,
|
||||||
package_id: 1,
|
package_id: 1,
|
||||||
package_name: 'Standard',
|
package_name: 'Classic',
|
||||||
package_type: 'endcustomer',
|
package_type: 'endcustomer',
|
||||||
included_package_slug: null,
|
included_package_slug: null,
|
||||||
active: true,
|
active: true,
|
||||||
|
|||||||
@@ -252,7 +252,7 @@ export default function RegisterForm({ packageId, onSuccess, privacyHtml, locale
|
|||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||||
<div className="md:col-span-1">
|
<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')}
|
{t('register.first_name')} {t('common:required')}
|
||||||
</label>
|
</label>
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
@@ -269,7 +269,7 @@ export default function RegisterForm({ packageId, onSuccess, privacyHtml, locale
|
|||||||
clearErrors('first_name');
|
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')}
|
placeholder={t('register.first_name_placeholder')}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -277,7 +277,7 @@ export default function RegisterForm({ packageId, onSuccess, privacyHtml, locale
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="md:col-span-1">
|
<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')}
|
{t('register.last_name')} {t('common:required')}
|
||||||
</label>
|
</label>
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
@@ -294,7 +294,7 @@ export default function RegisterForm({ packageId, onSuccess, privacyHtml, locale
|
|||||||
clearErrors('last_name');
|
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')}
|
placeholder={t('register.last_name_placeholder')}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -302,7 +302,7 @@ export default function RegisterForm({ packageId, onSuccess, privacyHtml, locale
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="md:col-span-2">
|
<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')}
|
{t('register.email')} {t('common:required')}
|
||||||
</label>
|
</label>
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
@@ -319,7 +319,7 @@ export default function RegisterForm({ packageId, onSuccess, privacyHtml, locale
|
|||||||
clearErrors('email');
|
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')}
|
placeholder={t('register.email_placeholder')}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -327,7 +327,7 @@ export default function RegisterForm({ packageId, onSuccess, privacyHtml, locale
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="md:col-span-1">
|
<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')}
|
{t('register.password')} {t('common:required')}
|
||||||
</label>
|
</label>
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
@@ -347,7 +347,7 @@ export default function RegisterForm({ packageId, onSuccess, privacyHtml, locale
|
|||||||
clearErrors('password_confirmation');
|
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')}
|
placeholder={t('register.password_placeholder')}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -355,7 +355,7 @@ export default function RegisterForm({ packageId, onSuccess, privacyHtml, locale
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="md:col-span-1">
|
<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')}
|
{t('register.password_confirmation')} {t('common:required')}
|
||||||
</label>
|
</label>
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
@@ -375,7 +375,7 @@ export default function RegisterForm({ packageId, onSuccess, privacyHtml, locale
|
|||||||
clearErrors('password_confirmation');
|
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')}
|
placeholder={t('register.password_confirmation_placeholder')}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -399,14 +399,14 @@ export default function RegisterForm({ packageId, onSuccess, privacyHtml, locale
|
|||||||
clearErrors('terms');
|
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')}{' '}
|
{t('register.privacy_consent')}{' '}
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => setPrivacyOpen(true)}
|
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')}
|
{t('register.privacy_policy_link')}
|
||||||
</button>.
|
</button>.
|
||||||
|
|||||||
@@ -664,7 +664,7 @@ const resolveServiceTierLabel = (slug: string | null | undefined): string => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (slug === 'standard') {
|
if (slug === 'standard') {
|
||||||
return 'Standard';
|
return 'Classic';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (slug === 'pro') {
|
if (slug === 'pro') {
|
||||||
@@ -784,7 +784,7 @@ function PackageCard({
|
|||||||
: null;
|
: null;
|
||||||
|
|
||||||
const displayFeatures = buildDisplayFeatures(pkg, variant);
|
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 metrics = resolvePackageMetrics(pkg, variant, t, tCommon);
|
||||||
|
|
||||||
const metricList = (
|
const metricList = (
|
||||||
@@ -1200,18 +1200,6 @@ const PackageDetailGrid: React.FC<PackageDetailGridProps> = ({
|
|||||||
{t('packages.hero_description')}
|
{t('packages.hero_description')}
|
||||||
</p>
|
</p>
|
||||||
</motion.div>
|
</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>
|
</motion.div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
@@ -1238,16 +1226,15 @@ const PackageDetailGrid: React.FC<PackageDetailGridProps> = ({
|
|||||||
<TabsContent value="endcustomer" className="space-y-8 pt-8">
|
<TabsContent value="endcustomer" className="space-y-8 pt-8">
|
||||||
<div className="md:hidden">
|
<div className="md:hidden">
|
||||||
<div className="relative">
|
<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 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-6 bg-gradient-to-l from-white to-transparent dark:from-gray-950" />
|
<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
|
<div
|
||||||
ref={mobileEndcustomerRef}
|
ref={mobileEndcustomerRef}
|
||||||
className="flex snap-x snap-mandatory gap-4 overflow-x-auto pb-6"
|
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) => (
|
{orderedEndcustomerPackages.map((pkg) => (
|
||||||
<div key={pkg.id} className="snap-start basis-[72vw] shrink-0 sm:basis-[60vw]">
|
<div key={pkg.id} className="snap-center basis-[64vw] shrink-0 sm:basis-[56vw]">
|
||||||
<motion.div variants={revealUp} initial="hidden" whileInView="visible" viewport={viewportOnce}>
|
|
||||||
<PackageCard
|
<PackageCard
|
||||||
pkg={pkg}
|
pkg={pkg}
|
||||||
variant="endcustomer"
|
variant="endcustomer"
|
||||||
@@ -1257,7 +1244,6 @@ const PackageDetailGrid: React.FC<PackageDetailGridProps> = ({
|
|||||||
className="h-full"
|
className="h-full"
|
||||||
compact
|
compact
|
||||||
/>
|
/>
|
||||||
</motion.div>
|
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
@@ -1319,16 +1305,15 @@ const PackageDetailGrid: React.FC<PackageDetailGridProps> = ({
|
|||||||
</motion.div>
|
</motion.div>
|
||||||
<div className="md:hidden">
|
<div className="md:hidden">
|
||||||
<div className="relative">
|
<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 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-6 bg-gradient-to-l from-white to-transparent dark:from-gray-950" />
|
<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
|
<div
|
||||||
ref={mobileResellerRef}
|
ref={mobileResellerRef}
|
||||||
className="flex snap-x snap-mandatory gap-4 overflow-x-auto pb-6"
|
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) => (
|
{orderedResellerPackages.map((pkg) => (
|
||||||
<div key={pkg.id} className="snap-start basis-[72vw] shrink-0 sm:basis-[60vw]">
|
<div key={pkg.id} className="snap-center basis-[64vw] shrink-0 sm:basis-[56vw]">
|
||||||
<motion.div variants={revealUp} initial="hidden" whileInView="visible" viewport={viewportOnce}>
|
|
||||||
<PackageCard
|
<PackageCard
|
||||||
pkg={pkg}
|
pkg={pkg}
|
||||||
variant="reseller"
|
variant="reseller"
|
||||||
@@ -1338,7 +1323,6 @@ const PackageDetailGrid: React.FC<PackageDetailGridProps> = ({
|
|||||||
className="h-full"
|
className="h-full"
|
||||||
compact
|
compact
|
||||||
/>
|
/>
|
||||||
</motion.div>
|
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
@@ -1386,6 +1370,19 @@ const PackageDetailGrid: React.FC<PackageDetailGridProps> = ({
|
|||||||
<PackageComparison packages={orderedResellerPackages} variant="reseller" serviceTierNames={serviceTierNames} />
|
<PackageComparison packages={orderedResellerPackages} variant="reseller" serviceTierNames={serviceTierNames} />
|
||||||
</motion.div>
|
</motion.div>
|
||||||
</TabsContent>
|
</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>
|
</Tabs>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ describe('Home', () => {
|
|||||||
<Home
|
<Home
|
||||||
packages={[
|
packages={[
|
||||||
{ id: 1, name: 'Starter', description: 'Desc', price: 29 },
|
{ 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,
|
id: 2,
|
||||||
name: 'Standard',
|
name: 'Classic',
|
||||||
slug: 'standard',
|
slug: 'standard',
|
||||||
description: 'Desc',
|
description: 'Desc',
|
||||||
description_breakdown: [],
|
description_breakdown: [],
|
||||||
|
|||||||
@@ -44,12 +44,12 @@
|
|||||||
"packages": {
|
"packages": {
|
||||||
"title": "Unsere Packages",
|
"title": "Unsere Packages",
|
||||||
"hero_kicker": "Pakete, die mit eurem Event mitwachsen",
|
"hero_kicker": "Pakete, die mit eurem Event mitwachsen",
|
||||||
"hero_title": "Entdecken Sie unsere flexiblen Packages",
|
"hero_title": "Entdecken Sie unsere flexiblen Event-Pakete",
|
||||||
"hero_description": "Von kostenlosem Einstieg bis Premium-Features: Passen Sie Ihr Event-Paket an Ihre Bedürfnisse an. Einfach, sicher und skalierbar.",
|
"hero_description": "Von kostenlosem Einstieg bis Premium-Features: Passen Sie Ihr Event-Paket an Ihre Bedürfnisse an. Einfach, sicher und skalierbar.",
|
||||||
"cta_explore": "Pakete entdecken",
|
"cta_explore": "Pakete entdecken",
|
||||||
"gift_cta": "Paket verschenken",
|
"gift_cta": "Paket verschenken",
|
||||||
"tab_endcustomer": "Einzel-Events",
|
"tab_endcustomer": "Einzel-Events",
|
||||||
"tab_reseller": "Partner / Agentur",
|
"tab_reseller": "mehrere Events",
|
||||||
"section_endcustomer": "Packages für Endkunden (Einmalkauf pro Event)",
|
"section_endcustomer": "Packages für Endkunden (Einmalkauf pro Event)",
|
||||||
"section_reseller": "Packages für Partner / Agenturen (Event-Kontingent)",
|
"section_reseller": "Packages für Partner / Agenturen (Event-Kontingent)",
|
||||||
"bundles_title": "Partner & Agentur Bundles",
|
"bundles_title": "Partner & Agentur Bundles",
|
||||||
@@ -100,7 +100,7 @@
|
|||||||
"feature_watermark_custom": "Eigenes Wasserzeichen",
|
"feature_watermark_custom": "Eigenes Wasserzeichen",
|
||||||
"feature_branding": "Branding",
|
"feature_branding": "Branding",
|
||||||
"feature_support": "Support",
|
"feature_support": "Support",
|
||||||
"feature_basic_uploads": "Basis-Uploads",
|
"feature_basic_uploads": "Download aller Fotos",
|
||||||
"feature_unlimited_sharing": "Unbegrenztes Teilen",
|
"feature_unlimited_sharing": "Unbegrenztes Teilen",
|
||||||
"feature_no_watermark": "Fotospiel-Wasserzeichen entfernen",
|
"feature_no_watermark": "Fotospiel-Wasserzeichen entfernen",
|
||||||
"feature_custom_tasks": "Benutzerdefinierte Tasks",
|
"feature_custom_tasks": "Benutzerdefinierte Tasks",
|
||||||
@@ -164,7 +164,7 @@
|
|||||||
"standard": [
|
"standard": [
|
||||||
{
|
{
|
||||||
"name": "Lena & Jonas",
|
"name": "Lena & Jonas",
|
||||||
"text": "Standard fühlt sich wie das Allround-Paket an: genug Gäste und Fotos plus ein Jahr Galerie."
|
"text": "Classic fühlt sich wie das Allround-Paket an: genug Gäste und Fotos plus ein Jahr Galerie."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Marco P.",
|
"name": "Marco P.",
|
||||||
@@ -206,7 +206,7 @@
|
|||||||
"m-medium-reseller": [
|
"m-medium-reseller": [
|
||||||
{
|
{
|
||||||
"name": "Eventbüro Lenz",
|
"name": "Eventbüro Lenz",
|
||||||
"text": "15 Events decken unsere Saison meistens ab. Standard-Level ist für viele Kunden passend."
|
"text": "15 Events decken unsere Saison meistens ab. Classic-Level ist für viele Kunden passend."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Jasmin & Co.",
|
"name": "Jasmin & Co.",
|
||||||
@@ -256,7 +256,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Agentur Süd",
|
"name": "Agentur Süd",
|
||||||
"text": "Standard-Level ist ein guter Mittelweg für verschiedene Event-Typen."
|
"text": "Classic-Level ist ein guter Mittelweg für verschiedene Event-Typen."
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,11 +3,11 @@
|
|||||||
return [
|
return [
|
||||||
'packages' => [
|
'packages' => [
|
||||||
'title' => 'Unsere Packages – Wählen Sie Ihr Event-Paket',
|
'title' => 'Unsere Packages – Wählen Sie Ihr Event-Paket',
|
||||||
'hero_title' => 'Entdecken Sie unsere flexiblen Packages',
|
'hero_title' => 'Entdecken Sie unsere flexiblen Event-Pakete',
|
||||||
'hero_description' => 'Von kostenlosem Einstieg bis Premium-Features: Passen Sie Ihr Event-Paket an Ihre Bedürfnisse an. Einfach, sicher und skalierbar.',
|
'hero_description' => 'Von kostenlosem Einstieg bis Premium-Features: Passen Sie Ihr Event-Paket an Ihre Bedürfnisse an. Einfach, sicher und skalierbar.',
|
||||||
'cta_explore' => 'Packages entdecken',
|
'cta_explore' => 'Packages entdecken',
|
||||||
'tab_endcustomer' => 'Einzel-Events',
|
'tab_endcustomer' => 'Einzel-Events',
|
||||||
'tab_reseller' => 'Partner / Agenturen',
|
'tab_reseller' => 'mehrere Events',
|
||||||
'section_endcustomer' => 'Packages für Endkunden (Einmalkauf pro Event)',
|
'section_endcustomer' => 'Packages für Endkunden (Einmalkauf pro Event)',
|
||||||
'section_reseller' => 'Packages für Partner / Agenturen (Event-Kontingent)',
|
'section_reseller' => 'Packages für Partner / Agenturen (Event-Kontingent)',
|
||||||
'free' => 'Kostenlos',
|
'free' => 'Kostenlos',
|
||||||
@@ -40,7 +40,7 @@ return [
|
|||||||
'feature_watermark_custom' => 'Eigenes Wasserzeichen',
|
'feature_watermark_custom' => 'Eigenes Wasserzeichen',
|
||||||
'feature_branding' => 'Branding',
|
'feature_branding' => 'Branding',
|
||||||
'feature_support' => 'Support',
|
'feature_support' => 'Support',
|
||||||
'feature_basic_uploads' => 'Grundlegende Uploads',
|
'feature_basic_uploads' => 'Download aller Fotos',
|
||||||
'feature_unlimited_sharing' => 'Unbegrenztes Teilen',
|
'feature_unlimited_sharing' => 'Unbegrenztes Teilen',
|
||||||
'feature_no_watermark' => 'Fotospiel-Wasserzeichen entfernen',
|
'feature_no_watermark' => 'Fotospiel-Wasserzeichen entfernen',
|
||||||
'feature_custom_tasks' => 'Benutzerdefinierte Tasks',
|
'feature_custom_tasks' => 'Benutzerdefinierte Tasks',
|
||||||
@@ -85,9 +85,9 @@ return [
|
|||||||
'family' => 'Familienfeiern',
|
'family' => 'Familienfeiern',
|
||||||
],
|
],
|
||||||
'blog' => 'Blog',
|
'blog' => 'Blog',
|
||||||
'packages' => 'Packages',
|
'packages' => 'Pakete',
|
||||||
'contact' => 'Kontakt',
|
'contact' => 'Kontakt',
|
||||||
'discover_packages' => 'Packages entdecken',
|
'discover_packages' => 'Pakete entdecken',
|
||||||
'language' => 'Sprache',
|
'language' => 'Sprache',
|
||||||
'open_menu' => 'Menü öffnen',
|
'open_menu' => 'Menü öffnen',
|
||||||
'close_menu' => 'Menü schließen',
|
'close_menu' => 'Menü schließen',
|
||||||
|
|||||||
@@ -49,7 +49,7 @@
|
|||||||
"cta_explore": "Discover Packages",
|
"cta_explore": "Discover Packages",
|
||||||
"gift_cta": "Gift a package",
|
"gift_cta": "Gift a package",
|
||||||
"tab_endcustomer": "End Customers",
|
"tab_endcustomer": "End Customers",
|
||||||
"tab_reseller": "Partner / Agency",
|
"tab_reseller": "Bundles",
|
||||||
"section_endcustomer": "Packages for End Customers (One-time purchase per Event)",
|
"section_endcustomer": "Packages for End Customers (One-time purchase per Event)",
|
||||||
"section_reseller": "Packages for Partner / Agencies (Event-Bundle)",
|
"section_reseller": "Packages for Partner / Agencies (Event-Bundle)",
|
||||||
"bundles_title": "Partner & Agency Bundles",
|
"bundles_title": "Partner & Agency Bundles",
|
||||||
@@ -165,7 +165,7 @@
|
|||||||
"standard": [
|
"standard": [
|
||||||
{
|
{
|
||||||
"name": "Lena & Jonas",
|
"name": "Lena & Jonas",
|
||||||
"text": "Standard feels like the all-round package: plenty of guests and photos plus a full year of gallery."
|
"text": "Classic feels like the all-round package: plenty of guests and photos plus a full year of gallery."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Marco P.",
|
"name": "Marco P.",
|
||||||
@@ -207,7 +207,7 @@
|
|||||||
"m-medium-reseller": [
|
"m-medium-reseller": [
|
||||||
{
|
{
|
||||||
"name": "Event Bureau Lenz",
|
"name": "Event Bureau Lenz",
|
||||||
"text": "Fifteen events usually cover our season. Standard level fits most clients."
|
"text": "Fifteen events usually cover our season. Classic level fits most clients."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Jasmin & Co.",
|
"name": "Jasmin & Co.",
|
||||||
@@ -257,7 +257,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Agency South",
|
"name": "Agency South",
|
||||||
"text": "Standard level is a solid middle ground for varied event types."
|
"text": "Classic level is a solid middle ground for varied event types."
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ return [
|
|||||||
'hero_description' => 'From free entry to premium features: Tailor your event package to your needs. Simple, secure and scalable.',
|
'hero_description' => 'From free entry to premium features: Tailor your event package to your needs. Simple, secure and scalable.',
|
||||||
'cta_explore' => 'Discover Packages',
|
'cta_explore' => 'Discover Packages',
|
||||||
'tab_endcustomer' => 'End Customers',
|
'tab_endcustomer' => 'End Customers',
|
||||||
'tab_reseller' => 'Partner / Agencies',
|
'tab_reseller' => 'Bundles',
|
||||||
'section_endcustomer' => 'Packages for End Customers (One-time purchase per Event)',
|
'section_endcustomer' => 'Packages for End Customers (One-time purchase per Event)',
|
||||||
'section_reseller' => 'Packages for Partner / Agencies (Event bundle)',
|
'section_reseller' => 'Packages for Partner / Agencies (Event bundle)',
|
||||||
'free' => 'Free',
|
'free' => 'Free',
|
||||||
|
|||||||
@@ -107,7 +107,7 @@ class CustomerEmailRenderTest extends TestCase
|
|||||||
$user->forceFill(['tenant_id' => $tenant->id])->save();
|
$user->forceFill(['tenant_id' => $tenant->id])->save();
|
||||||
|
|
||||||
$package = Package::factory()->create([
|
$package = Package::factory()->create([
|
||||||
'name' => 'Standard',
|
'name' => 'Classic',
|
||||||
'type' => 'endcustomer',
|
'type' => 'endcustomer',
|
||||||
'max_photos' => 500,
|
'max_photos' => 500,
|
||||||
'max_guests' => 200,
|
'max_guests' => 200,
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ class PurchaseConfirmationMailTest extends TestCase
|
|||||||
$user->forceFill(['tenant_id' => $tenant->id])->save();
|
$user->forceFill(['tenant_id' => $tenant->id])->save();
|
||||||
|
|
||||||
$package = Package::factory()->create([
|
$package = Package::factory()->create([
|
||||||
'name' => 'Standard',
|
'name' => 'Classic',
|
||||||
'type' => 'endcustomer',
|
'type' => 'endcustomer',
|
||||||
'max_photos' => 500,
|
'max_photos' => 500,
|
||||||
'max_guests' => 200,
|
'max_guests' => 200,
|
||||||
@@ -51,7 +51,7 @@ class PurchaseConfirmationMailTest extends TestCase
|
|||||||
$html = $mailable->render();
|
$html = $mailable->render();
|
||||||
|
|
||||||
$this->assertStringContainsString('Die Fotospiel.App', $html);
|
$this->assertStringContainsString('Die Fotospiel.App', $html);
|
||||||
$this->assertStringContainsString('Standard', $html);
|
$this->assertStringContainsString('Classic', $html);
|
||||||
$this->assertStringContainsString('txn_123', $html);
|
$this->assertStringContainsString('txn_123', $html);
|
||||||
$this->assertStringContainsString('https://paddle.test/invoice/123', $html);
|
$this->assertStringContainsString('https://paddle.test/invoice/123', $html);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ class SeedDemoSwitcherTenantsTest extends TestCase
|
|||||||
|
|
||||||
Package::factory()->create([
|
Package::factory()->create([
|
||||||
'slug' => 'standard',
|
'slug' => 'standard',
|
||||||
'name' => 'Standard',
|
'name' => 'Classic',
|
||||||
'type' => 'endcustomer',
|
'type' => 'endcustomer',
|
||||||
'max_events_per_year' => 5,
|
'max_events_per_year' => 5,
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -65,8 +65,8 @@ class DashboardSummaryTest extends TestCase
|
|||||||
$package = Package::factory()
|
$package = Package::factory()
|
||||||
->reseller()
|
->reseller()
|
||||||
->create([
|
->create([
|
||||||
'name' => 'Standard',
|
'name' => 'Classic',
|
||||||
'name_translations' => ['de' => 'Standard', 'en' => 'Standard'],
|
'name_translations' => ['de' => 'Classic', 'en' => 'Classic'],
|
||||||
'price' => 59,
|
'price' => 59,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@@ -96,7 +96,7 @@ class DashboardSummaryTest extends TestCase
|
|||||||
$activePackagePayload = Arr::get($payload, 'active_package');
|
$activePackagePayload = Arr::get($payload, 'active_package');
|
||||||
|
|
||||||
$this->assertIsArray($activePackagePayload);
|
$this->assertIsArray($activePackagePayload);
|
||||||
$this->assertSame('Standard', Arr::get($activePackagePayload, 'name'));
|
$this->assertSame('Classic', Arr::get($activePackagePayload, 'name'));
|
||||||
$this->assertSame($activePackage->remaining_events, Arr::get($activePackagePayload, 'remaining_events'));
|
$this->assertSame($activePackage->remaining_events, Arr::get($activePackagePayload, 'remaining_events'));
|
||||||
|
|
||||||
$this->assertSame(
|
$this->assertSame(
|
||||||
|
|||||||
@@ -37,10 +37,10 @@ class EventListTest extends TenantTestCase
|
|||||||
{
|
{
|
||||||
$package = Package::factory()->create([
|
$package = Package::factory()->create([
|
||||||
'type' => 'endcustomer',
|
'type' => 'endcustomer',
|
||||||
'name' => 'Standard',
|
'name' => 'Classic',
|
||||||
'name_translations' => [
|
'name_translations' => [
|
||||||
'de' => 'Standard',
|
'de' => 'Classic',
|
||||||
'en' => 'Standard',
|
'en' => 'Classic',
|
||||||
],
|
],
|
||||||
'price' => 59,
|
'price' => 59,
|
||||||
'gallery_days' => 45,
|
'gallery_days' => 45,
|
||||||
@@ -75,7 +75,7 @@ class EventListTest extends TenantTestCase
|
|||||||
|
|
||||||
$this->assertIsArray($matchingEvent['package']);
|
$this->assertIsArray($matchingEvent['package']);
|
||||||
$this->assertSame($package->id, $matchingEvent['package']['id']);
|
$this->assertSame($package->id, $matchingEvent['package']['id']);
|
||||||
$this->assertSame('Standard', $matchingEvent['package']['name']);
|
$this->assertSame('Classic', $matchingEvent['package']['name']);
|
||||||
$this->assertSame('59.00', $matchingEvent['package']['price']);
|
$this->assertSame('59.00', $matchingEvent['package']['price']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -129,7 +129,7 @@ class GiftVoucherServiceTest extends TestCase
|
|||||||
config()->set('gift-vouchers.tiers', [
|
config()->set('gift-vouchers.tiers', [
|
||||||
[
|
[
|
||||||
'key' => 'gift-standard-usd',
|
'key' => 'gift-standard-usd',
|
||||||
'label' => 'Gift Standard (USD)',
|
'label' => 'Gift Classic (USD)',
|
||||||
'amount' => 65.00,
|
'amount' => 65.00,
|
||||||
'currency' => 'USD',
|
'currency' => 'USD',
|
||||||
'paddle_price_id' => 'pri_usd_123',
|
'paddle_price_id' => 'pri_usd_123',
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ test.describe('Marketing frontend smoke', () => {
|
|||||||
await acceptCookies.click();
|
await acceptCookies.click();
|
||||||
}
|
}
|
||||||
|
|
||||||
const packageCards = page.locator('section >> text=/Starter|Standard|Premium/');
|
const packageCards = page.locator('section >> text=/Starter|Classic|Premium/');
|
||||||
await expect(packageCards.first()).toBeVisible();
|
await expect(packageCards.first()).toBeVisible();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ test.describe('Paddle sandbox full flow (staging)', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Jump directly into wizard for Standard package (2)
|
// Jump directly into wizard for Classic package (2)
|
||||||
await page.goto(`${baseUrl}/${locale}/${checkoutSlug}/2`);
|
await page.goto(`${baseUrl}/${locale}/${checkoutSlug}/2`);
|
||||||
|
|
||||||
await dismissConsentBanner(page);
|
await dismissConsentBanner(page);
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { test, expectFixture as expect } from '../helpers/test-fixtures';
|
|||||||
|
|
||||||
const shouldRun = process.env.E2E_TESTING_API === '1';
|
const shouldRun = process.env.E2E_TESTING_API === '1';
|
||||||
|
|
||||||
test.describe('Standard package checkout with Paddle completion', () => {
|
test.describe('Classic package checkout with Paddle completion', () => {
|
||||||
test.skip(!shouldRun, 'Set E2E_TESTING_API=1 to enable checkout tests that use /api/_testing endpoints.');
|
test.skip(!shouldRun, 'Set E2E_TESTING_API=1 to enable checkout tests that use /api/_testing endpoints.');
|
||||||
test('registers, applies coupon, and reaches confirmation', async ({
|
test('registers, applies coupon, and reaches confirmation', async ({
|
||||||
page,
|
page,
|
||||||
@@ -67,7 +67,7 @@ test.describe('Standard package checkout with Paddle completion', () => {
|
|||||||
|
|
||||||
const standardDetailsButton = page
|
const standardDetailsButton = page
|
||||||
.locator('[data-slot="card"]')
|
.locator('[data-slot="card"]')
|
||||||
.filter({ hasText: /Standard/i })
|
.filter({ hasText: /Classic/i })
|
||||||
.getByRole('button', { name: /Details ansehen|Details anzeigen|View details/i })
|
.getByRole('button', { name: /Details ansehen|Details anzeigen|View details/i })
|
||||||
.first();
|
.first();
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ const demoTenantCredentials = {
|
|||||||
password: process.env.E2E_DEMO_TENANT_PASSWORD ?? 'Demo1234!',
|
password: process.env.E2E_DEMO_TENANT_PASSWORD ?? 'Demo1234!',
|
||||||
};
|
};
|
||||||
|
|
||||||
test.describe('Standard package checkout with coupons', () => {
|
test.describe('Classic package checkout with coupons', () => {
|
||||||
test.skip(!shouldRun, 'Set E2E_TESTING_API=1 to enable checkout tests that use /api/_testing endpoints.');
|
test.skip(!shouldRun, 'Set E2E_TESTING_API=1 to enable checkout tests that use /api/_testing endpoints.');
|
||||||
test('applies seeded coupon and shows discount summary', async ({
|
test('applies seeded coupon and shows discount summary', async ({
|
||||||
page,
|
page,
|
||||||
@@ -25,7 +25,7 @@ test.describe('Standard package checkout with coupons', () => {
|
|||||||
|
|
||||||
const dialog = page.getByRole('dialog');
|
const dialog = page.getByRole('dialog');
|
||||||
await expect(dialog).toBeVisible();
|
await expect(dialog).toBeVisible();
|
||||||
await expect(dialog.getByRole('heading', { name: /Standard/i })).toBeVisible();
|
await expect(dialog.getByRole('heading', { name: /Classic/i })).toBeVisible();
|
||||||
|
|
||||||
await dialog.getByRole('link', { name: /Jetzt bestellen|Order now|Jetzt buchen/i }).click();
|
await dialog.getByRole('link', { name: /Jetzt bestellen|Order now|Jetzt buchen/i }).click();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user