Refine guest v2 gallery empty states
This commit is contained in:
@@ -2,7 +2,7 @@ import React from 'react';
|
|||||||
import { YStack, XStack } from '@tamagui/stacks';
|
import { YStack, XStack } from '@tamagui/stacks';
|
||||||
import { SizableText as Text } from '@tamagui/text';
|
import { SizableText as Text } from '@tamagui/text';
|
||||||
import { Button } from '@tamagui/button';
|
import { Button } from '@tamagui/button';
|
||||||
import { Image as ImageIcon, Filter } from 'lucide-react';
|
import { Camera, Image as ImageIcon, Filter } from 'lucide-react';
|
||||||
import AppShell from '../components/AppShell';
|
import AppShell from '../components/AppShell';
|
||||||
import PhotoFrameTile from '../components/PhotoFrameTile';
|
import PhotoFrameTile from '../components/PhotoFrameTile';
|
||||||
import { useEventData } from '../context/EventDataContext';
|
import { useEventData } from '../context/EventDataContext';
|
||||||
@@ -56,6 +56,7 @@ export default function GalleryScreen() {
|
|||||||
const [loading, setLoading] = React.useState(false);
|
const [loading, setLoading] = React.useState(false);
|
||||||
const { data: delta } = usePollGalleryDelta(token ?? null, { locale });
|
const { data: delta } = usePollGalleryDelta(token ?? null, { locale });
|
||||||
const [filter, setFilter] = React.useState<GalleryFilter>('latest');
|
const [filter, setFilter] = React.useState<GalleryFilter>('latest');
|
||||||
|
const uploadPath = React.useMemo(() => buildEventPath(token ?? null, '/upload'), [token]);
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (!token) {
|
if (!token) {
|
||||||
@@ -139,6 +140,8 @@ export default function GalleryScreen() {
|
|||||||
const displayPhotos = filteredPhotos;
|
const displayPhotos = filteredPhotos;
|
||||||
const leftColumn = displayPhotos.filter((_, index) => index % 2 === 0);
|
const leftColumn = displayPhotos.filter((_, index) => index % 2 === 0);
|
||||||
const rightColumn = displayPhotos.filter((_, index) => index % 2 === 1);
|
const rightColumn = displayPhotos.filter((_, index) => index % 2 === 1);
|
||||||
|
const isEmpty = !loading && displayPhotos.length === 0;
|
||||||
|
const isSingle = !loading && displayPhotos.length === 1;
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (filter === 'photobooth' && !photos.some((photo) => photo.ingestSource === 'photobooth')) {
|
if (filter === 'photobooth' && !photos.some((photo) => photo.ingestSource === 'photobooth')) {
|
||||||
@@ -265,10 +268,88 @@ export default function GalleryScreen() {
|
|||||||
</XStack>
|
</XStack>
|
||||||
</YStack>
|
</YStack>
|
||||||
|
|
||||||
<XStack gap="$3">
|
{isEmpty ? (
|
||||||
<YStack flex={1} gap="$3">
|
<YStack
|
||||||
{(loading || leftColumn.length === 0 ? Array.from({ length: 5 }, (_, index) => index) : leftColumn).map(
|
padding="$4"
|
||||||
(tile, index) => {
|
borderRadius="$card"
|
||||||
|
backgroundColor="$surface"
|
||||||
|
borderWidth={1}
|
||||||
|
borderColor={cardBorder}
|
||||||
|
gap="$3"
|
||||||
|
alignItems="center"
|
||||||
|
style={{
|
||||||
|
boxShadow: cardShadow,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<YStack
|
||||||
|
width={64}
|
||||||
|
height={64}
|
||||||
|
borderRadius={20}
|
||||||
|
backgroundColor="$primary"
|
||||||
|
alignItems="center"
|
||||||
|
justifyContent="center"
|
||||||
|
style={{ boxShadow: cardShadow }}
|
||||||
|
>
|
||||||
|
<Camera size={28} color="#FFFFFF" />
|
||||||
|
</YStack>
|
||||||
|
<Text fontSize="$4" fontWeight="$7" textAlign="center">
|
||||||
|
{t('galleryPage.emptyTitle', 'Noch keine Fotos')}
|
||||||
|
</Text>
|
||||||
|
<Text fontSize="$2" color="$color" opacity={0.7} textAlign="center">
|
||||||
|
{t('galleryPage.emptyDescription', 'Lade das erste Foto hoch und starte die Galerie.')}
|
||||||
|
</Text>
|
||||||
|
<Button
|
||||||
|
size="$3"
|
||||||
|
backgroundColor="$primary"
|
||||||
|
borderRadius="$pill"
|
||||||
|
onPress={() => navigate(uploadPath)}
|
||||||
|
>
|
||||||
|
<Text fontSize="$2" fontWeight="$7" color="#FFFFFF">
|
||||||
|
{t('galleryPage.emptyCta', 'Foto hochladen')}
|
||||||
|
</Text>
|
||||||
|
</Button>
|
||||||
|
</YStack>
|
||||||
|
) : isSingle ? (
|
||||||
|
<YStack gap="$3">
|
||||||
|
<Button unstyled onPress={() => openLightbox(displayPhotos[0].id)}>
|
||||||
|
<PhotoFrameTile height={360} borderRadius="$card">
|
||||||
|
<YStack flex={1} width="100%" height="100%" alignItems="center" justifyContent="center">
|
||||||
|
<img
|
||||||
|
src={displayPhotos[0].imageUrl}
|
||||||
|
alt={t('galleryPage.photo.alt', { id: displayPhotos[0].id }, 'Photo {id}')}
|
||||||
|
style={{ width: '100%', height: '100%', objectFit: 'cover' }}
|
||||||
|
/>
|
||||||
|
</YStack>
|
||||||
|
</PhotoFrameTile>
|
||||||
|
</Button>
|
||||||
|
<Button unstyled onPress={() => navigate(uploadPath)}>
|
||||||
|
<PhotoFrameTile height={160} borderRadius="$card">
|
||||||
|
<YStack flex={1} alignItems="center" justifyContent="center" gap="$2" padding="$3">
|
||||||
|
<YStack
|
||||||
|
width={48}
|
||||||
|
height={48}
|
||||||
|
borderRadius={16}
|
||||||
|
backgroundColor="$primary"
|
||||||
|
alignItems="center"
|
||||||
|
justifyContent="center"
|
||||||
|
style={{ boxShadow: cardShadow }}
|
||||||
|
>
|
||||||
|
<Camera size={20} color="#FFFFFF" />
|
||||||
|
</YStack>
|
||||||
|
<Text fontSize="$3" fontWeight="$7" textAlign="center">
|
||||||
|
{t('galleryPage.promptTitle', 'Füge dein nächstes Foto hinzu')}
|
||||||
|
</Text>
|
||||||
|
<Text fontSize="$2" color="$color" opacity={0.7} textAlign="center">
|
||||||
|
{t('galleryPage.promptDescription', 'Teile den Moment mit allen Gästen.')}
|
||||||
|
</Text>
|
||||||
|
</YStack>
|
||||||
|
</PhotoFrameTile>
|
||||||
|
</Button>
|
||||||
|
</YStack>
|
||||||
|
) : (
|
||||||
|
<XStack gap="$3">
|
||||||
|
<YStack flex={1} gap="$3">
|
||||||
|
{(loading ? Array.from({ length: 5 }, (_, index) => index) : leftColumn).map((tile, index) => {
|
||||||
if (typeof tile === 'number') {
|
if (typeof tile === 'number') {
|
||||||
return <PhotoFrameTile key={`left-${tile}`} height={140 + (index % 3) * 24} shimmer shimmerDelayMs={200 + index * 120} />;
|
return <PhotoFrameTile key={`left-${tile}`} height={140 + (index % 3) * 24} shimmer shimmerDelayMs={200 + index * 120} />;
|
||||||
}
|
}
|
||||||
@@ -289,12 +370,10 @@ export default function GalleryScreen() {
|
|||||||
</PhotoFrameTile>
|
</PhotoFrameTile>
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
}
|
})}
|
||||||
)}
|
</YStack>
|
||||||
</YStack>
|
<YStack flex={1} gap="$3">
|
||||||
<YStack flex={1} gap="$3">
|
{(loading ? Array.from({ length: 5 }, (_, index) => index) : rightColumn).map((tile, index) => {
|
||||||
{(loading || rightColumn.length === 0 ? Array.from({ length: 5 }, (_, index) => index) : rightColumn).map(
|
|
||||||
(tile, index) => {
|
|
||||||
if (typeof tile === 'number') {
|
if (typeof tile === 'number') {
|
||||||
return <PhotoFrameTile key={`right-${tile}`} height={120 + (index % 3) * 28} shimmer shimmerDelayMs={260 + index * 140} />;
|
return <PhotoFrameTile key={`right-${tile}`} height={120 + (index % 3) * 28} shimmer shimmerDelayMs={260 + index * 140} />;
|
||||||
}
|
}
|
||||||
@@ -315,10 +394,35 @@ export default function GalleryScreen() {
|
|||||||
</PhotoFrameTile>
|
</PhotoFrameTile>
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
}
|
})}
|
||||||
)}
|
{!loading && rightColumn.length === 0 ? (
|
||||||
</YStack>
|
<Button unstyled onPress={() => navigate(uploadPath)}>
|
||||||
</XStack>
|
<PhotoFrameTile height={180}>
|
||||||
|
<YStack flex={1} alignItems="center" justifyContent="center" gap="$2" padding="$3">
|
||||||
|
<YStack
|
||||||
|
width={46}
|
||||||
|
height={46}
|
||||||
|
borderRadius={16}
|
||||||
|
backgroundColor="$primary"
|
||||||
|
alignItems="center"
|
||||||
|
justifyContent="center"
|
||||||
|
style={{ boxShadow: cardShadow }}
|
||||||
|
>
|
||||||
|
<Camera size={20} color="#FFFFFF" />
|
||||||
|
</YStack>
|
||||||
|
<Text fontSize="$3" fontWeight="$7" textAlign="center">
|
||||||
|
{t('galleryPage.promptTitle', 'Füge dein nächstes Foto hinzu')}
|
||||||
|
</Text>
|
||||||
|
<Text fontSize="$2" color="$color" opacity={0.7} textAlign="center">
|
||||||
|
{t('galleryPage.promptDescription', 'Teile den Moment mit allen Gästen.')}
|
||||||
|
</Text>
|
||||||
|
</YStack>
|
||||||
|
</PhotoFrameTile>
|
||||||
|
</Button>
|
||||||
|
) : null}
|
||||||
|
</YStack>
|
||||||
|
</XStack>
|
||||||
|
)}
|
||||||
|
|
||||||
<YStack
|
<YStack
|
||||||
padding="$4"
|
padding="$4"
|
||||||
|
|||||||
Reference in New Issue
Block a user