fixed notification system and added a new tenant notifications receipt table to track read status and filter messages by scope.

This commit is contained in:
Codex Agent
2025-12-17 10:57:19 +01:00
parent 0aae494945
commit d64839ba2f
31 changed files with 1089 additions and 127 deletions

View File

@@ -266,6 +266,18 @@ export default function MobileEventPhotosPage() {
))}
</XStack>
{!loading ? (
<LimitWarnings
limits={limits}
addons={catalogAddons}
onCheckout={(scopeOrKey) => { void handleCheckout(scopeOrKey, slug, catalogAddons, setBusyScope, t); }}
busyScope={busyScope}
translate={translateLimits(t)}
textColor={text}
borderColor={border}
/>
) : null}
{loading ? (
<YStack space="$2">
{Array.from({ length: 4 }).map((_, idx) => (
@@ -281,15 +293,6 @@ export default function MobileEventPhotosPage() {
</MobileCard>
) : (
<YStack space="$3">
<LimitWarnings
limits={limits}
addons={catalogAddons}
onCheckout={(scopeOrKey) => { void handleCheckout(scopeOrKey, slug, catalogAddons, setBusyScope, t); }}
busyScope={busyScope}
translate={translateLimits(t)}
textColor={text}
borderColor={border}
/>
<Text fontSize="$sm" color={muted}>
{t('mobilePhotos.count', '{{count}} photos', { count: totalCount })}
</Text>
@@ -490,6 +493,7 @@ function translateLimits(t: (key: string, defaultValue?: string, options?: Recor
galleryWarningDays: 'Gallery expires in {{days}} days.',
buyMorePhotos: 'Buy more photos',
extendGallery: 'Extend gallery',
buyMoreGuests: 'Add more guests',
};
return (key, options) => t(`limits.${key}`, defaults[key] ?? key, options);
}
@@ -524,7 +528,7 @@ function LimitWarnings({
<Text fontSize="$sm" color={textColor} fontWeight="700">
{warning.message}
</Text>
{(warning.scope === 'photos' || warning.scope === 'gallery') && addons.length ? (
{(warning.scope === 'photos' || warning.scope === 'gallery' || warning.scope === 'guests') && addons.length ? (
<MobileAddonsPicker
scope={warning.scope}
addons={addons}
@@ -539,7 +543,7 @@ function LimitWarnings({
? translate('buyMorePhotos')
: warning.scope === 'gallery'
? translate('extendGallery')
: translate('buyMorePhotos')
: translate('buyMoreGuests')
}
onPress={() => onCheckout(warning.scope)}
loading={busyScope === warning.scope}
@@ -557,7 +561,7 @@ function MobileAddonsPicker({
onCheckout,
translate,
}: {
scope: 'photos' | 'gallery';
scope: 'photos' | 'gallery' | 'guests';
addons: EventAddonCatalogItem[];
busy: boolean;
onCheckout: (addonKey: string) => void;
@@ -603,7 +607,13 @@ function MobileAddonsPicker({
))}
</select>
<CTAButton
label={scope === 'gallery' ? translate('extendGallery') : translate('buyMorePhotos')}
label={
scope === 'gallery'
? translate('extendGallery')
: scope === 'guests'
? translate('buyMoreGuests')
: translate('buyMorePhotos')
}
disabled={!selected || busy}
onPress={() => selected && onCheckout(selected)}
loading={busy}
@@ -640,15 +650,25 @@ function EventAddonList({ addons, textColor, mutedColor }: { addons: EventAddonS
}
async function handleCheckout(
scopeOrKey: 'photos' | 'gallery' | string,
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 : scopeOrKey.includes('gallery') ? 'gallery' : 'photos';
const addonKey = scopeOrKey === 'photos' || scopeOrKey === 'gallery' ? selectAddonKeyForScope(addons, scope) : scopeOrKey;
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);