POWR/app/(packs)/manage.tsx

238 lines
8.0 KiB
TypeScript
Raw Permalink Normal View History

// app/(packs)/manage.tsx
import React, { useState, useEffect } from 'react';
import { View, ScrollView, StyleSheet, TouchableOpacity } from 'react-native';
import { router, Stack } from 'expo-router';
import { Text } from '@/components/ui/text';
import { Button } from '@/components/ui/button';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
import { Separator } from '@/components/ui/separator';
import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle } from '@/components/ui/alert-dialog';
import { POWRPackWithContent } from '@/types/powr-pack';
import { usePOWRPackService } from '@/components/DatabaseProvider';
import { formatDistanceToNow } from 'date-fns';
import { Trash2, PackageOpen, Plus, X } from 'lucide-react-native';
import { useIconColor } from '@/lib/theme/iconUtils';
import { useColorScheme } from '@/lib/theme/useColorScheme';
import { COLORS } from '@/lib/theme/colors';
import { FIXED_COLORS } from '@/lib/theme/colors';
export default function ManagePOWRPacksScreen() {
const powrPackService = usePOWRPackService();
const [packs, setPacks] = useState<POWRPackWithContent[]>([]);
const [isLoading, setIsLoading] = useState(true);
const [selectedPackId, setSelectedPackId] = useState<string | null>(null);
const [showDeleteDialog, setShowDeleteDialog] = useState(false);
const { getIconProps } = useIconColor();
const { isDarkColorScheme } = useColorScheme();
// Load imported packs
useEffect(() => {
loadPacks();
}, []);
// Function to load imported packs
const loadPacks = async () => {
setIsLoading(true);
try {
const importedPacks = await powrPackService.getImportedPacks();
setPacks(importedPacks);
} catch (error) {
console.error('Error loading packs:', error);
} finally {
setIsLoading(false);
}
};
// Handle import button click
const handleImport = () => {
router.push('/(packs)/import');
};
// Handle close button press
const handleClose = () => {
router.back();
};
// Handle delete button click
const handleDeleteClick = (packId: string) => {
setSelectedPackId(packId);
setShowDeleteDialog(true);
};
// Handle delete confirmation
const handleDeleteConfirm = async () => {
if (!selectedPackId) return;
try {
// Always delete everything (we no longer need the keepItems parameter)
await powrPackService.deletePack(selectedPackId, false);
// Refresh the list
loadPacks();
} catch (error) {
console.error('Error deleting pack:', error);
} finally {
setShowDeleteDialog(false);
setSelectedPackId(null);
}
};
// Format import date
const formatImportDate = (timestamp: number): string => {
return formatDistanceToNow(new Date(timestamp), { addSuffix: true });
};
return (
<View style={styles.container}>
<Stack.Screen
options={{
title: 'Manage POWR Packs',
headerShown: true,
// Add a close button for iOS
headerRight: () => (
<TouchableOpacity onPress={handleClose} style={styles.closeButton}>
<X {...getIconProps('primary')} size={24} />
</TouchableOpacity>
),
}}
/>
<ScrollView contentContainerStyle={styles.scrollContent}>
{/* Import button */}
<Button
onPress={handleImport}
className="mb-4"
style={{ backgroundColor: COLORS.purple.DEFAULT }}
>
<Text style={{ color: '#fff', fontWeight: '500' }}>Import New Pack</Text>
</Button>
{/* No packs message */}
{!isLoading && packs.length === 0 && (
<Card>
<CardContent className="py-8 items-center">
<PackageOpen size={48} {...getIconProps('muted')} />
<Text className="text-lg font-medium mt-4 text-center text-foreground">No POWR Packs Imported</Text>
<Text className="text-center mt-2 text-muted-foreground">
Import workout packs shared by the community to get started.
</Text>
<Button
onPress={handleImport}
className="mt-4"
style={{ backgroundColor: COLORS.purple.DEFAULT }}
>
<Text style={{ color: '#fff', fontWeight: '500' }}>Import Your First Pack</Text>
</Button>
</CardContent>
</Card>
)}
{/* Pack list */}
{packs.map((packWithContent) => {
const { pack, templates, exercises } = packWithContent;
return (
<Card key={pack.id} className="mb-4">
<CardHeader>
<View style={styles.cardHeaderContent}>
<View style={styles.cardHeaderText}>
<CardTitle>
<Text className="text-lg font-semibold text-foreground">{pack.title}</Text>
</CardTitle>
{pack.description && (
<CardDescription>
<Text className="text-muted-foreground">{pack.description}</Text>
</CardDescription>
)}
</View>
<TouchableOpacity
onPress={() => handleDeleteClick(pack.id)}
style={styles.deleteButton}
>
<Trash2 {...getIconProps('destructive')} size={20} />
</TouchableOpacity>
</View>
</CardHeader>
<CardContent>
<View style={styles.statsRow}>
<Text className="text-muted-foreground">
{templates.length} template{templates.length !== 1 ? 's' : ''} {exercises.length} exercise{exercises.length !== 1 ? 's' : ''}
</Text>
</View>
<Separator className="my-2" />
<Text className="text-sm text-muted-foreground">
Imported {formatImportDate(pack.importDate)}
</Text>
</CardContent>
</Card>
);
})}
</ScrollView>
{/* Delete confirmation dialog */}
<AlertDialog open={showDeleteDialog} onOpenChange={setShowDeleteDialog}>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>
<Text className="text-xl font-semibold text-foreground">Delete Pack</Text>
</AlertDialogTitle>
<AlertDialogDescription>
<Text className="text-muted-foreground">
This will remove the POWR Pack and all its associated templates and exercises from your library.
</Text>
</AlertDialogDescription>
</AlertDialogHeader>
<View className="flex-row justify-end gap-3">
<AlertDialogCancel asChild>
<Button variant="outline" className="mr-2">
<Text>Cancel</Text>
</Button>
</AlertDialogCancel>
<AlertDialogAction asChild>
<Button
variant="destructive"
onPress={handleDeleteConfirm}
style={{ backgroundColor: FIXED_COLORS.destructive }}
>
<Text style={{ color: '#FFFFFF' }}>Delete Pack</Text>
</Button>
</AlertDialogAction>
</View>
</AlertDialogContent>
</AlertDialog>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 16,
},
scrollContent: {
paddingBottom: 80,
},
cardHeaderContent: {
flexDirection: 'row',
justifyContent: 'space-between',
width: '100%',
},
cardHeaderText: {
flex: 1,
},
deleteButton: {
padding: 8,
},
statsRow: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
marginBottom: 4,
},
dialogActions: {
flexDirection: 'row',
justifyContent: 'flex-end',
},
closeButton: {
padding: 8,
}
});