- 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

@@ -23,15 +23,15 @@ interface Props {
currentIndex?: number;
onClose?: () => void;
onIndexChange?: (index: number) => void;
slug?: string;
token?: string;
}
export default function PhotoLightbox({ photos, currentIndex, onClose, onIndexChange, slug }: Props) {
export default function PhotoLightbox({ photos, currentIndex, onClose, onIndexChange, token }: Props) {
const params = useParams<{ token?: string; photoId?: string }>();
const location = useLocation();
const navigate = useNavigate();
const photoId = params.photoId;
const eventSlug = params.token || slug;
const eventToken = params.token || token;
const { t } = useTranslation();
const [standalonePhoto, setStandalonePhoto] = useState<Photo | null>(null);
@@ -53,7 +53,7 @@ export default function PhotoLightbox({ photos, currentIndex, onClose, onIndexCh
// Fetch single photo for standalone mode
useEffect(() => {
if (isStandalone && photoId && !standalonePhoto && eventSlug) {
if (isStandalone && photoId && !standalonePhoto && eventToken) {
const fetchPhoto = async () => {
setLoading(true);
setError(null);
@@ -80,7 +80,7 @@ export default function PhotoLightbox({ photos, currentIndex, onClose, onIndexCh
} else if (!isStandalone) {
setLoading(false);
}
}, [isStandalone, photoId, eventSlug, standalonePhoto, location.state, t]);
}, [isStandalone, photoId, eventToken, standalonePhoto, location.state, t]);
// Update likes when photo changes
React.useEffect(() => {
@@ -133,7 +133,7 @@ export default function PhotoLightbox({ photos, currentIndex, onClose, onIndexCh
// Load task info if photo has task_id and event key is available
React.useEffect(() => {
if (!photo?.task_id || !eventSlug) {
if (!photo?.task_id || !eventToken) {
setTask(null);
setTaskLoading(false);
return;
@@ -144,7 +144,7 @@ export default function PhotoLightbox({ photos, currentIndex, onClose, onIndexCh
(async () => {
setTaskLoading(true);
try {
const res = await fetch(`/api/v1/events/${encodeURIComponent(eventSlug)}/tasks`);
const res = await fetch(`/api/v1/events/${encodeURIComponent(eventToken)}/tasks`);
if (res.ok) {
const tasks = await res.json();
const foundTask = tasks.find((t: any) => t.id === taskId);
@@ -175,7 +175,7 @@ export default function PhotoLightbox({ photos, currentIndex, onClose, onIndexCh
setTaskLoading(false);
}
})();
}, [photo?.task_id, eventSlug, t]);
}, [photo?.task_id, eventToken, t]);
async function onLike() {
if (liked || !photo) return;