Refactor and enhance UI components across multiple pages
Some checks failed
Frontend CI / lint (push) Failing after 19s
Frontend CI / build (push) Has been skipped

- Improved import organization and formatting in PlaylistsPage, RegisterPage, SoundsPage, SettingsPage, and UsersPage for better readability.
- Added error handling and user feedback with toast notifications in SoundsPage and SettingsPage.
- Enhanced user experience by implementing debounced search functionality in PlaylistsPage and SoundsPage.
- Updated the layout and structure of forms in SettingsPage and UsersPage for better usability.
- Improved accessibility and semantics by ensuring proper labeling and descriptions in forms.
- Fixed minor bugs related to state management and API calls in various components.
This commit is contained in:
JSC
2025-08-14 23:51:47 +02:00
parent 8358aa16aa
commit 4e50e7e79d
53 changed files with 2477 additions and 1520 deletions

View File

@@ -1,22 +1,26 @@
import { useState, useEffect, useCallback } from 'react'
import { Button } from '@/components/ui/button'
import { Progress } from '@/components/ui/progress'
import {
Play,
Pause,
SkipBack,
SkipForward,
Volume2,
VolumeX,
Music,
Maximize2
} from 'lucide-react'
import { playerService, type PlayerState, type MessageResponse } from '@/lib/api/services/player'
import { filesService } from '@/lib/api/services/files'
import { playerEvents, PLAYER_EVENTS } from '@/lib/events'
import { toast } from 'sonner'
import {
type MessageResponse,
type PlayerState,
playerService,
} from '@/lib/api/services/player'
import { PLAYER_EVENTS, playerEvents } from '@/lib/events'
import { cn } from '@/lib/utils'
import { formatDuration } from '@/utils/format-duration'
import {
Maximize2,
Music,
Pause,
Play,
SkipBack,
SkipForward,
Volume2,
VolumeX,
} from 'lucide-react'
import { useCallback, useEffect, useState } from 'react'
import { toast } from 'sonner'
interface CompactPlayerProps {
className?: string
@@ -28,7 +32,7 @@ export function CompactPlayer({ className }: CompactPlayerProps) {
mode: 'continuous',
volume: 80,
previous_volume: 80,
position: 0
position: 0,
})
const [isLoading, setIsLoading] = useState(false)
@@ -58,18 +62,23 @@ export function CompactPlayer({ className }: CompactPlayerProps) {
}
}, [])
const executeAction = useCallback(async (action: () => Promise<void | MessageResponse>, actionName: string) => {
setIsLoading(true)
try {
await action()
} catch (error) {
console.error(`Failed to ${actionName}:`, error)
toast.error(`Failed to ${actionName}`)
} finally {
setIsLoading(false)
}
}, [])
const executeAction = useCallback(
async (
action: () => Promise<void | MessageResponse>,
actionName: string,
) => {
setIsLoading(true)
try {
await action()
} catch (error) {
console.error(`Failed to ${actionName}:`, error)
toast.error(`Failed to ${actionName}`)
} finally {
setIsLoading(false)
}
},
[],
)
const handlePlayPause = useCallback(() => {
if (state.status === 'playing') {
@@ -103,7 +112,7 @@ export function CompactPlayer({ className }: CompactPlayerProps) {
// }
return (
<div className={cn("w-full", className)}>
<div className={cn('w-full', className)}>
{/* Collapsed state - only play/pause button */}
<div className="group-data-[collapsible=icon]:flex group-data-[collapsible=icon]:justify-center hidden">
<Button
@@ -128,11 +137,11 @@ export function CompactPlayer({ className }: CompactPlayerProps) {
<div className="flex items-center gap-2 mb-3 px-1">
<div className="flex-shrink-0 w-8 h-8 bg-muted rounded flex items-center justify-center overflow-hidden">
{state.current_sound?.thumbnail ? (
<img
src={filesService.getThumbnailUrl(state.current_sound.id)}
<img
src={filesService.getThumbnailUrl(state.current_sound.id)}
alt={state.current_sound.name}
className="w-full h-full object-cover"
onError={(e) => {
onError={e => {
// Hide image and show music icon if thumbnail fails to load
const target = e.target as HTMLImageElement
target.style.display = 'none'
@@ -141,11 +150,11 @@ export function CompactPlayer({ className }: CompactPlayerProps) {
}}
/>
) : null}
<Music
<Music
className={cn(
"h-4 w-4 text-muted-foreground",
state.current_sound?.thumbnail ? "hidden" : "block"
)}
'h-4 w-4 text-muted-foreground',
state.current_sound?.thumbnail ? 'hidden' : 'block',
)}
/>
</div>
<div className="flex-1 min-w-0">
@@ -160,7 +169,9 @@ export function CompactPlayer({ className }: CompactPlayerProps) {
size="sm"
variant="ghost"
onClick={() => {
const expandFn = (window as unknown as { __expandPlayerFromSidebar?: () => void }).__expandPlayerFromSidebar
const expandFn = (
window as unknown as { __expandPlayerFromSidebar?: () => void }
).__expandPlayerFromSidebar
if (expandFn) expandFn()
}}
className="h-6 w-6 p-0 flex-shrink-0"
@@ -194,7 +205,7 @@ export function CompactPlayer({ className }: CompactPlayerProps) {
>
<SkipBack className="h-3 w-3" />
</Button>
<Button
size="sm"
variant="ghost"
@@ -238,4 +249,4 @@ export function CompactPlayer({ className }: CompactPlayerProps) {
</div>
</div>
)
}
}