feat: add loader for favorites

This commit is contained in:
MAZE 2024-01-09 16:09:07 +03:30
parent a33ae450cf
commit f682a910da
4 changed files with 26 additions and 7 deletions

View file

@ -5,7 +5,7 @@ import { Range } from './range';
import { Favorite } from './favorite'; import { Favorite } from './favorite';
import { useSound } from '@/hooks/use-sound'; import { useSound } from '@/hooks/use-sound';
import { useSoundStore } from '@/store'; import { useSoundStore, useLoadingStore } from '@/store';
import { cn } from '@/helpers/styles'; import { cn } from '@/helpers/styles';
import styles from './sound.module.css'; import styles from './sound.module.css';
@ -37,6 +37,8 @@ export function Sound({
const volume = useSoundStore(state => state.sounds[id].volume); const volume = useSoundStore(state => state.sounds[id].volume);
const isSelected = useSoundStore(state => state.sounds[id].isSelected); const isSelected = useSoundStore(state => state.sounds[id].isSelected);
const isLoading = useLoadingStore(state => state.loaders[src]);
const sound = useSound(src, { loop: true, volume }); const sound = useSound(src, { loop: true, volume });
useEffect(() => { useEffect(() => {
@ -80,7 +82,7 @@ export function Sound({
> >
<Favorite id={id} /> <Favorite id={id} />
<div className={styles.icon}> <div className={styles.icon}>
{sound.isLoading ? ( {isLoading ? (
<span className={styles.spinner}> <span className={styles.spinner}>
<ImSpinner9 /> <ImSpinner9 />
</span> </span>

View file

@ -1,6 +1,7 @@
import { useMemo, useEffect, useCallback, useState } from 'react'; import { useMemo, useEffect, useCallback, useState } from 'react';
import { Howl } from 'howler'; import { Howl } from 'howler';
import { useLoadingStore } from '@/store';
import { useSSR } from './use-ssr'; import { useSSR } from './use-ssr';
export function useSound( export function useSound(
@ -8,7 +9,9 @@ export function useSound(
options: { loop?: boolean; volume?: number } = {}, options: { loop?: boolean; volume?: number } = {},
) { ) {
const [hasLoaded, setHasLoaded] = useState(false); const [hasLoaded, setHasLoaded] = useState(false);
const [isLoading, setIsLoading] = useState(false); const isLoading = useLoadingStore(state => state.loaders[src]);
const setIsLoading = useLoadingStore(state => state.set);
const { isBrowser } = useSSR(); const { isBrowser } = useSSR();
const sound = useMemo<Howl | null>(() => { const sound = useMemo<Howl | null>(() => {
let sound: Howl | null = null; let sound: Howl | null = null;
@ -16,7 +19,7 @@ export function useSound(
if (isBrowser) { if (isBrowser) {
sound = new Howl({ sound = new Howl({
onload: () => { onload: () => {
setIsLoading(false); setIsLoading(src, false);
setHasLoaded(true); setHasLoaded(true);
}, },
preload: false, preload: false,
@ -25,7 +28,7 @@ export function useSound(
} }
return sound; return sound;
}, [src, isBrowser]); }, [src, isBrowser, setIsLoading]);
useEffect(() => { useEffect(() => {
if (sound) { if (sound) {
@ -41,7 +44,7 @@ export function useSound(
const play = useCallback(() => { const play = useCallback(() => {
if (sound) { if (sound) {
if (!hasLoaded && !isLoading) { if (!hasLoaded && !isLoading) {
setIsLoading(true); setIsLoading(src, true);
sound.load(); sound.load();
} }
@ -49,7 +52,7 @@ export function useSound(
sound.play(); sound.play();
} }
} }
}, [sound, hasLoaded, isLoading]); }, [src, setIsLoading, sound, hasLoaded, isLoading]);
const stop = useCallback(() => { const stop = useCallback(() => {
if (sound) sound.stop(); if (sound) sound.stop();

View file

@ -1 +1,2 @@
export { useSoundStore } from './sound'; export { useSoundStore } from './sound';
export { useLoadingStore } from './loading';

View file

@ -0,0 +1,13 @@
import { create } from 'zustand';
interface LoadingStore {
loaders: Record<string, boolean>;
set: (id: string, value: boolean) => void;
}
export const useLoadingStore = create<LoadingStore>()((set, get) => ({
loaders: {},
set(id: string, value: boolean) {
set({ loaders: { ...get().loaders, [id]: value } });
},
}));