completed addon checkout in mobile event admin
This commit is contained in:
@@ -30,6 +30,7 @@ import { useTheme } from '@tamagui/core';
|
||||
import { buildLimitWarnings } from '../lib/limitWarnings';
|
||||
import { adminPath } from '../constants';
|
||||
import { scopeDefaults, selectAddonKeyForScope } from './addons';
|
||||
import { LegalConsentSheet } from './components/LegalConsentSheet';
|
||||
|
||||
type FilterKey = 'all' | 'featured' | 'hidden' | 'pending';
|
||||
|
||||
@@ -59,6 +60,9 @@ export default function MobileEventPhotosPage() {
|
||||
const [catalogAddons, setCatalogAddons] = React.useState<EventAddonCatalogItem[]>([]);
|
||||
const [eventAddons, setEventAddons] = React.useState<EventAddonSummary[]>([]);
|
||||
const [busyScope, setBusyScope] = React.useState<string | null>(null);
|
||||
const [consentOpen, setConsentOpen] = React.useState(false);
|
||||
const [consentTarget, setConsentTarget] = React.useState<{ scope: 'photos' | 'gallery' | 'guests'; addonKey: string } | null>(null);
|
||||
const [consentBusy, setConsentBusy] = React.useState(false);
|
||||
const theme = useTheme();
|
||||
const text = String(theme.color?.val ?? '#111827');
|
||||
const muted = String(theme.gray?.val ?? '#4b5563');
|
||||
@@ -209,6 +213,62 @@ export default function MobileEventPhotosPage() {
|
||||
}
|
||||
}
|
||||
|
||||
function resolveScopeAndAddonKey(scopeOrKey: 'photos' | 'gallery' | 'guests' | string) {
|
||||
const scope =
|
||||
scopeOrKey === 'photos' || scopeOrKey === 'gallery' || scopeOrKey === 'guests'
|
||||
? scopeOrKey
|
||||
: scopeOrKey.includes('gallery')
|
||||
? 'gallery'
|
||||
: scopeOrKey.includes('guest')
|
||||
? 'guests'
|
||||
: 'photos';
|
||||
|
||||
const addonKey =
|
||||
scopeOrKey === 'photos' || scopeOrKey === 'gallery' || scopeOrKey === 'guests'
|
||||
? selectAddonKeyForScope(catalogAddons, scope)
|
||||
: scopeOrKey;
|
||||
|
||||
return { scope, addonKey };
|
||||
}
|
||||
|
||||
function startAddonCheckout(scopeOrKey: 'photos' | 'gallery' | 'guests' | string) {
|
||||
if (!slug) return;
|
||||
const { scope, addonKey } = resolveScopeAndAddonKey(scopeOrKey);
|
||||
setConsentTarget({ scope, addonKey });
|
||||
setConsentOpen(true);
|
||||
}
|
||||
|
||||
async function confirmAddonCheckout(consents: { acceptedTerms: boolean; acceptedWaiver: boolean }) {
|
||||
if (!slug || !consentTarget) return;
|
||||
|
||||
const currentUrl = typeof window !== 'undefined' ? `${window.location.origin}${adminPath(`/mobile/events/${slug}/photos`)}` : '';
|
||||
const successUrl = `${currentUrl}?addon_success=1`;
|
||||
setBusyScope(consentTarget.scope);
|
||||
setConsentBusy(true);
|
||||
try {
|
||||
const checkout = await createEventAddonCheckout(slug, {
|
||||
addon_key: consentTarget.addonKey,
|
||||
quantity: 1,
|
||||
success_url: successUrl,
|
||||
cancel_url: currentUrl,
|
||||
accepted_terms: consents.acceptedTerms,
|
||||
accepted_waiver: consents.acceptedWaiver,
|
||||
});
|
||||
if (checkout.checkout_url) {
|
||||
window.location.href = checkout.checkout_url;
|
||||
} else {
|
||||
toast.error(t('events.errors.checkoutMissing', 'Checkout could not be started.'));
|
||||
}
|
||||
} catch (err) {
|
||||
toast.error(getApiErrorMessage(err, t('events.errors.checkoutFailed', 'Add-on checkout failed.')));
|
||||
} finally {
|
||||
setConsentBusy(false);
|
||||
setConsentOpen(false);
|
||||
setConsentTarget(null);
|
||||
setBusyScope(null);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<MobileShell
|
||||
activeTab="uploads"
|
||||
@@ -270,7 +330,7 @@ export default function MobileEventPhotosPage() {
|
||||
<LimitWarnings
|
||||
limits={limits}
|
||||
addons={catalogAddons}
|
||||
onCheckout={(scopeOrKey) => { void handleCheckout(scopeOrKey, slug, catalogAddons, setBusyScope, t); }}
|
||||
onCheckout={startAddonCheckout}
|
||||
busyScope={busyScope}
|
||||
translate={translateLimits(t)}
|
||||
textColor={text}
|
||||
@@ -465,6 +525,18 @@ export default function MobileEventPhotosPage() {
|
||||
<EventAddonList addons={eventAddons} textColor={text} mutedColor={muted} />
|
||||
</YStack>
|
||||
) : null}
|
||||
|
||||
<LegalConsentSheet
|
||||
open={consentOpen}
|
||||
onClose={() => {
|
||||
if (consentBusy) return;
|
||||
setConsentOpen(false);
|
||||
setConsentTarget(null);
|
||||
}}
|
||||
onConfirm={confirmAddonCheckout}
|
||||
busy={consentBusy}
|
||||
t={t}
|
||||
/>
|
||||
</MobileShell>
|
||||
);
|
||||
}
|
||||
@@ -648,45 +720,3 @@ function EventAddonList({ addons, textColor, mutedColor }: { addons: EventAddonS
|
||||
</YStack>
|
||||
);
|
||||
}
|
||||
|
||||
async function handleCheckout(
|
||||
scopeOrKey: 'photos' | 'gallery' | 'guests' | string,
|
||||
slug: string | null,
|
||||
addons: EventAddonCatalogItem[],
|
||||
setBusyScope: (scope: string | null) => void,
|
||||
t: (key: string, defaultValue?: string) => string,
|
||||
): Promise<void> {
|
||||
if (!slug) return;
|
||||
const scope =
|
||||
scopeOrKey === 'photos' || scopeOrKey === 'gallery' || scopeOrKey === 'guests'
|
||||
? scopeOrKey
|
||||
: scopeOrKey.includes('gallery')
|
||||
? 'gallery'
|
||||
: scopeOrKey.includes('guest')
|
||||
? 'guests'
|
||||
: 'photos';
|
||||
const addonKey =
|
||||
scopeOrKey === 'photos' || scopeOrKey === 'gallery' || scopeOrKey === 'guests'
|
||||
? selectAddonKeyForScope(addons, scope)
|
||||
: scopeOrKey;
|
||||
const currentUrl = typeof window !== 'undefined' ? `${window.location.origin}${adminPath(`/mobile/events/${slug}/photos`)}` : '';
|
||||
const successUrl = `${currentUrl}?addon_success=1`;
|
||||
setBusyScope(scope);
|
||||
try {
|
||||
const checkout = await createEventAddonCheckout(slug, {
|
||||
addon_key: addonKey,
|
||||
quantity: 1,
|
||||
success_url: successUrl,
|
||||
cancel_url: currentUrl,
|
||||
});
|
||||
if (checkout.checkout_url) {
|
||||
window.location.href = checkout.checkout_url;
|
||||
} else {
|
||||
toast.error(t('mobileBilling.checkoutUnavailable', 'Checkout unavailable right now.'));
|
||||
}
|
||||
} catch (err) {
|
||||
toast.error(getApiErrorMessage(err, t('mobileBilling.checkoutFailed', 'Checkout failed.')));
|
||||
} finally {
|
||||
setBusyScope(null);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user