From 105df86af933f88fee540c80e1fe85e592f5cb44 Mon Sep 17 00:00:00 2001 From: kappa118 Date: Sat, 1 Mar 2025 20:00:17 -0500 Subject: [PATCH] latest frontend changes --- frontend/src/App.js | 6 ++++- frontend/src/components/Alert.js | 26 ++++++++++++++++++ frontend/src/components/forms/UserAgent.js | 27 ++++++++++--------- .../components/tables/StreamProfilesTable.js | 13 +++++++-- .../src/components/tables/UserAgentsTable.js | 14 ++++++++++ frontend/src/store/alerts.js | 24 +++++++++++++++++ 6 files changed, 94 insertions(+), 16 deletions(-) create mode 100644 frontend/src/components/Alert.js create mode 100644 frontend/src/store/alerts.js diff --git a/frontend/src/App.js b/frontend/src/App.js index 914e13ac..257e209a 100644 --- a/frontend/src/App.js +++ b/frontend/src/App.js @@ -28,6 +28,7 @@ import Settings from './pages/Settings'; import StreamProfiles from './pages/StreamProfiles'; import useAuthStore from './store/auth'; import logo from './images/logo.png'; +import Alert from './components/Alert'; // NEW: import the floating PiP component import FloatingVideo from './components/FloatingVideo'; @@ -110,8 +111,8 @@ const App = () => { flexDirection: 'column', ml: `${open ? drawerWidth : miniDrawerWidth}px`, transition: 'width 0.3s, margin-left 0.3s', - // height: '100vh', backgroundColor: '#495057', + height: '100%', }} > { + {/* Global Snackbar for system-wide messages */} + + {/* Always-available floating video; remains visible across page changes */} diff --git a/frontend/src/components/Alert.js b/frontend/src/components/Alert.js new file mode 100644 index 00000000..8f625364 --- /dev/null +++ b/frontend/src/components/Alert.js @@ -0,0 +1,26 @@ +import React, { useState } from 'react'; +import { Snackbar, Alert, Button } from '@mui/material'; +import useAlertStore from '../store/alerts'; + +const AlertPopup = () => { + const { open, message, severity, hideAlert } = useAlertStore(); + + const handleClose = () => { + hideAlert(); + }; + + return ( + + + {message} + + + ); +}; + +export default AlertPopup; diff --git a/frontend/src/components/forms/UserAgent.js b/frontend/src/components/forms/UserAgent.js index 6f5f80c4..db13429f 100644 --- a/frontend/src/components/forms/UserAgent.js +++ b/frontend/src/components/forms/UserAgent.js @@ -1,5 +1,5 @@ // Modal.js -import React, { useEffect } from "react"; +import React, { useEffect } from 'react'; import { TextField, Button, @@ -9,22 +9,23 @@ import { DialogTitle, DialogContent, DialogActions, -} from "@mui/material"; -import { useFormik } from "formik"; -import * as Yup from "yup"; -import API from "../../api"; +} from '@mui/material'; +import { useFormik } from 'formik'; +import * as Yup from 'yup'; +import API from '../../api'; +import useSettingsStore from '../../store/settings'; const UserAgent = ({ userAgent = null, isOpen, onClose }) => { const formik = useFormik({ initialValues: { - user_agent_name: "", - user_agent: "", - description: "", + user_agent_name: '', + user_agent: '', + description: '', is_active: true, }, validationSchema: Yup.object({ - user_agent_name: Yup.string().required("Name is required"), - user_agent: Yup.string().required("User-Agent is required"), + user_agent_name: Yup.string().required('Name is required'), + user_agent: Yup.string().required('User-Agent is required'), }), onSubmit: async (values, { setSubmitting, resetForm }) => { if (userAgent?.id) { @@ -60,8 +61,8 @@ const UserAgent = ({ userAgent = null, isOpen, onClose }) => { User-Agent @@ -132,7 +133,7 @@ const UserAgent = ({ userAgent = null, isOpen, onClose }) => { color="primary" disabled={formik.isSubmitting} > - {formik.isSubmitting ? : "Submit"} + {formik.isSubmitting ? : 'Submit'} diff --git a/frontend/src/components/tables/StreamProfilesTable.js b/frontend/src/components/tables/StreamProfilesTable.js index b23257a8..c22d6c4b 100644 --- a/frontend/src/components/tables/StreamProfilesTable.js +++ b/frontend/src/components/tables/StreamProfilesTable.js @@ -30,6 +30,8 @@ import useEPGsStore from '../../store/epgs'; import StreamProfileForm from '../forms/StreamProfile'; import useStreamProfilesStore from '../../store/streamProfiles'; import { TableHelper } from '../../helpers'; +import useSettingsStore from '../../store/settings'; +import useAlertStore from '../../store/alerts'; const StreamProfiles = () => { const [profile, setProfile] = useState(null); @@ -40,6 +42,8 @@ const StreamProfiles = () => { const [activeFilterValue, setActiveFilterValue] = useState('all'); const streamProfiles = useStreamProfilesStore((state) => state.profiles); + const { settings } = useSettingsStore(); + const { showAlert } = useAlertStore(); const columns = useMemo( //column definitions... @@ -112,8 +116,13 @@ const StreamProfiles = () => { setProfileModalOpen(true); }; - const deleteStreamProfile = async (ids) => { - await API.deleteStreamProfile(ids); + const deleteStreamProfile = async (id) => { + if (id == settings['default-stream-profile'].value) { + showAlert('Cannot delete default stream-profile', 'error'); + return; + } + + await API.deleteStreamProfile(id); }; const closeStreamProfileForm = () => { diff --git a/frontend/src/components/tables/UserAgentsTable.js b/frontend/src/components/tables/UserAgentsTable.js index 7271aff8..a8ecb81d 100644 --- a/frontend/src/components/tables/UserAgentsTable.js +++ b/frontend/src/components/tables/UserAgentsTable.js @@ -26,6 +26,8 @@ import { import useUserAgentsStore from '../../store/userAgents'; import UserAgentForm from '../forms/UserAgent'; import { TableHelper } from '../../helpers'; +import useSettingsStore from '../../store/settings'; +import useAlertStore from '../../store/alerts'; const UserAgentsTable = () => { const [userAgent, setUserAgent] = useState(null); @@ -34,6 +36,8 @@ const UserAgentsTable = () => { const [activeFilterValue, setActiveFilterValue] = useState('all'); const userAgents = useUserAgentsStore((state) => state.userAgents); + const { settings } = useSettingsStore(); + const { showAlert } = useAlertStore(); const columns = useMemo( //column definitions... @@ -108,8 +112,18 @@ const UserAgentsTable = () => { const deleteUserAgent = async (ids) => { if (Array.isArray(ids)) { + if (ids.includes(settings['default-user-agent'].value)) { + showAlert('Cannot delete default user-agent', 'error'); + return; + } + await API.deleteUserAgents(ids); } else { + if (ids == settings['default-user-agent'].value) { + showAlert('Cannot delete default user-agent', 'error'); + return; + } + await API.deleteUserAgent(ids); } }; diff --git a/frontend/src/store/alerts.js b/frontend/src/store/alerts.js new file mode 100644 index 00000000..b51076a3 --- /dev/null +++ b/frontend/src/store/alerts.js @@ -0,0 +1,24 @@ +// frontend/src/store/useAlertStore.js +import { create } from 'zustand'; + +/** + * Global store to track whether a floating video is visible and which URL is playing. + */ +const useAlertStore = create((set) => ({ + open: false, + message: '', + severity: 'info', + + showAlert: (message, severity = 'info') => + set({ + open: true, + message, + severity, + }), + + hideAlert: () => { + set({ open: false }); + }, +})); + +export default useAlertStore;