Refactor event tasks tabs
This commit is contained in:
@@ -10,7 +10,6 @@ import { ListItem } from '@tamagui/list-item';
|
||||
import { Pressable } from '@tamagui/react-native-web-lite';
|
||||
import { Button } from '@tamagui/button';
|
||||
import { AlertDialog } from '@tamagui/alert-dialog';
|
||||
import { ScrollView } from '@tamagui/scroll-view';
|
||||
import { Switch } from '@tamagui/switch';
|
||||
import { Checkbox } from '@tamagui/checkbox';
|
||||
import { Tabs } from 'tamagui';
|
||||
@@ -47,8 +46,7 @@ import { Tag } from './components/Tag';
|
||||
import { useEventContext } from '../context/EventContext';
|
||||
import { RadioGroup } from '@tamagui/radio-group';
|
||||
import { useBackNavigation } from './hooks/useBackNavigation';
|
||||
import { buildTaskSummary } from './lib/taskSummary';
|
||||
import { buildTaskSectionCounts, type TaskSectionKey } from './lib/taskSectionCounts';
|
||||
import { type TaskSectionKey } from './lib/taskSectionCounts';
|
||||
import { withAlpha } from './components/colors';
|
||||
import { useAdminTheme } from './theme';
|
||||
import { resolveEngagementMode } from '../lib/events';
|
||||
@@ -97,7 +95,7 @@ export default function MobileEventTasksPage() {
|
||||
const [library, setLibrary] = React.useState<TenantTask[]>([]);
|
||||
const [collections, setCollections] = React.useState<TenantTaskCollection[]>([]);
|
||||
const [emotions, setEmotions] = React.useState<TenantEmotion[]>([]);
|
||||
const [showCollectionSheet, setShowCollectionSheet] = React.useState(false);
|
||||
const [activeTab, setActiveTab] = React.useState<TaskSectionKey>('assigned');
|
||||
const [showTaskSheet, setShowTaskSheet] = React.useState(false);
|
||||
const [newTask, setNewTask] = React.useState({
|
||||
id: null as number | null,
|
||||
@@ -131,19 +129,10 @@ export default function MobileEventTasksPage() {
|
||||
const [savingEmotion, setSavingEmotion] = React.useState(false);
|
||||
const [showEmotionFilterSheet, setShowEmotionFilterSheet] = React.useState(false);
|
||||
const [showTaskDetails, setShowTaskDetails] = React.useState(false);
|
||||
const [quickNavSelection, setQuickNavSelection] = React.useState<TaskSectionKey | ''>('');
|
||||
const [eventRecord, setEventRecord] = React.useState<TenantEvent | null>(null);
|
||||
const [tasksToggleBusy, setTasksToggleBusy] = React.useState(false);
|
||||
const text = textStrong;
|
||||
const assignedRef = React.useRef<HTMLDivElement>(null);
|
||||
const libraryRef = React.useRef<HTMLDivElement>(null);
|
||||
const back = useBackNavigation(slug ? adminPath(`/mobile/events/${slug}`) : adminPath('/mobile/events'));
|
||||
const summary = buildTaskSummary({
|
||||
assigned: assignedTasks.length,
|
||||
library: library.length,
|
||||
collections: collections.length,
|
||||
emotions: emotions.length,
|
||||
});
|
||||
const permissionSource = eventRecord ?? activeEvent;
|
||||
const memberPermissions = Array.isArray(permissionSource?.member_permissions) ? permissionSource?.member_permissions ?? [] : [];
|
||||
const canManageTasks = React.useMemo(
|
||||
@@ -151,7 +140,6 @@ export default function MobileEventTasksPage() {
|
||||
[isMember, memberPermissions]
|
||||
);
|
||||
const tasksEnabled = resolveEngagementMode(permissionSource ?? null) !== 'photo_only';
|
||||
const sectionCounts = React.useMemo(() => buildTaskSectionCounts(summary), [summary]);
|
||||
const maxTasks = React.useMemo(() => {
|
||||
const limit = eventRecord?.limits?.tasks?.limit;
|
||||
return typeof limit === 'number' && Number.isFinite(limit) ? limit : null;
|
||||
@@ -187,34 +175,6 @@ export default function MobileEventTasksPage() {
|
||||
setSearchTerm('');
|
||||
}, [slug]);
|
||||
|
||||
const scrollToSection = (ref: React.RefObject<HTMLDivElement | null>) => {
|
||||
if (ref.current) {
|
||||
ref.current.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
||||
}
|
||||
};
|
||||
|
||||
const handleQuickNav = (key: TaskSectionKey) => {
|
||||
if (key === 'assigned') {
|
||||
scrollToSection(assignedRef);
|
||||
return;
|
||||
}
|
||||
if (key === 'library') {
|
||||
scrollToSection(libraryRef);
|
||||
return;
|
||||
}
|
||||
if (key === 'collections') {
|
||||
setShowCollectionSheet(true);
|
||||
return;
|
||||
}
|
||||
setShowEmotionSheet(true);
|
||||
};
|
||||
|
||||
const handleQuickNavPress = (key: TaskSectionKey) => {
|
||||
if (quickNavSelection === key) {
|
||||
handleQuickNav(key);
|
||||
}
|
||||
};
|
||||
|
||||
const load = React.useCallback(async () => {
|
||||
if (!slug) {
|
||||
try {
|
||||
@@ -654,7 +614,7 @@ export default function MobileEventTasksPage() {
|
||||
<CTAButton
|
||||
label={t('events.tasks.emptyActionPack', 'Import photo task pack')}
|
||||
tone="ghost"
|
||||
onPress={() => setShowCollectionSheet(true)}
|
||||
onPress={() => setActiveTab('collections')}
|
||||
disabled={!canAddTasks}
|
||||
fullWidth={false}
|
||||
/>
|
||||
@@ -708,7 +668,7 @@ export default function MobileEventTasksPage() {
|
||||
toast.error(limitReachedMessage);
|
||||
return;
|
||||
}
|
||||
setShowCollectionSheet(true);
|
||||
setActiveTab('collections');
|
||||
}}
|
||||
title={
|
||||
<XStack alignItems="center" space="$2">
|
||||
@@ -741,7 +701,6 @@ export default function MobileEventTasksPage() {
|
||||
</YStack>
|
||||
) : (
|
||||
<YStack space="$2">
|
||||
<YStack ref={assignedRef} />
|
||||
<XStack alignItems="center" flexWrap="wrap" space="$2">
|
||||
<Text fontSize="$sm" color={muted}>
|
||||
{t('events.tasks.count', '{{count}} photo tasks', { count: filteredTasks.length })}
|
||||
@@ -845,29 +804,41 @@ export default function MobileEventTasksPage() {
|
||||
</YGroup.Item>
|
||||
))}
|
||||
</YGroup>
|
||||
<XStack justifyContent="space-between" alignItems="center" marginTop="$2">
|
||||
<YStack ref={libraryRef} />
|
||||
<Text fontSize={12.5} fontWeight="600" color={text}>
|
||||
{t('events.tasks.library', 'Weitere Fotoaufgaben')}
|
||||
</YStack>
|
||||
);
|
||||
|
||||
const libraryPanel = (
|
||||
<YStack space="$2">
|
||||
<XStack alignItems="center" justifyContent="space-between" flexWrap="wrap">
|
||||
<Text fontSize="$sm" fontWeight="700" color={text}>
|
||||
{t('events.tasks.tabs.library', 'Task Library')}
|
||||
</Text>
|
||||
<Pressable onPress={() => setShowCollectionSheet(true)}>
|
||||
<Pressable onPress={() => setActiveTab('collections')}>
|
||||
<Text fontSize={12} fontWeight="600" color={primary}>
|
||||
{t('events.tasks.import', 'Import photo task pack')}
|
||||
</Text>
|
||||
</Pressable>
|
||||
</XStack>
|
||||
<Pressable onPress={() => setExpandedLibrary((prev) => !prev)}>
|
||||
<Text fontSize={12} fontWeight="600" color={primary}>
|
||||
{expandedLibrary ? t('events.tasks.hideLibrary', 'Hide library') : t('events.tasks.viewAllLibrary', 'View all')}
|
||||
{!canAddTasks ? (
|
||||
<Text fontSize={12} fontWeight="600" color={dangerText}>
|
||||
{limitReachedMessage}
|
||||
{limitReachedHint ? ` ${limitReachedHint}` : ''}
|
||||
</Text>
|
||||
</Pressable>
|
||||
) : null}
|
||||
{library.length > 6 ? (
|
||||
<Pressable onPress={() => setExpandedLibrary((prev) => !prev)}>
|
||||
<Text fontSize={12} fontWeight="600" color={primary}>
|
||||
{expandedLibrary ? t('events.tasks.hideLibrary', 'Hide library') : t('events.tasks.viewAllLibrary', 'View all')}
|
||||
</Text>
|
||||
</Pressable>
|
||||
) : null}
|
||||
{library.length === 0 ? (
|
||||
<Text fontSize={12} fontWeight="500" color={subtle}>
|
||||
{t('events.tasks.libraryEmpty', 'Keine weiteren Fotoaufgaben verfügbar.')}
|
||||
{t('events.tasks.libraryEmpty', 'No more photo tasks available.')}
|
||||
</Text>
|
||||
) : (
|
||||
<YGroup {...({ borderWidth: 1, borderColor: border, borderRadius: "$4", overflow: "hidden" } as any)}>
|
||||
{(expandedLibrary ? library : library.slice(0, 6)).map((task, idx, arr) => (
|
||||
{(expandedLibrary ? library : library.slice(0, 6)).map((task) => (
|
||||
<YGroup.Item key={`lib-${task.id}`}>
|
||||
<ListItem
|
||||
hoverTheme
|
||||
@@ -915,6 +886,134 @@ export default function MobileEventTasksPage() {
|
||||
</YStack>
|
||||
);
|
||||
|
||||
const collectionsPanel = (
|
||||
<YStack space="$2">
|
||||
<Text fontSize="$xs" color={muted}>
|
||||
{t('events.tasks.importHint', 'Use predefined packs for your event type.')}
|
||||
</Text>
|
||||
{!canAddTasks ? (
|
||||
<Text fontSize={12} fontWeight="600" color={dangerText}>
|
||||
{limitReachedMessage}
|
||||
{limitReachedHint ? ` ${limitReachedHint}` : ''}
|
||||
</Text>
|
||||
) : null}
|
||||
{collections.length > 6 ? (
|
||||
<Pressable onPress={() => setExpandedCollections((prev) => !prev)}>
|
||||
<Text fontSize={12} fontWeight="600" color={primary}>
|
||||
{expandedCollections ? t('events.tasks.hideCollections', 'Hide collections') : t('events.tasks.showCollections', 'Show all')}
|
||||
</Text>
|
||||
</Pressable>
|
||||
) : null}
|
||||
{collections.length === 0 ? (
|
||||
<Text fontSize={13} fontWeight="500" color={muted}>
|
||||
{t('events.tasks.collectionsEmpty', 'No collections available.')}
|
||||
</Text>
|
||||
) : (
|
||||
<YGroup {...({ borderWidth: 1, borderColor: border, borderRadius: "$4", overflow: "hidden" } as any)}>
|
||||
{(expandedCollections ? collections : collections.slice(0, 6)).map((collection) => (
|
||||
<YGroup.Item key={collection.id}>
|
||||
<ListItem
|
||||
hoverTheme
|
||||
pressTheme
|
||||
title={
|
||||
<Text fontSize={12.5} fontWeight="600" color={text}>
|
||||
{collection.name}
|
||||
</Text>
|
||||
}
|
||||
subTitle={
|
||||
collection.description ? (
|
||||
<Text fontSize={11.5} fontWeight="400" color={subtle}>
|
||||
{collection.description}
|
||||
</Text>
|
||||
) : null
|
||||
}
|
||||
iconAfter={
|
||||
<XStack space="$1.5" alignItems="center">
|
||||
<Pressable
|
||||
onPress={() => {
|
||||
if (!canAddTasks) {
|
||||
toast.error(limitReachedMessage);
|
||||
return;
|
||||
}
|
||||
importCollection(collection.id);
|
||||
}}
|
||||
>
|
||||
<Text fontSize={12} fontWeight="600" color={canAddTasks ? primary : muted}>
|
||||
{t('events.tasks.import', 'Import')}
|
||||
</Text>
|
||||
</Pressable>
|
||||
<ChevronRight size={14} color={subtle} />
|
||||
</XStack>
|
||||
}
|
||||
paddingVertical="$2"
|
||||
paddingHorizontal="$3"
|
||||
/>
|
||||
</YGroup.Item>
|
||||
))}
|
||||
</YGroup>
|
||||
)}
|
||||
</YStack>
|
||||
);
|
||||
|
||||
const emotionsPanel = (
|
||||
<YStack space="$2">
|
||||
<XStack alignItems="center" justifyContent="space-between" flexWrap="wrap">
|
||||
<Text fontSize="$sm" fontWeight="700" color={text}>
|
||||
{t('events.tasks.tabs.emotions', 'Emotions')}
|
||||
</Text>
|
||||
<CTAButton
|
||||
label={t('events.tasks.addEmotion', 'Add emotion')}
|
||||
fullWidth={false}
|
||||
onPress={() => {
|
||||
setEditingEmotion(null);
|
||||
setEmotionForm({ name: '', color: border });
|
||||
setShowEmotionSheet(true);
|
||||
}}
|
||||
/>
|
||||
</XStack>
|
||||
{emotions.length === 0 ? (
|
||||
<Text fontSize={12} fontWeight="500" color={muted}>
|
||||
{t('events.tasks.emotionsEmpty', 'No emotions yet. Add one to help categorize tasks.')}
|
||||
</Text>
|
||||
) : (
|
||||
<YGroup {...({ borderWidth: 1, borderColor: border, borderRadius: "$4", overflow: "hidden" } as any)}>
|
||||
{emotions.map((emotion) => (
|
||||
<YGroup.Item key={`emo-${emotion.id}`}>
|
||||
<ListItem
|
||||
hoverTheme
|
||||
pressTheme
|
||||
title={
|
||||
<XStack alignItems="center" space="$2">
|
||||
<Tag label={emotion.name ?? ''} color={emotion.color ?? border} />
|
||||
</XStack>
|
||||
}
|
||||
iconAfter={
|
||||
<XStack space="$2">
|
||||
<Pressable
|
||||
onPress={() => {
|
||||
setEditingEmotion(emotion);
|
||||
setEmotionForm({ name: emotion.name ?? '', color: emotion.color ?? border });
|
||||
setShowEmotionSheet(true);
|
||||
}}
|
||||
>
|
||||
<Pencil size={14} color={primary} />
|
||||
</Pressable>
|
||||
<Pressable onPress={() => removeEmotion(emotion.id)}>
|
||||
<Trash2 size={14} color={danger} />
|
||||
</Pressable>
|
||||
<ChevronRight size={14} color={subtle} />
|
||||
</XStack>
|
||||
}
|
||||
paddingVertical="$2"
|
||||
paddingHorizontal="$3"
|
||||
/>
|
||||
</YGroup.Item>
|
||||
))}
|
||||
</YGroup>
|
||||
)}
|
||||
</YStack>
|
||||
);
|
||||
|
||||
return (
|
||||
<MobileShell
|
||||
activeTab="tasks"
|
||||
@@ -1024,212 +1123,80 @@ export default function MobileEventTasksPage() {
|
||||
))}
|
||||
</YStack>
|
||||
) : (
|
||||
<YStack space="$2">
|
||||
<Card
|
||||
borderRadius={22}
|
||||
borderWidth={2}
|
||||
borderColor={border}
|
||||
backgroundColor={surface}
|
||||
padding="$3"
|
||||
>
|
||||
<YStack space="$2.5">
|
||||
<XStack alignItems="center" justifyContent="space-between">
|
||||
<XStack
|
||||
alignItems="center"
|
||||
paddingHorizontal="$3"
|
||||
paddingVertical="$1.5"
|
||||
borderRadius={999}
|
||||
borderWidth={1}
|
||||
borderColor={border}
|
||||
backgroundColor={surfaceMuted}
|
||||
<Tabs value={activeTab} onValueChange={(value) => setActiveTab(value as TaskSectionKey)}>
|
||||
<Tabs.List>
|
||||
<Tabs.Tab value="assigned">{t('events.tasks.tabs.tasks', 'Tasks')}</Tabs.Tab>
|
||||
<Tabs.Tab value="library">{t('events.tasks.tabs.library', 'Task Library')}</Tabs.Tab>
|
||||
<Tabs.Tab value="emotions">{t('events.tasks.tabs.emotions', 'Emotions')}</Tabs.Tab>
|
||||
<Tabs.Tab value="collections">{t('events.tasks.tabs.collections', 'Collections')}</Tabs.Tab>
|
||||
</Tabs.List>
|
||||
|
||||
<Tabs.Content value="assigned" paddingTop="$2">
|
||||
<YStack space="$2">
|
||||
<YStack className="admin-sticky-toolbar">
|
||||
<Card
|
||||
borderRadius={20}
|
||||
borderWidth={2}
|
||||
borderColor={stickyBorder}
|
||||
backgroundColor={stickySurface}
|
||||
padding="$3"
|
||||
shadowColor={stickyShadow}
|
||||
shadowOpacity={0.16}
|
||||
shadowRadius={16}
|
||||
shadowOffset={{ width: 0, height: 10 }}
|
||||
>
|
||||
<Text fontSize="$xs" fontWeight="800" color={text}>
|
||||
{t('events.tasks.quickNav', 'Quick jump')}
|
||||
</Text>
|
||||
</XStack>
|
||||
</XStack>
|
||||
|
||||
<ScrollView horizontal showsHorizontalScrollIndicator={false}>
|
||||
<Tabs
|
||||
value={quickNavSelection}
|
||||
onValueChange={(next) => {
|
||||
const key = next as TaskSectionKey | '';
|
||||
if (!key) {
|
||||
return;
|
||||
}
|
||||
setQuickNavSelection(key);
|
||||
handleQuickNav(key);
|
||||
}}
|
||||
orientation="horizontal"
|
||||
>
|
||||
<Tabs.List backgroundColor="transparent" borderWidth={0} paddingVertical="$1" gap="$2">
|
||||
{sectionCounts.map((section) => {
|
||||
const isActive = quickNavSelection === section.key;
|
||||
const activeBorder = withAlpha(primary, 0.45);
|
||||
const activeBackground = withAlpha(primary, 0.16);
|
||||
return (
|
||||
<Tabs.Tab
|
||||
key={section.key}
|
||||
value={section.key}
|
||||
unstyled
|
||||
onPress={() => handleQuickNavPress(section.key)}
|
||||
borderRadius={999}
|
||||
borderWidth={1}
|
||||
borderColor={isActive ? activeBorder : border}
|
||||
backgroundColor={isActive ? activeBackground : surface}
|
||||
paddingHorizontal="$3"
|
||||
paddingVertical="$2"
|
||||
height={36}
|
||||
pressStyle={{ backgroundColor: isActive ? activeBackground : surfaceMuted }}
|
||||
>
|
||||
<XStack alignItems="center" space="$1.5">
|
||||
<Text fontSize="$xs" fontWeight="700" color={textStrong}>
|
||||
{t(`events.tasks.sections.${section.key}`, section.key)}
|
||||
</Text>
|
||||
<XStack
|
||||
paddingHorizontal="$2"
|
||||
paddingVertical="$0.5"
|
||||
borderRadius={999}
|
||||
borderWidth={1}
|
||||
borderColor={isActive ? activeBorder : border}
|
||||
backgroundColor={surfaceMuted}
|
||||
>
|
||||
<Text fontSize={10} fontWeight="800" color={textStrong}>
|
||||
{section.count}
|
||||
</Text>
|
||||
</XStack>
|
||||
</XStack>
|
||||
</Tabs.Tab>
|
||||
);
|
||||
})}
|
||||
</Tabs.List>
|
||||
</Tabs>
|
||||
</ScrollView>
|
||||
</YStack>
|
||||
</Card>
|
||||
|
||||
<div className="admin-sticky-toolbar">
|
||||
<Card
|
||||
borderRadius={20}
|
||||
borderWidth={2}
|
||||
borderColor={stickyBorder}
|
||||
backgroundColor={stickySurface}
|
||||
padding="$3"
|
||||
shadowColor={stickyShadow}
|
||||
shadowOpacity={0.16}
|
||||
shadowRadius={16}
|
||||
shadowOffset={{ width: 0, height: 10 }}
|
||||
>
|
||||
<XStack alignItems="center" space="$2">
|
||||
<XStack flex={1}>
|
||||
<MobileInput
|
||||
type="search"
|
||||
value={searchTerm}
|
||||
onChange={(e) => setSearchTerm(e.target.value)}
|
||||
placeholder={t('events.tasks.search', 'Search photo tasks')}
|
||||
compact
|
||||
/>
|
||||
</XStack>
|
||||
<Pressable onPress={() => setShowEmotionFilterSheet(true)}>
|
||||
<XStack
|
||||
alignItems="center"
|
||||
space="$1.5"
|
||||
paddingVertical="$2"
|
||||
paddingHorizontal="$3"
|
||||
borderRadius={14}
|
||||
borderWidth={1}
|
||||
borderColor={border}
|
||||
backgroundColor={surface}
|
||||
>
|
||||
<Text fontSize={11} fontWeight="700" color={text}>
|
||||
{t('events.tasks.emotionFilterShort', 'Emotion')}
|
||||
</Text>
|
||||
<Text fontSize={11} color={muted}>
|
||||
{emotionFilter
|
||||
? emotions.find((e) => String(e.id) === emotionFilter)?.name ?? t('events.tasks.customEmotion', 'Custom emotion')
|
||||
: t('events.tasks.allEmotions', 'All')}
|
||||
</Text>
|
||||
<ChevronDown size={14} color={muted} />
|
||||
</XStack>
|
||||
</Pressable>
|
||||
</XStack>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
{taskPanel}
|
||||
</YStack>
|
||||
)}
|
||||
|
||||
<MobileSheet
|
||||
open={showCollectionSheet}
|
||||
onClose={() => setShowCollectionSheet(false)}
|
||||
title={t('events.tasks.import', 'Fotoaufgabenpaket importieren')}
|
||||
footer={null}
|
||||
>
|
||||
<YStack space="$2">
|
||||
{!canAddTasks ? (
|
||||
<Text fontSize={12} fontWeight="600" color={dangerText}>
|
||||
{limitReachedMessage}
|
||||
{limitReachedHint ? ` ${limitReachedHint}` : ''}
|
||||
</Text>
|
||||
) : null}
|
||||
{collections.length > 6 ? (
|
||||
<Pressable onPress={() => setExpandedCollections((prev) => !prev)}>
|
||||
<Text fontSize={12} fontWeight="600" color={primary}>
|
||||
{expandedCollections ? t('events.tasks.hideCollections', 'Hide collections') : t('events.tasks.showCollections', 'Show all')}
|
||||
</Text>
|
||||
</Pressable>
|
||||
) : null}
|
||||
{collections.length === 0 ? (
|
||||
<Text fontSize={13} fontWeight="500" color={muted}>
|
||||
{t('events.tasks.collectionsEmpty', 'Keine Pakete vorhanden.')}
|
||||
</Text>
|
||||
) : (
|
||||
<YGroup {...({ borderWidth: 1, borderColor: border, borderRadius: "$4", overflow: "hidden" } as any)}>
|
||||
{(expandedCollections ? collections : collections.slice(0, 6)).map((collection, idx, arr) => (
|
||||
<YGroup.Item key={collection.id}>
|
||||
<ListItem
|
||||
hoverTheme
|
||||
pressTheme
|
||||
title={
|
||||
<Text fontSize={12.5} fontWeight="600" color={text}>
|
||||
{collection.name}
|
||||
</Text>
|
||||
}
|
||||
subTitle={
|
||||
collection.description ? (
|
||||
<Text fontSize={11.5} fontWeight="400" color={subtle}>
|
||||
{collection.description}
|
||||
<XStack alignItems="center" space="$2">
|
||||
<XStack flex={1}>
|
||||
<MobileInput
|
||||
type="search"
|
||||
value={searchTerm}
|
||||
onChange={(e) => setSearchTerm(e.target.value)}
|
||||
placeholder={t('events.tasks.search', 'Search photo tasks')}
|
||||
compact
|
||||
/>
|
||||
</XStack>
|
||||
<Pressable onPress={() => setShowEmotionFilterSheet(true)}>
|
||||
<XStack
|
||||
alignItems="center"
|
||||
space="$1.5"
|
||||
paddingVertical="$2"
|
||||
paddingHorizontal="$3"
|
||||
borderRadius={14}
|
||||
borderWidth={1}
|
||||
borderColor={border}
|
||||
backgroundColor={surface}
|
||||
>
|
||||
<Text fontSize={11} fontWeight="700" color={text}>
|
||||
{t('events.tasks.emotionFilterShort', 'Emotion')}
|
||||
</Text>
|
||||
) : null
|
||||
}
|
||||
iconAfter={
|
||||
<XStack space="$1.5" alignItems="center">
|
||||
<Pressable
|
||||
onPress={() => {
|
||||
if (!canAddTasks) {
|
||||
toast.error(limitReachedMessage);
|
||||
return;
|
||||
}
|
||||
importCollection(collection.id);
|
||||
}}
|
||||
>
|
||||
<Text fontSize={12} fontWeight="600" color={canAddTasks ? primary : muted}>
|
||||
{t('events.tasks.import', 'Import')}
|
||||
</Text>
|
||||
</Pressable>
|
||||
<ChevronRight size={14} color={subtle} />
|
||||
<Text fontSize={11} color={muted}>
|
||||
{emotionFilter
|
||||
? emotions.find((e) => String(e.id) === emotionFilter)?.name ?? t('events.tasks.customEmotion', 'Custom emotion')
|
||||
: t('events.tasks.allEmotions', 'All')}
|
||||
</Text>
|
||||
<ChevronDown size={14} color={muted} />
|
||||
</XStack>
|
||||
}
|
||||
paddingVertical="$2"
|
||||
paddingHorizontal="$3"
|
||||
/>
|
||||
</YGroup.Item>
|
||||
))}
|
||||
</YGroup>
|
||||
)}
|
||||
</YStack>
|
||||
</MobileSheet>
|
||||
</Pressable>
|
||||
</XStack>
|
||||
</Card>
|
||||
</YStack>
|
||||
{taskPanel}
|
||||
</YStack>
|
||||
</Tabs.Content>
|
||||
|
||||
<Tabs.Content value="library" paddingTop="$2">
|
||||
{libraryPanel}
|
||||
</Tabs.Content>
|
||||
|
||||
<Tabs.Content value="emotions" paddingTop="$2">
|
||||
{emotionsPanel}
|
||||
</Tabs.Content>
|
||||
|
||||
<Tabs.Content value="collections" paddingTop="$2">
|
||||
{collectionsPanel}
|
||||
</Tabs.Content>
|
||||
</Tabs>
|
||||
)}
|
||||
|
||||
<MobileSheet
|
||||
open={showTaskSheet}
|
||||
@@ -1355,39 +1322,6 @@ export default function MobileEventTasksPage() {
|
||||
style={{ padding: 0 }}
|
||||
/>
|
||||
</MobileField>
|
||||
<YGroup {...({ borderWidth: 1, borderColor: border, borderRadius: "$4", overflow: "hidden" } as any)}>
|
||||
{emotions.map((em, idx) => (
|
||||
<YGroup.Item key={`emo-${em.id}`}>
|
||||
<ListItem
|
||||
hoverTheme
|
||||
pressTheme
|
||||
title={
|
||||
<XStack alignItems="center" space="$2">
|
||||
<Tag label={em.name ?? ''} color={em.color ?? border} />
|
||||
</XStack>
|
||||
}
|
||||
iconAfter={
|
||||
<XStack space="$2">
|
||||
<Pressable
|
||||
onPress={() => {
|
||||
setEditingEmotion(em);
|
||||
setEmotionForm({ name: em.name ?? '', color: em.color ?? border });
|
||||
}}
|
||||
>
|
||||
<Pencil size={14} color={primary} />
|
||||
</Pressable>
|
||||
<Pressable onPress={() => removeEmotion(em.id)}>
|
||||
<Trash2 size={14} color={danger} />
|
||||
</Pressable>
|
||||
<ChevronRight size={14} color={subtle} />
|
||||
</XStack>
|
||||
}
|
||||
paddingVertical="$2"
|
||||
paddingHorizontal="$3"
|
||||
/>
|
||||
</YGroup.Item>
|
||||
))}
|
||||
</YGroup>
|
||||
</YStack>
|
||||
</MobileSheet>
|
||||
|
||||
@@ -1619,7 +1553,7 @@ export default function MobileEventTasksPage() {
|
||||
}
|
||||
onPress={() => {
|
||||
setShowFabMenu(false);
|
||||
setShowEmotionSheet(true);
|
||||
setActiveTab('emotions');
|
||||
}}
|
||||
paddingVertical="$2"
|
||||
paddingHorizontal="$3"
|
||||
|
||||
Reference in New Issue
Block a user