upgrade to tamagui v2 and guest pwa overhaul

This commit is contained in:
Codex Agent
2026-02-02 13:01:20 +01:00
parent 2e78f3ab8d
commit 7c6e14ffe2
168 changed files with 47462 additions and 8914 deletions

View File

@@ -65,7 +65,7 @@ export default function MobilePackageShopPage() {
onBack={() => navigate(-1)}
activeTab="profile"
>
<YStack space="$3">
<YStack gap="$3">
<SkeletonCard height={150} />
<SkeletonCard height={150} />
</YStack>
@@ -125,10 +125,10 @@ export default function MobilePackageShopPage() {
onBack={() => navigate(-1)}
activeTab="profile"
>
<YStack space="$4">
<YStack gap="$4">
{catalogType !== 'reseller' && recommendedFeature && (
<MobileCard borderColor={primary} backgroundColor={accentSoft} space="$2" padding="$3">
<XStack space="$2" alignItems="center">
<MobileCard borderColor={primary} backgroundColor={accentSoft} gap="$2" padding="$3">
<XStack gap="$2" alignItems="center">
<Sparkles size={16} color={primary} />
<Text fontSize="$sm" fontWeight="700" color={textStrong}>
{t('shop.recommendationTitle', 'Recommended for you')}
@@ -149,7 +149,7 @@ export default function MobilePackageShopPage() {
</YStack>
{packageEntries.length > 1 ? (
<XStack space="$2" paddingHorizontal="$2">
<XStack gap="$2" paddingHorizontal="$2">
<CTAButton
label={t('shop.compare.toggleCards', 'Cards')}
tone={viewMode === 'cards' ? 'primary' : 'ghost'}
@@ -167,7 +167,7 @@ export default function MobilePackageShopPage() {
</XStack>
) : null}
<YStack space="$3">
<YStack gap="$3">
{viewMode === 'compare' ? (
<PackageShopCompareView
entries={packageEntries}
@@ -234,14 +234,14 @@ function PackageShopCard({
onPress={handlePress}
borderColor={isRecommended ? primary : (isActive ? '$green8' : border)}
borderWidth={isRecommended || isActive ? 2 : 1}
space="$3"
gap="$3"
pressStyle={handlePress ? { backgroundColor: accentSoft } : undefined}
backgroundColor={isActive ? '$green1' : undefined}
style={{ opacity: isSubdued ? 0.6 : 1 }}
>
<XStack justifyContent="space-between" alignItems="flex-start">
<YStack space="$1">
<XStack space="$2" alignItems="center">
<YStack gap="$1">
<XStack gap="$2" alignItems="center">
<Text fontSize="$lg" fontWeight="800" color={textStrong}>
{pkg.name}
</Text>
@@ -255,7 +255,7 @@ function PackageShopCard({
{!isResellerCatalog && isActive ? <PillBadge tone="success">{t('shop.badges.active', 'Active')}</PillBadge> : null}
</XStack>
<XStack space="$2" alignItems="center">
<XStack gap="$2" alignItems="center">
<Text fontSize="$md" color={primary} fontWeight="700">
{new Intl.NumberFormat(undefined, { style: 'currency', currency: 'EUR' }).format(pkg.price)}
</Text>
@@ -271,7 +271,7 @@ function PackageShopCard({
</YStack>
</XStack>
<YStack space="$1.5">
<YStack gap="$1.5">
{isResellerCatalog ? (
<>
{includedTierLabel ? (
@@ -333,7 +333,7 @@ function PackageShopCard({
function FeatureRow({ label }: { label: string }) {
const { textStrong, primary } = useAdminTheme();
return (
<XStack alignItems="center" space="$2">
<XStack alignItems="center" gap="$2">
<Check size={14} color={primary} />
<Text fontSize="$sm" color={textStrong}>{label}</Text>
</XStack>
@@ -411,8 +411,8 @@ function PackageShopCompareView({
};
return (
<MobileCard space="$3" borderColor={border}>
<YStack space="$1">
<MobileCard gap="$3" borderColor={border}>
<YStack gap="$1">
<Text fontSize="$md" fontWeight="700" color={textStrong}>
{t('shop.compare.title', 'Compare plans')}
</Text>
@@ -422,7 +422,7 @@ function PackageShopCompareView({
</YStack>
<XStack style={{ overflowX: 'auto' }}>
<YStack space="$1.5" minWidth={labelWidth + columnWidth * entries.length}>
<YStack gap="$1.5" minWidth={labelWidth + columnWidth * entries.length}>
{rows.map((row) => (
<XStack key={row.id} borderBottomWidth={1} borderColor={border}>
<YStack
@@ -443,11 +443,11 @@ function PackageShopCompareView({
if (row.id === 'meta.plan') {
const statusLabel = getPackageStatusLabel({ t, isActive: entry.isActive, owned: entry.owned });
content = (
<YStack space="$1">
<YStack gap="$1">
<Text fontSize="$sm" fontWeight="800" color={textStrong}>
{entry.pkg.name}
</Text>
<XStack space="$1.5" flexWrap="wrap">
<XStack gap="$1.5" flexWrap="wrap">
{entry.isRecommended ? (
<PillBadge tone="warning">{t('shop.badges.recommended', 'Recommended')}</PillBadge>
) : null}
@@ -492,7 +492,7 @@ function PackageShopCompareView({
} else if (row.type === 'feature') {
const enabled = getEnabledPackageFeatures(entry.pkg).includes(row.featureKey);
content = (
<XStack alignItems="center" space="$1.5">
<XStack alignItems="center" gap="$1.5">
{enabled ? (
<Check size={16} color={primary} />
) : (
@@ -607,8 +607,8 @@ function CheckoutConfirmation({ pkg, onCancel }: { pkg: Package; onCancel: () =>
return (
<MobileShell title={t('shop.confirmTitle', 'Confirm Purchase')} onBack={onCancel} activeTab="profile">
<YStack space="$4">
<MobileCard space="$2" borderColor={border}>
<YStack gap="$4">
<MobileCard gap="$2" borderColor={border}>
<Text fontSize="$sm" color={muted}>{subtitle}</Text>
<Text fontSize="$xl" fontWeight="800" color={textStrong}>{pkg.name}</Text>
<Text fontSize="$lg" color={primary} fontWeight="700">
@@ -616,13 +616,13 @@ function CheckoutConfirmation({ pkg, onCancel }: { pkg: Package; onCancel: () =>
</Text>
</MobileCard>
<MobileCard space="$3" borderColor={border}>
<XStack alignItems="center" space="$2">
<MobileCard gap="$3" borderColor={border}>
<XStack alignItems="center" gap="$2">
<ShieldCheck size={18} color={textStrong} />
<Text fontSize="$md" fontWeight="700" color={textStrong}>{t('shop.legalTitle', 'Terms & Conditions')}</Text>
</XStack>
<XStack space="$3" alignItems="flex-start">
<XStack gap="$3" alignItems="flex-start">
<Checkbox
id="agb"
size="$4"
@@ -638,7 +638,7 @@ function CheckoutConfirmation({ pkg, onCancel }: { pkg: Package; onCancel: () =>
</Text>
</XStack>
<XStack space="$3" alignItems="flex-start">
<XStack gap="$3" alignItems="flex-start">
<Checkbox
id="withdrawal"
size="$4"
@@ -655,7 +655,7 @@ function CheckoutConfirmation({ pkg, onCancel }: { pkg: Package; onCancel: () =>
</XStack>
</MobileCard>
<YStack space="$2">
<YStack gap="$2">
<CTAButton
label={busy ? t('shop.processing', 'Processing...') : t('shop.payNow', 'Pay Now')}
onPress={handleCheckout}