feat: update loading skeleton and playlist handling for main playlists
This commit is contained in:
@@ -2,12 +2,7 @@ import { AppLayout } from '@/components/AppLayout'
|
||||
import { DashboardHeader } from '@/components/dashboard/DashboardHeader'
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
|
||||
interface LoadingSkeletonProps {
|
||||
title: string
|
||||
description: string
|
||||
}
|
||||
|
||||
export function LoadingSkeleton({ title, description }: LoadingSkeletonProps) {
|
||||
export function LoadingSkeleton() {
|
||||
return (
|
||||
<AppLayout
|
||||
breadcrumb={{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { LucideIcon } from 'lucide-react'
|
||||
import { ReactNode } from 'react'
|
||||
import type { LucideIcon } from 'lucide-react'
|
||||
import type { ReactNode } from 'react'
|
||||
|
||||
interface StatisticCardProps {
|
||||
title: string
|
||||
|
||||
@@ -13,7 +13,8 @@ export function CreditsNav({ user }: CreditsNavProps) {
|
||||
const [credits, setCredits] = useState(user.credits)
|
||||
|
||||
useEffect(() => {
|
||||
const handleCreditsChanged = (data: { credits_after: number }) => {
|
||||
const handleCreditsChanged = (...args: unknown[]) => {
|
||||
const data = args[0] as { credits_after: number }
|
||||
setCredits(data.credits_after)
|
||||
}
|
||||
|
||||
|
||||
@@ -51,7 +51,8 @@ export function CompactPlayer({ className }: CompactPlayerProps) {
|
||||
|
||||
// Listen for player state updates
|
||||
useEffect(() => {
|
||||
const handlePlayerState = (newState: PlayerState) => {
|
||||
const handlePlayerState = (...args: unknown[]) => {
|
||||
const newState = args[0] as PlayerState
|
||||
setState(newState)
|
||||
}
|
||||
|
||||
|
||||
@@ -99,7 +99,8 @@ export function Player({ className, onPlayerModeChange }: PlayerProps) {
|
||||
|
||||
// Listen for player state updates
|
||||
useEffect(() => {
|
||||
const handlePlayerState = (newState: PlayerState) => {
|
||||
const handlePlayerState = (...args: unknown[]) => {
|
||||
const newState = args[0] as PlayerState
|
||||
setState(newState)
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Badge } from '@/components/ui/badge'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { TableCell, TableRow } from '@/components/ui/table'
|
||||
import type { Playlist } from '@/lib/api/services/playlists'
|
||||
import { formatDate, formatDateDistanceToNow } from '@/utils/format-date'
|
||||
import { formatDateDistanceToNow } from '@/utils/format-date'
|
||||
import { formatDuration } from '@/utils/format-duration'
|
||||
import { Calendar, Clock, Edit, Music, Play, User } from 'lucide-react'
|
||||
|
||||
|
||||
@@ -117,7 +117,13 @@ export function PlaylistDetailsCard({
|
||||
|
||||
{/* Edit/Save/Cancel buttons */}
|
||||
<div className="pt-4 border-t">
|
||||
{isEditMode ? (
|
||||
{playlist.is_main ? (
|
||||
<div className="text-center">
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Main playlist details cannot be edited
|
||||
</p>
|
||||
</div>
|
||||
) : isEditMode ? (
|
||||
<div className="flex justify-end gap-2">
|
||||
<Button variant="outline" onClick={onCancelEdit}>
|
||||
<X className="h-4 w-4 mr-2" />
|
||||
|
||||
@@ -7,13 +7,15 @@ import { Music, X } from 'lucide-react'
|
||||
interface SimpleSortableRowProps {
|
||||
sound: PlaylistSound
|
||||
index: number
|
||||
onRemoveSound: (soundId: number) => void
|
||||
onRemoveSound?: (soundId: number) => void
|
||||
isMainPlaylist?: boolean
|
||||
}
|
||||
|
||||
export function SimpleSortableRow({
|
||||
sound,
|
||||
index,
|
||||
onRemoveSound,
|
||||
isMainPlaylist = false,
|
||||
}: SimpleSortableRowProps) {
|
||||
const {
|
||||
attributes,
|
||||
@@ -48,18 +50,20 @@ export function SimpleSortableRow({
|
||||
<div className="font-medium truncate">{sound.name}</div>
|
||||
</div>
|
||||
|
||||
<Button
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
onClick={e => {
|
||||
e.stopPropagation()
|
||||
onRemoveSound(sound.id)
|
||||
}}
|
||||
className="h-4 w-4 p-0 text-destructive hover:text-destructive flex-shrink-0"
|
||||
title="Remove from playlist"
|
||||
>
|
||||
<X className="h-3 w-3" />
|
||||
</Button>
|
||||
{onRemoveSound && !isMainPlaylist && (
|
||||
<Button
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
onClick={e => {
|
||||
e.stopPropagation()
|
||||
onRemoveSound(sound.id)
|
||||
}}
|
||||
className="h-4 w-4 p-0 text-destructive hover:text-destructive flex-shrink-0"
|
||||
title="Remove from playlist"
|
||||
>
|
||||
<X className="h-3 w-3" />
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -12,8 +12,9 @@ interface SortableTableRowProps {
|
||||
index: number
|
||||
onMoveSoundUp: (index: number) => void
|
||||
onMoveSoundDown: (index: number) => void
|
||||
onRemoveSound: (soundId: number) => void
|
||||
onRemoveSound?: (soundId: number) => void
|
||||
totalSounds: number
|
||||
isMainPlaylist?: boolean
|
||||
}
|
||||
|
||||
export function SortableTableRow({
|
||||
@@ -23,6 +24,7 @@ export function SortableTableRow({
|
||||
onMoveSoundDown,
|
||||
onRemoveSound,
|
||||
totalSounds,
|
||||
isMainPlaylist = false,
|
||||
}: SortableTableRowProps) {
|
||||
const {
|
||||
attributes,
|
||||
@@ -97,15 +99,17 @@ export function SortableTableRow({
|
||||
>
|
||||
<ChevronDown className="h-4 w-4" />
|
||||
</Button>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
onClick={() => onRemoveSound(sound.id)}
|
||||
className="h-8 w-8 p-0 text-destructive hover:text-destructive"
|
||||
title="Remove from playlist"
|
||||
>
|
||||
<Trash2 className="h-4 w-4" />
|
||||
</Button>
|
||||
{onRemoveSound && !isMainPlaylist && (
|
||||
<Button
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
onClick={() => onRemoveSound(sound.id)}
|
||||
className="h-8 w-8 p-0 text-destructive hover:text-destructive"
|
||||
title="Remove from playlist"
|
||||
>
|
||||
<Trash2 className="h-4 w-4" />
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
|
||||
Reference in New Issue
Block a user