- Wired the checkout wizard for Google “comfort login”: added Socialite controller + dependency, new Google env

hooks in config/services.php/.env.example, and updated wizard steps/controllers to store session payloads,
attach packages, and surface localized success/error states.
- Retooled payment handling for both Stripe and PayPal, adding richer status management in CheckoutController/
PayPalController, fallback flows in the wizard’s PaymentStep.tsx, and fresh feature tests for intent
creation, webhooks, and the wizard CTA.
- Introduced a consent-aware Matomo analytics stack: new consent context, cookie-banner UI, useAnalytics/
useCtaExperiment hooks, and MatomoTracker component, then instrumented marketing pages (Home, Packages,
Checkout) with localized copy and experiment tracking.
- Polished package presentation across marketing UIs by centralizing formatting in PresentsPackages, surfacing
localized description tables/placeholders, tuning badges/layouts, and syncing guest/marketing translations.
- Expanded docs & reference material (docs/prp/*, TODOs, public gallery overview) and added a Playwright smoke
test for the hero CTA while reconciling outstanding checklist items.
This commit is contained in:
Codex Agent
2025-10-19 11:41:03 +02:00
parent ae9b9160ac
commit a949c8d3af
113 changed files with 5169 additions and 712 deletions

View File

@@ -272,17 +272,17 @@ function SummaryCards({ data }: { data: AchievementsPayload }) {
);
}
function PersonalActions({ slug }: { slug: string }) {
function PersonalActions({ token }: { token: string }) {
return (
<div className="flex flex-wrap gap-3">
<Button asChild>
<Link to={`/e/${encodeURIComponent(slug)}/upload`} className="flex items-center gap-2">
<Link to={`/e/${encodeURIComponent(token)}/upload`} className="flex items-center gap-2">
<Camera className="h-4 w-4" />
Neues Foto hochladen
</Link>
</Button>
<Button variant="outline" asChild>
<Link to={`/e/${encodeURIComponent(slug)}/tasks`} className="flex items-center gap-2">
<Link to={`/e/${encodeURIComponent(token)}/tasks`} className="flex items-center gap-2">
<Sparkles className="h-4 w-4" />
Aufgabe ziehen
</Link>
@@ -292,7 +292,7 @@ function PersonalActions({ slug }: { slug: string }) {
}
export default function AchievementsPage() {
const { token: slug } = useParams<{ token: string }>();
const { token } = useParams<{ token: string }>();
const identity = useGuestIdentity();
const [data, setData] = useState<AchievementsPayload | null>(null);
const [loading, setLoading] = useState(true);
@@ -302,12 +302,12 @@ export default function AchievementsPage() {
const personalName = identity.hydrated && identity.name ? identity.name : undefined;
useEffect(() => {
if (!slug) return;
if (!token) return;
const controller = new AbortController();
setLoading(true);
setError(null);
fetchAchievements(slug, personalName, controller.signal)
fetchAchievements(token, personalName, controller.signal)
.then((payload) => {
setData(payload);
if (!payload.personal) {
@@ -322,11 +322,11 @@ export default function AchievementsPage() {
.finally(() => setLoading(false));
return () => controller.abort();
}, [slug, personalName]);
}, [token, personalName]);
const hasPersonal = Boolean(data?.personal);
if (!slug) {
if (!token) {
return null;
}
@@ -407,7 +407,7 @@ export default function AchievementsPage() {
{data.personal.photos} Fotos | {data.personal.tasks} Aufgaben | {data.personal.likes} Likes
</CardDescription>
</div>
<PersonalActions slug={slug} />
<PersonalActions token={token} />
</CardHeader>
</Card>