upgrade to tamagui v2 and guest pwa overhaul
This commit is contained in:
170
resources/js/guest-v2/screens/ShareScreen.tsx
Normal file
170
resources/js/guest-v2/screens/ShareScreen.tsx
Normal file
@@ -0,0 +1,170 @@
|
||||
import React from 'react';
|
||||
import { YStack, XStack } from '@tamagui/stacks';
|
||||
import { SizableText as Text } from '@tamagui/text';
|
||||
import { Button } from '@tamagui/button';
|
||||
import { Share2, QrCode, Link, Users } from 'lucide-react';
|
||||
import AppShell from '../components/AppShell';
|
||||
import { useEventData } from '../context/EventDataContext';
|
||||
import { buildEventShareLink } from '../services/eventLink';
|
||||
import { useAppearance } from '@/hooks/use-appearance';
|
||||
import { useTranslation } from '@/guest/i18n/useTranslation';
|
||||
|
||||
export default function ShareScreen() {
|
||||
const { event, token } = useEventData();
|
||||
const { t } = useTranslation();
|
||||
const { resolved } = useAppearance();
|
||||
const isDark = resolved === 'dark';
|
||||
const cardBorder = isDark ? 'rgba(255, 255, 255, 0.12)' : 'rgba(15, 23, 42, 0.12)';
|
||||
const cardShadow = isDark ? '0 18px 40px rgba(2, 6, 23, 0.4)' : '0 16px 30px rgba(15, 23, 42, 0.12)';
|
||||
const [copyState, setCopyState] = React.useState<'idle' | 'copied' | 'failed'>('idle');
|
||||
const shareUrl = buildEventShareLink(event, token);
|
||||
const qrUrl = shareUrl
|
||||
? `https://api.qrserver.com/v1/create-qr-code/?size=240x240&data=${encodeURIComponent(shareUrl)}`
|
||||
: '';
|
||||
|
||||
const handleCopy = React.useCallback(async () => {
|
||||
if (!shareUrl) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await navigator.clipboard?.writeText(shareUrl);
|
||||
setCopyState('copied');
|
||||
} catch (error) {
|
||||
console.error('Copy failed', error);
|
||||
setCopyState('failed');
|
||||
} finally {
|
||||
window.setTimeout(() => setCopyState('idle'), 2000);
|
||||
}
|
||||
}, [shareUrl]);
|
||||
|
||||
const handleShare = React.useCallback(async () => {
|
||||
if (!shareUrl) return;
|
||||
const title = event?.name ?? t('share.defaultEvent', 'Fotospiel');
|
||||
const data: ShareData = { title, text: title, url: shareUrl };
|
||||
if (navigator.share && (!navigator.canShare || navigator.canShare(data))) {
|
||||
try {
|
||||
await navigator.share(data);
|
||||
} catch (error) {
|
||||
// user dismissed
|
||||
}
|
||||
} else {
|
||||
await handleCopy();
|
||||
}
|
||||
}, [event?.name, handleCopy, shareUrl]);
|
||||
|
||||
return (
|
||||
<AppShell>
|
||||
<YStack gap="$4">
|
||||
<YStack
|
||||
padding="$4"
|
||||
borderRadius="$card"
|
||||
backgroundColor="$surface"
|
||||
borderWidth={1}
|
||||
borderColor={cardBorder}
|
||||
gap="$2"
|
||||
style={{
|
||||
boxShadow: cardShadow,
|
||||
}}
|
||||
>
|
||||
<XStack alignItems="center" gap="$2">
|
||||
<Share2 size={18} color={isDark ? '#F8FAFF' : '#0F172A'} />
|
||||
<Text fontSize="$4" fontWeight="$7">
|
||||
{t('share.invite.title', 'Invite guests')}
|
||||
</Text>
|
||||
</XStack>
|
||||
<Text fontSize="$2" color="$color" opacity={0.7}>
|
||||
{t('share.invite.description', 'Share the event link or show the QR code to join.')}
|
||||
</Text>
|
||||
</YStack>
|
||||
|
||||
<XStack gap="$3">
|
||||
<YStack
|
||||
flex={1}
|
||||
height={180}
|
||||
borderRadius="$card"
|
||||
backgroundColor="$muted"
|
||||
borderWidth={1}
|
||||
borderColor={cardBorder}
|
||||
alignItems="center"
|
||||
justifyContent="center"
|
||||
gap="$2"
|
||||
style={{
|
||||
backgroundImage: isDark
|
||||
? 'radial-gradient(circle at 30% 30%, rgba(255, 79, 216, 0.2), transparent 55%)'
|
||||
: 'radial-gradient(circle at 30% 30%, color-mix(in oklab, var(--guest-primary, #FF5A5F) 18%, white), transparent 60%)',
|
||||
}}
|
||||
>
|
||||
{qrUrl ? (
|
||||
<img
|
||||
src={qrUrl}
|
||||
alt={t('share.invite.qrAlt', 'Event QR code')}
|
||||
style={{ width: 120, height: 120, borderRadius: 16 }}
|
||||
/>
|
||||
) : (
|
||||
<QrCode size={28} color={isDark ? '#F8FAFF' : '#0F172A'} />
|
||||
)}
|
||||
<Text fontSize="$3" fontWeight="$7">
|
||||
{t('share.invite.qrLabel', 'Show QR')}
|
||||
</Text>
|
||||
</YStack>
|
||||
<YStack
|
||||
flex={1}
|
||||
height={180}
|
||||
borderRadius="$card"
|
||||
backgroundColor="$surface"
|
||||
borderWidth={1}
|
||||
borderColor={cardBorder}
|
||||
alignItems="center"
|
||||
justifyContent="center"
|
||||
gap="$2"
|
||||
style={{
|
||||
boxShadow: isDark ? '0 16px 30px rgba(2, 6, 23, 0.35)' : '0 14px 24px rgba(15, 23, 42, 0.12)',
|
||||
}}
|
||||
>
|
||||
<Link size={24} color={isDark ? '#F8FAFF' : '#0F172A'} />
|
||||
<Text fontSize="$3" fontWeight="$7">
|
||||
{copyState === 'copied'
|
||||
? t('share.copySuccess', 'Copied')
|
||||
: copyState === 'failed'
|
||||
? t('share.copyError', 'Copy failed')
|
||||
: t('share.invite.copyLabel', 'Copy link')}
|
||||
</Text>
|
||||
<Button size="$2" backgroundColor="$primary" borderRadius="$pill" onPress={handleCopy} disabled={!shareUrl}>
|
||||
{t('share.copyLink', 'Copy link')}
|
||||
</Button>
|
||||
</YStack>
|
||||
</XStack>
|
||||
|
||||
<YStack
|
||||
padding="$4"
|
||||
borderRadius="$card"
|
||||
backgroundColor="$surface"
|
||||
borderWidth={1}
|
||||
borderColor={cardBorder}
|
||||
gap="$3"
|
||||
style={{
|
||||
backgroundImage: isDark
|
||||
? 'linear-gradient(135deg, rgba(79, 209, 255, 0.12), rgba(255, 79, 216, 0.18))'
|
||||
: 'linear-gradient(135deg, color-mix(in oklab, var(--guest-secondary, #F43F5E) 8%, white), color-mix(in oklab, var(--guest-primary, #FF5A5F) 12%, white))',
|
||||
boxShadow: isDark ? '0 22px 44px rgba(2, 6, 23, 0.45)' : '0 18px 32px rgba(15, 23, 42, 0.12)',
|
||||
}}
|
||||
>
|
||||
<XStack alignItems="center" gap="$2">
|
||||
<Users size={18} color={isDark ? '#F8FAFF' : '#0F172A'} />
|
||||
<Text fontSize="$4" fontWeight="$7">
|
||||
{t('share.invite.guestsTitle', 'Guests joined')}
|
||||
</Text>
|
||||
</XStack>
|
||||
<Text fontSize="$2" color="$color" opacity={0.7}>
|
||||
{event?.name
|
||||
? t('share.invite.guestsSubtitleEvent', 'Share {event} with your guests.', { event: event.name })
|
||||
: t('share.invite.guestsSubtitle', 'Share the event with your guests.')}
|
||||
</Text>
|
||||
<Button size="$3" backgroundColor="$primary" borderRadius="$pill" alignSelf="flex-start" onPress={handleShare}>
|
||||
{t('share.invite.send', 'Send invite')}
|
||||
</Button>
|
||||
</YStack>
|
||||
</YStack>
|
||||
</AppShell>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user