- Add auth middleware (API key) to protect API routes (#5, #7) - Add WebSocket handlers and cleanup on disconnect (#3, #8) - Add web Dockerfile (#1) - Fix memory upload with streaming chunks (#10) - Move lofi seed to startup, remove per-request seeding (#9) - Document ffmpeg dependency in README and .env.example (#6) - Fill in mobile app with API-connected UI (#4) - Set GENIUS_API_KEY from env var with documentation (#2)
70 lines
2.6 KiB
TypeScript
70 lines
2.6 KiB
TypeScript
import { View, Text, ScrollView, TouchableOpacity, FlatList, ActivityIndicator } from 'react-native'
|
||
import { useRouter } from 'expo-router'
|
||
import { BottomNavBar } from '../src/components/BottomNavBar'
|
||
import { usePlayerStore } from '../src/store/playerStore'
|
||
import { useState, useEffect } from 'react'
|
||
|
||
export default function ReleasesScreen() {
|
||
const router = useRouter()
|
||
const [releases, setReleases] = useState([])
|
||
const [loading, setLoading] = useState(true)
|
||
|
||
useEffect(() => {
|
||
fetchReleases()
|
||
}, [])
|
||
|
||
const fetchReleases = async () => {
|
||
try {
|
||
const res = await fetch('/api/releases?limit=20')
|
||
const data = await res.json()
|
||
setReleases(data.items || [])
|
||
} catch {
|
||
setReleases([])
|
||
} finally {
|
||
setLoading(false)
|
||
}
|
||
}
|
||
|
||
return (
|
||
<View className="flex-1 bg-music-black">
|
||
<ScrollView className="flex-1 px-4 pt-4">
|
||
<View className="flex-row items-center justify-between mb-6">
|
||
<View className="w-10" />
|
||
<Text className="text-xl font-semibold text-music-text">New Releases</Text>
|
||
<View className="w-10" />
|
||
</View>
|
||
|
||
{loading ? (
|
||
<View className="items-center py-12">
|
||
<ActivityIndicator size="large" color="#e94560" />
|
||
<Text className="text-music-muted mt-2">Loading releases...</Text>
|
||
</View>
|
||
) : releases.length > 0 ? (
|
||
releases.map((release: any, i: number) => (
|
||
<View key={release.id || i} className="flex-row gap-4 p-4 rounded-2xl bg-music-card mb-4">
|
||
<View className="items-center">
|
||
<View className="w-16 h-16 rounded-lg bg-music-dark mb-2" />
|
||
<Text className="text-xs text-music-muted">{release.artist || 'Artist'}</Text>
|
||
<TouchableOpacity className="flex-row items-center px-3 py-1 rounded-full bg-music-dark mt-2">
|
||
<Text className="text-xs text-music-text">➕ Add</Text>
|
||
</TouchableOpacity>
|
||
</View>
|
||
<View className="flex-wrap flex-row gap-2 flex-1">
|
||
{[...Array(Math.min(6, release.tracks || 3))].map((_, j) => (
|
||
<TouchableOpacity key={j} className="w-[15%] aspect-square rounded-lg bg-music-dark" />
|
||
))}
|
||
</View>
|
||
</View>
|
||
))
|
||
) : (
|
||
<View className="items-center py-12">
|
||
<Text className="text-4xl mb-2">🎵</Text>
|
||
<Text className="text-music-muted">No new releases found</Text>
|
||
</View>
|
||
)}
|
||
</ScrollView>
|
||
<BottomNavBar />
|
||
</View>
|
||
)
|
||
}
|