POWR/components/templates/TemplateCard.tsx
2025-02-09 20:38:38 -05:00

248 lines
8.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// components/templates/TemplateCard.tsx
import React from 'react';
import { View, TouchableOpacity, Platform } from 'react-native';
import { Text } from '@/components/ui/text';
import { Card, CardContent } from '@/components/ui/card';
import { Button } from '@/components/ui/button';
import { Badge } from '@/components/ui/badge';
import { Trash2, Star, Play } from 'lucide-react-native';
import {
AlertDialog,
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
AlertDialogTrigger,
} from '@/components/ui/alert-dialog';
import { Sheet, SheetContent, SheetHeader, SheetTitle } from '@/components/ui/sheet';
import { Template } from '@/types/library';
interface TemplateCardProps {
template: Template;
onPress: () => void;
onDelete: (id: string) => void;
onFavorite: () => void;
onStartWorkout: () => void;
}
export function TemplateCard({
template,
onPress,
onDelete,
onFavorite,
onStartWorkout
}: TemplateCardProps) {
const [showSheet, setShowSheet] = React.useState(false);
const [showDeleteAlert, setShowDeleteAlert] = React.useState(false);
const {
id,
title,
type,
category,
exercises,
description,
tags = [],
source,
lastUsed,
isFavorite
} = template;
const handleConfirmDelete = () => {
onDelete(id);
setShowDeleteAlert(false);
};
const handleCardPress = () => {
setShowSheet(true);
onPress();
};
return (
<>
<TouchableOpacity onPress={handleCardPress} activeOpacity={0.7}>
<Card className="mx-4">
<CardContent className="p-4">
<View className="flex-row justify-between items-start">
<View className="flex-1">
<View className="flex-row items-center gap-2 mb-1">
<Text className="text-lg font-semibold text-card-foreground">
{title}
</Text>
<Badge
variant={source === 'local' ? 'outline' : 'secondary'}
className="text-xs capitalize"
>
<Text>{source}</Text>
</Badge>
</View>
<View className="flex-row gap-2">
<Badge variant="outline" className="text-xs capitalize">
<Text>{type}</Text>
</Badge>
<Text className="text-sm text-muted-foreground">
{category}
</Text>
</View>
{exercises.length > 0 && (
<View className="mt-2">
<Text className="text-sm text-muted-foreground mb-1">
Exercises:
</Text>
<View className="gap-1">
{exercises.slice(0, 3).map((exercise, index) => (
<Text key={index} className="text-sm text-muted-foreground">
{exercise.title} ({exercise.targetSets}×{exercise.targetReps})
</Text>
))}
{exercises.length > 3 && (
<Text className="text-sm text-muted-foreground">
+{exercises.length - 3} more
</Text>
)}
</View>
</View>
)}
{description && (
<Text className="text-sm text-muted-foreground mt-2 native:pr-12">
{description}
</Text>
)}
{tags.length > 0 && (
<View className="flex-row flex-wrap gap-2 mt-2">
{tags.map(tag => (
<Badge key={tag} variant="outline" className="text-xs">
<Text>{tag}</Text>
</Badge>
))}
</View>
)}
{lastUsed && (
<Text className="text-xs text-muted-foreground mt-2">
Last used: {lastUsed.toLocaleDateString()}
</Text>
)}
</View>
<View className="flex-row gap-1 native:absolute native:right-0 native:top-0 native:p-2">
<Button
variant="ghost"
size="icon"
onPress={onStartWorkout}
className="native:h-10 native:w-10"
>
<Play className="text-primary" size={20} />
</Button>
<Button
variant="ghost"
size="icon"
onPress={onFavorite}
className="native:h-10 native:w-10"
>
<Star
className={isFavorite ? "text-primary" : "text-muted-foreground"}
fill={isFavorite ? "currentColor" : "none"}
size={20}
/>
</Button>
<AlertDialog open={showDeleteAlert} onOpenChange={setShowDeleteAlert}>
<AlertDialogTrigger asChild>
<Button
variant="ghost"
size="icon"
className="native:h-10 native:w-10 native:bg-muted/50 items-center justify-center"
>
<Trash2
size={20}
color={Platform.select({
ios: undefined,
android: '#8B5CF6'
})}
className="text-destructive"
/>
</Button>
</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>
<Text>Delete Template</Text>
</AlertDialogTitle>
<AlertDialogDescription>
<Text>Are you sure you want to delete {title}? This action cannot be undone.</Text>
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>
<Text>Cancel</Text>
</AlertDialogCancel>
<AlertDialogAction onPress={handleConfirmDelete}>
<Text>Delete</Text>
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
</View>
</View>
</CardContent>
</Card>
</TouchableOpacity>
{/* Sheet for detailed view */}
<Sheet isOpen={showSheet} onClose={() => setShowSheet(false)}>
<SheetHeader>
<SheetTitle>
<Text className="text-xl font-bold">{title}</Text>
</SheetTitle>
</SheetHeader>
<SheetContent>
<View className="gap-6">
{description && (
<View>
<Text className="text-base font-semibold mb-2">Description</Text>
<Text className="text-base leading-relaxed">{description}</Text>
</View>
)}
<View>
<Text className="text-base font-semibold mb-2">Details</Text>
<View className="gap-2">
<Text className="text-base">Type: {type}</Text>
<Text className="text-base">Category: {category}</Text>
<Text className="text-base">Source: {source}</Text>
</View>
</View>
<View>
<Text className="text-base font-semibold mb-2">Exercises</Text>
<View className="gap-2">
{exercises.map((exercise, index) => (
<Text key={index} className="text-base">
{exercise.title} ({exercise.targetSets}×{exercise.targetReps})
</Text>
))}
</View>
</View>
{tags.length > 0 && (
<View>
<Text className="text-base font-semibold mb-2">Tags</Text>
<View className="flex-row flex-wrap gap-2">
{tags.map(tag => (
<Badge key={tag} variant="secondary">
<Text>{tag}</Text>
</Badge>
))}
</View>
</View>
)}
</View>
</SheetContent>
</Sheet>
</>
);
}