feat: update package copy and admin control room
This commit is contained in:
131
resources/js/admin/mobile/components/LimitWarnings.tsx
Normal file
131
resources/js/admin/mobile/components/LimitWarnings.tsx
Normal file
@@ -0,0 +1,131 @@
|
||||
import React from 'react';
|
||||
import { XStack, YStack } from '@tamagui/stacks';
|
||||
import { SizableText as Text } from '@tamagui/text';
|
||||
import { buildLimitWarnings } from '../../lib/limitWarnings';
|
||||
import type { EventAddonCatalogItem, EventLimitSummary } from '../../api';
|
||||
import { scopeDefaults, selectAddonKeyForScope } from '../addons';
|
||||
import { CTAButton, MobileCard } from './Primitives';
|
||||
import { MobileSelect } from './FormControls';
|
||||
|
||||
type LimitTranslator = (key: string, options?: Record<string, unknown>) => string;
|
||||
|
||||
export function LimitWarnings({
|
||||
limits,
|
||||
addons,
|
||||
onCheckout,
|
||||
busyScope,
|
||||
translate,
|
||||
textColor,
|
||||
borderColor,
|
||||
}: {
|
||||
limits: EventLimitSummary | null;
|
||||
addons: EventAddonCatalogItem[];
|
||||
onCheckout: (scopeOrKey: 'photos' | 'gallery' | string) => void;
|
||||
busyScope: string | null;
|
||||
translate: LimitTranslator;
|
||||
textColor: string;
|
||||
borderColor: string;
|
||||
}) {
|
||||
const warnings = React.useMemo(() => buildLimitWarnings(limits, translate), [limits, translate]);
|
||||
|
||||
if (!warnings.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<YStack space="$2">
|
||||
{warnings.map((warning) => (
|
||||
<MobileCard key={warning.id} borderColor={borderColor} space="$2">
|
||||
<Text fontSize="$sm" color={textColor} fontWeight="700">
|
||||
{warning.message}
|
||||
</Text>
|
||||
{(warning.scope === 'photos' || warning.scope === 'gallery' || warning.scope === 'guests')
|
||||
&& resolveAddonOptions(addons, warning.scope).length ? (
|
||||
<MobileAddonsPicker
|
||||
scope={warning.scope}
|
||||
addons={addons}
|
||||
busy={busyScope === warning.scope}
|
||||
onCheckout={onCheckout}
|
||||
translate={translate}
|
||||
/>
|
||||
) : (
|
||||
<CTAButton
|
||||
label={
|
||||
warning.scope === 'photos'
|
||||
? translate('buyMorePhotos')
|
||||
: warning.scope === 'gallery'
|
||||
? translate('extendGallery')
|
||||
: translate('buyMoreGuests')
|
||||
}
|
||||
onPress={() => onCheckout(warning.scope)}
|
||||
loading={busyScope === warning.scope}
|
||||
/>
|
||||
)}
|
||||
</MobileCard>
|
||||
))}
|
||||
</YStack>
|
||||
);
|
||||
}
|
||||
|
||||
function resolveAddonOptions(addons: EventAddonCatalogItem[], scope: 'photos' | 'gallery' | 'guests'): EventAddonCatalogItem[] {
|
||||
const whitelist = scopeDefaults[scope];
|
||||
const filtered = addons.filter((addon) => addon.price_id && whitelist.includes(addon.key));
|
||||
return filtered.length ? filtered : addons.filter((addon) => addon.price_id);
|
||||
}
|
||||
|
||||
function MobileAddonsPicker({
|
||||
scope,
|
||||
addons,
|
||||
busy,
|
||||
onCheckout,
|
||||
translate,
|
||||
}: {
|
||||
scope: 'photos' | 'gallery' | 'guests';
|
||||
addons: EventAddonCatalogItem[];
|
||||
busy: boolean;
|
||||
onCheckout: (addonKey: string) => void;
|
||||
translate: LimitTranslator;
|
||||
}) {
|
||||
const options = React.useMemo(() => resolveAddonOptions(addons, scope), [addons, scope]);
|
||||
const [selected, setSelected] = React.useState<string>(() => options[0]?.key ?? selectAddonKeyForScope(addons, scope));
|
||||
|
||||
React.useEffect(() => {
|
||||
if (options[0]?.key) {
|
||||
setSelected(options[0].key);
|
||||
}
|
||||
}, [options]);
|
||||
|
||||
if (!options.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<XStack space="$2" alignItems="center">
|
||||
<MobileSelect
|
||||
value={selected}
|
||||
onChange={(event) => setSelected(event.target.value)}
|
||||
containerStyle={{ flex: 1, minWidth: 0 }}
|
||||
compact
|
||||
>
|
||||
{options.map((addon) => (
|
||||
<option key={addon.key} value={addon.key}>
|
||||
{addon.label ?? addon.key}
|
||||
</option>
|
||||
))}
|
||||
</MobileSelect>
|
||||
<CTAButton
|
||||
label={
|
||||
scope === 'gallery'
|
||||
? translate('extendGallery')
|
||||
: scope === 'guests'
|
||||
? translate('buyMoreGuests')
|
||||
: translate('buyMorePhotos')
|
||||
}
|
||||
disabled={!selected || busy}
|
||||
onPress={() => selected && onCheckout(selected)}
|
||||
loading={busy}
|
||||
fullWidth={false}
|
||||
/>
|
||||
</XStack>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user