// components/social/POWRPackSection.tsx import React, { useState } from 'react'; import { View, ScrollView, StyleSheet, TouchableOpacity, Image } from 'react-native'; import { router } from 'expo-router'; import { useNDK } from '@/lib/hooks/useNDK'; import { findTagValue } from '@/utils/nostr-utils'; import { Text } from '@/components/ui/text'; import { Card, CardContent } from '@/components/ui/card'; import { Button } from '@/components/ui/button'; import { Skeleton } from '@/components/ui/skeleton'; import { PackageOpen, ArrowRight, RefreshCw } from 'lucide-react-native'; import { NDKEvent } from '@nostr-dev-kit/ndk-mobile'; import { Clipboard } from 'react-native'; import { nip19 } from 'nostr-tools'; export default function POWRPackSection() { const { ndk } = useNDK(); const [isLoading, setIsLoading] = useState(false); const [featuredPacks, setFeaturedPacks] = useState([]); const [error, setError] = useState(null); // Manual fetch function const handleFetchPacks = async () => { if (!ndk) return; try { setIsLoading(true); setError(null); console.log('Manually fetching POWR packs'); const events = await ndk.fetchEvents({ kinds: [30004], "#t": ["powrpack"], limit: 20 }); const eventsArray = Array.from(events); console.log(`Fetched ${eventsArray.length} events`); // Filter to find POWR packs const powrPacks = eventsArray.filter(event => { // Check if any tag has 'powrpack', 'fitness', or 'workout' return event.tags.some(tag => tag[0] === 't' && ['powrpack', 'fitness', 'workout'].includes(tag[1]) ); }); console.log(`Found ${powrPacks.length} POWR packs`); setFeaturedPacks(powrPacks); } catch (err) { console.error('Error fetching packs:', err); setError(err instanceof Error ? err : new Error('Failed to fetch packs')); } finally { setIsLoading(false); } }; // Handle pack click const handlePackClick = (packEvent: NDKEvent) => { try { // Get dTag for the pack const dTag = findTagValue(packEvent.tags, 'd'); if (!dTag) { throw new Error('Pack is missing identifier (d tag)'); } // Get relay hints from event tags const relayHints = packEvent.tags .filter(tag => tag[0] === 'r') .map(tag => tag[1]) .filter(relay => relay.startsWith('wss://')); // Default relays if none found const relays = relayHints.length > 0 ? relayHints : ['wss://relay.damus.io', 'wss://nos.lol', 'wss://relay.nostr.band']; // Create shareable naddr const naddr = nip19.naddrEncode({ kind: 30004, pubkey: packEvent.pubkey, identifier: dTag, relays }); // Copy to clipboard Clipboard.setString(naddr); // Navigate to import screen router.push('/(packs)/import'); // Alert user that the address has been copied alert('Pack address copied to clipboard. Paste it in the import field.'); } catch (error) { console.error('Error handling pack click:', error); alert('Failed to prepare pack for import. Please try again.'); } }; // View all packs const handleViewAll = () => { router.push('/(packs)/manage'); }; // Fetch packs when mounted React.useEffect(() => { if (ndk) { handleFetchPacks(); } }, [ndk]); return ( POWR Packs View All {isLoading ? ( // Loading skeletons Array.from({ length: 3 }).map((_, index) => ( )) ) : featuredPacks.length > 0 ? ( // Pack cards featuredPacks.map(pack => { const title = findTagValue(pack.tags, 'name') || 'Unnamed Pack'; const description = findTagValue(pack.tags, 'about') || ''; const image = findTagValue(pack.tags, 'image') || null; const exerciseCount = pack.tags.filter(t => t[0] === 'a' && t[1].startsWith('33401')).length; const templateCount = pack.tags.filter(t => t[0] === 'a' && t[1].startsWith('33402')).length; return ( handlePackClick(pack)} activeOpacity={0.7} > {image ? ( ) : ( )} {title} {templateCount} template{templateCount !== 1 ? 's' : ''} • {exerciseCount} exercise{exerciseCount !== 1 ? 's' : ''} ); }) ) : error ? ( // Error state Error loading packs ) : ( // No packs found No packs found )} ); } const styles = StyleSheet.create({ container: { marginVertical: 16, }, header: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', paddingHorizontal: 16, marginBottom: 12, }, title: { fontSize: 18, fontWeight: '600', }, headerButtons: { flexDirection: 'row', alignItems: 'center', }, refreshButton: { padding: 8, marginRight: 8, }, viewAll: { flexDirection: 'row', alignItems: 'center', }, viewAllText: { fontSize: 14, color: '#6b7280', marginRight: 4, }, scrollContent: { paddingLeft: 16, paddingRight: 8, }, packCard: { width: 160, marginRight: 8, borderRadius: 12, }, cardContent: { padding: 8, }, packImage: { width: '100%', height: 90, borderRadius: 8, marginBottom: 8, }, placeholderImage: { width: '100%', height: 90, borderRadius: 8, backgroundColor: '#f3f4f6', marginBottom: 8, justifyContent: 'center', alignItems: 'center', }, packTitle: { fontSize: 14, fontWeight: '600', marginBottom: 4, }, packSubtitle: { fontSize: 12, color: '#6b7280', }, titleSkeleton: { height: 16, width: '80%', borderRadius: 4, marginBottom: 8, }, subtitleSkeleton: { height: 12, width: '60%', borderRadius: 4, }, emptyState: { width: 280, padding: 24, alignItems: 'center', justifyContent: 'center', }, emptyText: { marginTop: 8, marginBottom: 16, color: '#6b7280', }, errorText: { marginTop: 8, marginBottom: 16, color: '#ef4444', }, emptyButton: { marginTop: 8, } });