Signed-off-by: mbrucedogs <mbrucedogs@gmail.com>
This commit is contained in:
parent
9dce7874a4
commit
ca9717fe7c
@ -6,13 +6,19 @@ import { FirebaseProvider } from './firebase/FirebaseProvider';
|
||||
import { ErrorBoundary } from './components/common';
|
||||
import { AuthInitializer } from './components/Auth';
|
||||
import { ModalProvider } from './components/common/ModalProvider';
|
||||
import ToastProvider from './components/common/ToastProvider';
|
||||
import { useAppSelector } from './redux';
|
||||
import { selectSettings } from './redux';
|
||||
|
||||
function App() {
|
||||
const playerSettings = useAppSelector(selectSettings);
|
||||
const showToasts = playerSettings?.showToasts ?? true;
|
||||
return (
|
||||
<ErrorBoundary>
|
||||
<FirebaseProvider>
|
||||
<Router>
|
||||
<AuthInitializer>
|
||||
<ToastProvider toastsEnabled={showToasts}>
|
||||
<ModalProvider>
|
||||
<Layout>
|
||||
<Routes>
|
||||
@ -31,6 +37,7 @@ function App() {
|
||||
</Routes>
|
||||
</Layout>
|
||||
</ModalProvider>
|
||||
</ToastProvider>
|
||||
</AuthInitializer>
|
||||
</Router>
|
||||
</FirebaseProvider>
|
||||
|
||||
57
src/components/common/ToastProvider.tsx
Normal file
57
src/components/common/ToastProvider.tsx
Normal file
@ -0,0 +1,57 @@
|
||||
import React, { useState, useCallback, useMemo } from 'react';
|
||||
import Toast from './Toast';
|
||||
import { ToastContext } from '../../hooks/useToast';
|
||||
import type { ToastProps } from '../../types';
|
||||
|
||||
interface ToastItem extends Omit<ToastProps, 'onClose'> {
|
||||
id: string;
|
||||
}
|
||||
|
||||
const ToastProvider: React.FC<{ children: React.ReactNode; toastsEnabled?: boolean }> = ({ children, toastsEnabled = true }) => {
|
||||
const [toasts, setToasts] = useState<ToastItem[]>([]);
|
||||
|
||||
const showToast = useCallback((toast: Omit<ToastProps, 'onClose'>) => {
|
||||
const id = Math.random().toString(36).substr(2, 9);
|
||||
const newToast: ToastItem = { ...toast, id };
|
||||
setToasts(prev => [...prev, newToast]);
|
||||
}, []);
|
||||
|
||||
const removeToast = useCallback((id: string) => {
|
||||
setToasts(prev => prev.filter(toast => toast.id !== id));
|
||||
}, []);
|
||||
|
||||
const showSuccess = useCallback((message: string, duration = 3000) => {
|
||||
showToast({ message, type: 'success', duration });
|
||||
}, [showToast]);
|
||||
|
||||
const showError = useCallback((message: string, duration = 5000) => {
|
||||
showToast({ message, type: 'error', duration });
|
||||
}, [showToast]);
|
||||
|
||||
const showInfo = useCallback((message: string, duration = 3000) => {
|
||||
showToast({ message, type: 'info', duration });
|
||||
}, [showToast]);
|
||||
|
||||
const contextValue = useMemo(() => ({
|
||||
showToast,
|
||||
showSuccess,
|
||||
showError,
|
||||
showInfo,
|
||||
removeToast,
|
||||
}), [showToast, showSuccess, showError, showInfo, removeToast]);
|
||||
|
||||
return (
|
||||
<ToastContext.Provider value={contextValue}>
|
||||
{children}
|
||||
{toastsEnabled && toasts.map(toast => (
|
||||
<Toast
|
||||
key={toast.id}
|
||||
{...toast}
|
||||
onClose={() => removeToast(toast.id)}
|
||||
/>
|
||||
))}
|
||||
</ToastContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export default ToastProvider;
|
||||
@ -2,7 +2,9 @@ import React, { useState } from 'react';
|
||||
import { IonContent, IonHeader, IonTitle, IonToolbar, IonList, IonItem, IonLabel, IonToggle, IonButton, IonIcon, IonModal, IonSearchbar } from '@ionic/react';
|
||||
import { ban } from 'ionicons/icons';
|
||||
import { useAppSelector } from '../../redux';
|
||||
import { selectIsAdmin, selectSettings } from '../../redux';
|
||||
import { selectIsAdmin, selectSettings, updateController, selectControllerName } from '../../redux';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { settingsService } from '../../firebase/services';
|
||||
import { useDisabledSongs } from '../../hooks';
|
||||
import { InfiniteScrollList, ActionButton, SongItem } from '../../components/common';
|
||||
import { ActionButtonVariant, ActionButtonSize, ActionButtonIconSlot } from '../../types';
|
||||
@ -14,6 +16,7 @@ import type { Song, DisabledSong } from '../../types';
|
||||
const Settings: React.FC = () => {
|
||||
const isAdmin = useAppSelector(selectIsAdmin);
|
||||
const playerSettings = useAppSelector(selectSettings);
|
||||
const dispatch = useDispatch();
|
||||
const {
|
||||
disabledSongs,
|
||||
loading,
|
||||
@ -22,6 +25,8 @@ const Settings: React.FC = () => {
|
||||
|
||||
const [showDisabledSongsModal, setShowDisabledSongsModal] = useState(false);
|
||||
const [searchTerm, setSearchTerm] = useState('');
|
||||
const controllerNameRedux = useAppSelector(selectControllerName);
|
||||
const existingPlayer = useAppSelector(state => state.controller.data?.player) || {};
|
||||
|
||||
// Convert disabled songs object to array for display
|
||||
const disabledSongsArray: DisabledSong[] = Object.entries(disabledSongs).map(([key, disabledSong]) => ({
|
||||
@ -38,8 +43,23 @@ const Settings: React.FC = () => {
|
||||
: disabledSongsArray;
|
||||
|
||||
const handleToggleSetting = async (setting: string, value: boolean) => {
|
||||
// This would need to be implemented with the settings service
|
||||
debugLog(`Toggle ${setting} to ${value}`);
|
||||
const controllerName = controllerNameRedux;
|
||||
if (controllerName) {
|
||||
await settingsService.updateSetting(controllerName, setting, value);
|
||||
dispatch(updateController({
|
||||
controllerName,
|
||||
updates: {
|
||||
player: {
|
||||
...existingPlayer,
|
||||
settings: {
|
||||
...existingPlayer.settings,
|
||||
[setting]: value
|
||||
}
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
const handleToggleDebug = (enabled: boolean) => {
|
||||
@ -88,6 +108,14 @@ const Settings: React.FC = () => {
|
||||
onIonChange={(e) => handleToggleSetting('userpick', e.detail.checked)}
|
||||
/>
|
||||
</IonItem>
|
||||
<IonItem>
|
||||
<IonLabel>Show Toasts</IonLabel>
|
||||
<IonToggle
|
||||
slot="end"
|
||||
checked={playerSettings?.showToasts ?? true}
|
||||
onIonChange={(e) => handleToggleSetting('showToasts', e.detail.checked)}
|
||||
/>
|
||||
</IonItem>
|
||||
<IonItem>
|
||||
<IonLabel>Debug Logging</IonLabel>
|
||||
<IonToggle
|
||||
|
||||
@ -1,45 +1,16 @@
|
||||
import { useState, useCallback } from 'react';
|
||||
import { createContext, useContext } from 'react';
|
||||
import type { ToastProps } from '../types';
|
||||
|
||||
interface ToastItem extends Omit<ToastProps, 'onClose'> {
|
||||
id: string;
|
||||
interface ToastContextType {
|
||||
showToast: (toast: Omit<ToastProps, 'onClose'>) => void;
|
||||
showSuccess: (message: string, duration?: number) => void;
|
||||
showError: (message: string, duration?: number) => void;
|
||||
showInfo: (message: string, duration?: number) => void;
|
||||
removeToast: (id: string) => void;
|
||||
}
|
||||
|
||||
export const ToastContext = createContext<ToastContextType | undefined>(undefined);
|
||||
|
||||
export const useToast = () => {
|
||||
const [toasts, setToasts] = useState<ToastItem[]>([]);
|
||||
|
||||
const showToast = useCallback((toast: Omit<ToastProps, 'onClose'>) => {
|
||||
const id = Math.random().toString(36).substr(2, 9);
|
||||
const newToast: ToastItem = {
|
||||
...toast,
|
||||
id,
|
||||
};
|
||||
|
||||
setToasts(prev => [...prev, newToast]);
|
||||
}, []);
|
||||
|
||||
const removeToast = useCallback((id: string) => {
|
||||
setToasts(prev => prev.filter(toast => toast.id !== id));
|
||||
}, []);
|
||||
|
||||
const showSuccess = useCallback((message: string, duration = 3000) => {
|
||||
showToast({ message, type: 'success', duration });
|
||||
}, [showToast]);
|
||||
|
||||
const showError = useCallback((message: string, duration = 5000) => {
|
||||
showToast({ message, type: 'error', duration });
|
||||
}, [showToast]);
|
||||
|
||||
const showInfo = useCallback((message: string, duration = 3000) => {
|
||||
showToast({ message, type: 'info', duration });
|
||||
}, [showToast]);
|
||||
|
||||
return {
|
||||
toasts,
|
||||
showToast,
|
||||
showSuccess,
|
||||
showError,
|
||||
showInfo,
|
||||
removeToast,
|
||||
};
|
||||
return useContext(ToastContext);
|
||||
};
|
||||
@ -36,6 +36,7 @@ export interface QueueItem extends Keyable {
|
||||
export interface Settings {
|
||||
autoadvance: boolean;
|
||||
userpick: boolean;
|
||||
showToasts?: boolean;
|
||||
}
|
||||
|
||||
export interface Singer extends Keyable {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user