Skip to content

Commit b98a52a

Browse files
committed
2 parents 80846f9 + fb44911 commit b98a52a

File tree

8 files changed

+792
-810
lines changed

8 files changed

+792
-810
lines changed

frontend/components/ImageWithFallback/ImageWithFallback.tsx

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ import {Image} from '@chakra-ui/react';
55
import {ImageProps} from '@chakra-ui/image';
66

77
export const ImageWithFallback = ({
8-
fallbackSrc,
9-
...props
10-
}: ImageProps & { fallbackSrc: string }) => {
8+
fallbackSrc,
9+
...props
10+
}: ImageProps & {fallbackSrc: string}) => {
1111
const [error, setError] = useState(false);
1212

1313
useEffect(() => {
@@ -16,17 +16,15 @@ export const ImageWithFallback = ({
1616

1717
return (
1818
<Image
19-
{...{
20-
onError: () => setError(true),
21-
htmlHeight: 250,
22-
htmlWidth: 250,
23-
loading: 'lazy',
24-
...props,
25-
src: cdnImageLoader({
26-
src: error ? fallbackSrc : props.src,
27-
width: 256,
28-
}),
29-
}}
19+
{...props}
20+
onError={() => setError(true)}
21+
htmlHeight={250}
22+
htmlWidth={250}
23+
loading={'lazy'}
24+
src={cdnImageLoader({
25+
src: error ? fallbackSrc : props.src,
26+
width: 256,
27+
})}
3028
draggable={false}
3129
/>
3230
);

frontend/components/StationInformation/StationInformation.tsx

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,9 @@ export default function StationInformation(props: any) {
3232
Math.round(
3333
(average(station?.reviews?.map((i: any) => i.stars) || []) || 0) * 10,
3434
) / 10;
35-
const NumberOfListeners = station?.now_playing?.listeners || null;
35+
const numberOfListeners = station?.now_playing?.listeners
36+
? station?.now_playing?.listeners + 1
37+
: null;
3638
const latestPost = station.posts[0];
3739
const toast = useToast();
3840

@@ -106,10 +108,12 @@ export default function StationInformation(props: any) {
106108

107109
<Flex>
108110
<ReactStars
111+
key={`rating-${station.id}`}
109112
count={5}
110113
onChange={(rating: any) => onRatingChange(rating)}
111114
size={20}
112115
value={StationRating}
116+
isHalf={true}
113117
activeColor="#fe7f38"
114118
/>
115119
{/* @ts-ignore */}
@@ -137,9 +141,9 @@ export default function StationInformation(props: any) {
137141
)}
138142
</Flex>
139143

140-
{NumberOfListeners && (
144+
{numberOfListeners && (
141145
<Text fontSize={{base: 'sm', lg: 'md'}}>
142-
{NumberOfListeners} persoane ascultă împreună cu tine acest radio
146+
{numberOfListeners} persoane ascultă împreună cu tine acest radio
143147
</Text>
144148
)}
145149

frontend/components/StationList/StationList.tsx

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ import {
1414
useMediaQuery,
1515
} from '@chakra-ui/react';
1616
import {ImageWithFallback} from '../ImageWithFallback/ImageWithFallback';
17+
import {ViewIcon} from '@chakra-ui/icons';
18+
import {useRouter} from 'next/router';
1719

1820
const StationMetadata = dynamic(
1921
() => import('@/components/StationMetadata/StationMetadata'),
@@ -22,11 +24,14 @@ const StationMetadata = dynamic(
2224

2325
const StationItem = ({
2426
station,
25-
priority,
27+
is_listening,
2628
}: {
2729
station: Station;
28-
priority?: boolean;
30+
is_listening?: boolean;
2931
}) => {
32+
const numberOfListeners = station?.now_playing?.listeners
33+
? station?.now_playing?.listeners + (is_listening ? 1 : 0)
34+
: null;
3035
const [isTabletOrMobile] = useMediaQuery('(max-width: 1024px)');
3136
return (
3237
<Box position={'relative'} role="group">
@@ -37,6 +42,24 @@ const StationItem = ({
3742
overflow={'hidden'}
3843
height={250}
3944
width={250}>
45+
{numberOfListeners && (
46+
<Text
47+
position={'absolute'}
48+
display={'flex'}
49+
justifyContent={'center'}
50+
alignItems={'center'}
51+
background={'rgba(0,0,0,0.68)'}
52+
color={'white'}
53+
paddingX={1}
54+
borderRadius={10}
55+
right={4}
56+
top={3}
57+
fontSize={14}
58+
gap={1}>
59+
<ViewIcon />
60+
{numberOfListeners}
61+
</Text>
62+
)}
4063
<ImageWithFallback
4164
src={
4265
station.now_playing?.song?.thumbnail_url ||
@@ -90,12 +113,18 @@ const StationItem = ({
90113
};
91114

92115
export default function StationList({
93-
station_group,
94-
stations,
95-
}: {
116+
station_group,
117+
stations,
118+
}: {
96119
station_group: StationGroup;
97120
stations: Station[];
98121
}) {
122+
const route = useRouter();
123+
// @ts-ignore
124+
const selectedStation: Station = stations.find(
125+
s => s.slug === route.asPath.split('/')[2],
126+
);
127+
99128
return (
100129
<Center>
101130
<Grid
@@ -109,7 +138,7 @@ export default function StationList({
109138
}}
110139
gap={9}>
111140
{Object.values(stations).length > 0 ? (
112-
Object.values(stations).map((station: Station, index): any => (
141+
Object.values(stations).map((station: Station): any => (
113142
<GridItem as="button" key={station.id}>
114143
<Link
115144
prefetch={false}
@@ -118,7 +147,10 @@ export default function StationList({
118147
)}/${encodeURIComponent(station.slug)}`}
119148
scroll={false}
120149
passHref>
121-
<StationItem station={station} />
150+
<StationItem
151+
station={station}
152+
is_listening={station === selectedStation || false}
153+
/>
122154
</Link>
123155
</GridItem>
124156
))

frontend/components/StationPlayer.tsx

Lines changed: 41 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
SliderTrack,
1010
Spacer,
1111
Text,
12+
Tooltip,
1213
useToast,
1314
} from '@chakra-ui/react';
1415
import {useLocalStorageState} from '@/utils/state';
@@ -17,6 +18,7 @@ import {CONSTANTS} from '../lib/constants';
1718
import {Loading} from '@/public/images/loading';
1819
import {ImageWithFallback} from '@/components/ImageWithFallback/ImageWithFallback';
1920
import Hls from 'hls.js';
21+
import useSpaceBarPress from '@/hooks/useSpaceBarPress';
2022

2123
enum STREAM_TYPE {
2224
HLS = 'HLS',
@@ -226,13 +228,33 @@ export default function StationPlayer({stations}: any) {
226228
return () => clearInterval(timer);
227229
}, [playbackState]);
228230

231+
useSpaceBarPress(() => {
232+
if (
233+
playbackState === PLAYBACK_STATE.PLAYING ||
234+
playbackState === PLAYBACK_STATE.STARTED
235+
) {
236+
setPlaybackState(PLAYBACK_STATE.STOPPED);
237+
return;
238+
}
239+
240+
if (playbackState === PLAYBACK_STATE.STOPPED) {
241+
setPlaybackState(PLAYBACK_STATE.STARTED);
242+
}
243+
});
244+
229245
const nextRandomStation = () => {
230246
const upStations = stations.filter(
231247
(station: any) => station.uptime.is_up === true,
232248
);
233-
const randomStation =
234-
upStations[Math.floor(Math.random() * stations.length)];
235-
router.push(`/radio/${randomStation.slug}`);
249+
250+
// Find the index of the current ID
251+
const currentIndex = upStations.findIndex((s: any) => s.id === station.id);
252+
253+
// Increment the index to move to the next ID
254+
const nextIndex = currentIndex + 1;
255+
const nextStation = upStations[nextIndex % upStations.length];
256+
257+
router.push(`/radio/${nextStation.slug}`);
236258
};
237259

238260
const renderPlayButtonSvg = () => {
@@ -296,7 +318,10 @@ export default function StationPlayer({stations}: any) {
296318
mt={{base: 0}}
297319
ml={{base: 4}}
298320
flexDirection={{base: 'row'}}>
299-
<Box>
321+
<Box
322+
display={'flex'}
323+
flexDirection={'column'}
324+
justifyContent={'center'}>
300325
<Text
301326
as="h2"
302327
fontSize={{base: 'sm'}}
@@ -358,16 +383,18 @@ export default function StationPlayer({stations}: any) {
358383
setPlaybackState(PLAYBACK_STATE.STARTED);
359384
}
360385
}}>
361-
<Box fill={{base: 'white'}}>
362-
<svg
363-
width="50px"
364-
height="50px"
365-
focusable="false"
366-
aria-hidden="true"
367-
viewBox="0 0 24 24">
368-
{renderPlayButtonSvg()}
369-
</svg>
370-
</Box>
386+
<Tooltip label="Start/Stop [Space]">
387+
<Box fill={{base: 'white'}}>
388+
<svg
389+
width="50px"
390+
height="50px"
391+
focusable="false"
392+
aria-hidden="true"
393+
viewBox="0 0 24 24">
394+
{renderPlayButtonSvg()}
395+
</svg>
396+
</Box>
397+
</Tooltip>
371398
</button>
372399
<audio
373400
preload="true"

frontend/hooks/useSpaceBarPress.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import {useEffect} from 'react';
2+
3+
const useSpaceBarPress = (callback: () => void) => {
4+
useEffect(() => {
5+
const handleKeyDown = (e: any) => {
6+
const isInputOrTextArea = ['input', 'textarea', 'select'].includes(
7+
e.target.tagName.toLowerCase(),
8+
);
9+
10+
if (
11+
e.keyCode === 32 &&
12+
e.target.getAttribute('contentEditable') !== 'true' &&
13+
!isInputOrTextArea
14+
) {
15+
e.preventDefault();
16+
}
17+
};
18+
19+
const handleKeyPress = (e: any) => {
20+
const isInputOrTextArea = ['input', 'textarea', 'select'].includes(
21+
e.target.tagName.toLowerCase(),
22+
);
23+
24+
if (
25+
(e.key === ' ' || e.code === 'Space' || e.keyCode === 32) &&
26+
!isInputOrTextArea
27+
) {
28+
callback();
29+
}
30+
};
31+
32+
document.body.addEventListener('keyup', handleKeyPress);
33+
document.body.addEventListener('keydown', handleKeyDown);
34+
35+
return () => {
36+
document.body.removeEventListener('keyup', handleKeyPress);
37+
document.body.removeEventListener('keydown', handleKeyDown);
38+
};
39+
}, [callback]);
40+
};
41+
42+
export default useSpaceBarPress;

frontend/package.json

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -12,39 +12,39 @@
1212
"build-and-start": "yarn run build && yarn run start"
1313
},
1414
"dependencies": {
15-
"@chakra-ui/icons": "^2.0.15",
16-
"@chakra-ui/react": "^2.4.6",
15+
"@chakra-ui/icons": "^2.0.19",
16+
"@chakra-ui/react": "^2.7.1",
1717
"@emotion/react": "^11",
1818
"@emotion/styled": "^11",
19-
"@types/uuid": "^9.0.0",
20-
"axios": "^1.2.2",
19+
"@types/uuid": "^9.0.2",
20+
"axios": "^1.4.0",
2121
"bluebird": "^3.7.2",
2222
"cachios": "^4.0.0",
23-
"concurrently": "^7.6.0",
23+
"concurrently": "^8.2.0",
2424
"cookie-session": "^2.0.0",
2525
"cross-env": "^7.0.3",
26-
"framer-motion": "^8",
27-
"hls.js": "1.2.9",
28-
"next": "13.1.1",
26+
"framer-motion": "^10",
27+
"hls.js": "1.4.6",
28+
"next": "13.4.7",
2929
"next-runtime-dotenv": "^1.5.1",
3030
"react": "18.2.0",
3131
"react-dom": "18.2.0",
3232
"react-rating-stars-component": "^2.2.0",
3333
"react-share": "^4.4.1",
34-
"sass": "^1.57.1",
35-
"sharp": "^0.31.3",
36-
"swr": "^2.0.0",
37-
"tslog": "^4.7.1",
34+
"sass": "^1.63.6",
35+
"sharp": "^0.32.1",
36+
"swr": "^2.2.0",
37+
"tslog": "^4.8.2",
3838
"uuid": "^9.0.0"
3939
},
4040
"devDependencies": {
41-
"@next/bundle-analyzer": "^13.1.1",
41+
"@next/bundle-analyzer": "^13.4.7",
4242
"@styled-jsx/plugin-sass": "^4.0.2",
4343
"@types/bluebird": "^3.5.38",
44-
"@types/node": "^18.11.18",
45-
"@types/react": "18.0.26",
46-
"prettier": "2.8.2",
44+
"@types/node": "^20.3.1",
45+
"@types/react": "18.2.14",
46+
"prettier": "2.8.8",
4747
"ts-node": "^10.9.1",
48-
"typescript": "4.9.4"
48+
"typescript": "5.1.3"
4949
}
5050
}

0 commit comments

Comments
 (0)