210 lines
5.8 KiB
TypeScript
210 lines
5.8 KiB
TypeScript
import { ActionIcon, Box, Group, Loader, Text, Tooltip } from '@mantine/core';
|
|
import { useDisclosure } from '@mantine/hooks';
|
|
import {
|
|
PlayIcon,
|
|
PauseIcon,
|
|
SkipBackIcon,
|
|
SkipForwardIcon,
|
|
GearIcon,
|
|
SpotifyLogoIcon,
|
|
FloppyDiskIcon,
|
|
ClockCounterClockwiseIcon,
|
|
} from '@phosphor-icons/react';
|
|
import { useSpotify } from '@/lib/spotify/hooks';
|
|
import { useAuth } from '@/contexts/auth-context';
|
|
import SpotifySheet from './spotify-sheet';
|
|
|
|
const SpotifyControlsBar = () => {
|
|
const { roles } = useAuth();
|
|
const isAdmin = roles?.includes('Admin') || false;
|
|
const [sheetOpened, { open: openSheet, close: closeSheet }] = useDisclosure(false);
|
|
|
|
const {
|
|
isAuthenticated,
|
|
playbackState,
|
|
currentTrack,
|
|
isLoading,
|
|
error,
|
|
play,
|
|
pause,
|
|
skipNext,
|
|
skipPrevious,
|
|
activeDevice,
|
|
capturedState,
|
|
isCaptureLoading,
|
|
isResumeLoading,
|
|
capturePlaybackState,
|
|
resumePlaybackState,
|
|
} = useSpotify();
|
|
|
|
if (!isAdmin) return null;
|
|
|
|
if (!isAuthenticated) {
|
|
return (
|
|
<Box py="md" mb="md">
|
|
<Group justify="center" gap="sm">
|
|
<SpotifyLogoIcon size={24} color="var(--mantine-color-green-6)" />
|
|
<Text size="sm" c="dimmed">
|
|
Connect Spotify
|
|
</Text>
|
|
<ActionIcon
|
|
variant="light"
|
|
color="green"
|
|
size="lg"
|
|
onClick={openSheet}
|
|
loading={isLoading}
|
|
>
|
|
<GearIcon size={18} />
|
|
</ActionIcon>
|
|
</Group>
|
|
<SpotifySheet opened={sheetOpened} onClose={closeSheet} />
|
|
</Box>
|
|
);
|
|
}
|
|
|
|
const isPlaying = playbackState?.is_playing || false;
|
|
const hasActiveDevice = !!activeDevice;
|
|
|
|
return (
|
|
<Box py="md" mb="md">
|
|
<Group justify="center" gap="md" align="center">
|
|
{currentTrack && (
|
|
<Group gap="sm" style={{ maxWidth: 400 }}>
|
|
{currentTrack.album.images[2] && (
|
|
<img
|
|
src={currentTrack.album.images[2].url}
|
|
alt={currentTrack.album.name}
|
|
style={{
|
|
width: 48,
|
|
height: 48,
|
|
borderRadius: 4,
|
|
flexShrink: 0
|
|
}}
|
|
/>
|
|
)}
|
|
|
|
<Box style={{ minWidth: 0, flex: 1 }}>
|
|
<Text size="sm" fw={600} truncate>
|
|
{currentTrack.name}
|
|
</Text>
|
|
<Text size="xs" c="dimmed" truncate>
|
|
{currentTrack.artists.map(a => a.name).join(', ')}
|
|
</Text>
|
|
<Text size="xs" c="dimmed" truncate>
|
|
{currentTrack.album.name}
|
|
</Text>
|
|
</Box>
|
|
</Group>
|
|
)}
|
|
|
|
<Group gap="xs">
|
|
<Tooltip label="Previous track">
|
|
<ActionIcon
|
|
variant="light"
|
|
size="lg"
|
|
onClick={skipPrevious}
|
|
disabled={!hasActiveDevice || isLoading}
|
|
loading={isLoading}
|
|
>
|
|
<SkipBackIcon size={18} />
|
|
</ActionIcon>
|
|
</Tooltip>
|
|
|
|
<Tooltip label={isPlaying ? 'Pause' : 'Play'}>
|
|
<ActionIcon
|
|
variant="filled"
|
|
color="green"
|
|
size="xl"
|
|
onClick={() => isPlaying ? pause() : play()}
|
|
disabled={!hasActiveDevice || isLoading}
|
|
loading={isLoading}
|
|
>
|
|
{isPlaying ? <PauseIcon size={24} /> : <PlayIcon size={24} />}
|
|
</ActionIcon>
|
|
</Tooltip>
|
|
|
|
<Tooltip label="Next track">
|
|
<ActionIcon
|
|
variant="light"
|
|
size="lg"
|
|
onClick={skipNext}
|
|
disabled={!hasActiveDevice || isLoading}
|
|
loading={isLoading}
|
|
>
|
|
<SkipForwardIcon size={18} />
|
|
</ActionIcon>
|
|
</Tooltip>
|
|
</Group>
|
|
|
|
<Group gap="xs">
|
|
<Tooltip label={'Capture current state'}>
|
|
<ActionIcon
|
|
variant="light"
|
|
color={capturedState ? 'blue' : 'gray'}
|
|
size="lg"
|
|
onClick={capturePlaybackState}
|
|
disabled={!hasActiveDevice || isLoading || isCaptureLoading}
|
|
loading={isCaptureLoading}
|
|
>
|
|
<FloppyDiskIcon size={18} />
|
|
</ActionIcon>
|
|
</Tooltip>
|
|
|
|
<Tooltip label={capturedState ? 'Restore captured state' : 'No state captured'}>
|
|
<ActionIcon
|
|
variant="light"
|
|
color={capturedState ? 'blue' : 'gray'}
|
|
size="lg"
|
|
onClick={resumePlaybackState}
|
|
disabled={!capturedState || !hasActiveDevice || isLoading || isResumeLoading}
|
|
loading={isResumeLoading}
|
|
>
|
|
<ClockCounterClockwiseIcon size={18} />
|
|
</ActionIcon>
|
|
</Tooltip>
|
|
</Group>
|
|
|
|
<Group gap="xs">
|
|
{activeDevice && (
|
|
<Box>
|
|
<Text size="xs" c="dimmed">
|
|
Playing on {activeDevice.name}
|
|
</Text>
|
|
</Box>
|
|
)}
|
|
|
|
<Tooltip label="Spotify settings">
|
|
<ActionIcon
|
|
variant="light"
|
|
color="green"
|
|
size="lg"
|
|
onClick={openSheet}
|
|
>
|
|
<GearIcon size={18} />
|
|
</ActionIcon>
|
|
</Tooltip>
|
|
</Group>
|
|
</Group>
|
|
|
|
{error && (
|
|
<Group justify="center" mt="xs">
|
|
<Text size="xs" c="red">
|
|
{error}
|
|
</Text>
|
|
</Group>
|
|
)}
|
|
|
|
{isAuthenticated && !hasActiveDevice && !isLoading && (
|
|
<Group justify="center" mt="xs">
|
|
<Text size="xs" c="orange">
|
|
No active device. Please select a device in settings.
|
|
</Text>
|
|
</Group>
|
|
)}
|
|
|
|
<SpotifySheet opened={sheetOpened} onClose={closeSheet} />
|
|
</Box>
|
|
);
|
|
};
|
|
|
|
export default SpotifyControlsBar; |