Component cleanup and refactoring

This commit is contained in:
Nick Sandstrom 2026-03-02 23:23:01 -08:00
parent f3304bd976
commit d292676b73
3 changed files with 45 additions and 59 deletions

View file

@ -48,7 +48,7 @@ export default function M3URefreshNotification() {
const refreshProgress = usePlaylistsStore((s) => s.refreshProgress);
const fetchStreams = useStreamsStore((s) => s.fetchStreams);
const fetchChannelGroups = useChannelsStore((s) => s.fetchChannelGroups);
const fetchChannelIds = useChannelsStore((s) => s.fetchChannelIds);
const fetchChannels = useChannelsStore((s) => s.fetchChannels);
const fetchPlaylists = usePlaylistsStore((s) => s.fetchPlaylists);
const fetchEPGData = useEPGsStore((s) => s.fetchEPGData);
const fetchCategories = useVODStore((s) => s.fetchCategories);
@ -151,28 +151,6 @@ export default function M3URefreshNotification() {
triggerPostCompletionFetches(data.action);
}
if (taskProgress == 0) {
message = `${message} starting...`;
} else if (taskProgress == 100) {
message = `${message} complete!`;
// Only trigger additional fetches on successful completion
if (data.action == 'parsing') {
fetchStreams();
API.requeryChannels();
fetchChannelIds();
} else if (data.action == 'processing_groups') {
fetchStreams();
fetchChannelGroups();
fetchEPGData();
fetchPlaylists();
} else if (data.action == 'vod_refresh') {
// VOD refresh completed, trigger VOD categories refresh
fetchPlaylists(); // Refresh playlist data to show updated VOD info
fetchCategories(); // Refresh VOD categories to make them visible
}
}
showNotification({
title: `M3U Processing: ${playlist.name}`,
message,

View file

@ -1,4 +1,4 @@
import React, { useEffect, useState, useCallback } from 'react';
import React, { useCallback, useEffect, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import {
ActionIcon,
@ -10,7 +10,9 @@ import {
Group,
Indicator,
Popover,
ScrollArea,
PopoverDropdown,
PopoverTarget,
ScrollAreaAutosize,
Stack,
Text,
ThemeIcon,
@ -18,22 +20,26 @@ import {
useMantineTheme,
} from '@mantine/core';
import {
AlertTriangle,
ArrowRight,
Bell,
Check,
CheckCheck,
Download,
ExternalLink,
Info,
Settings,
AlertTriangle,
Megaphone,
X,
Eye,
EyeOff,
ArrowRight,
Info,
Megaphone,
Settings,
X,
} from 'lucide-react';
import useNotificationsStore from '../store/notifications';
import API from '../api';
import {
dismissAllNotifications,
dismissNotification,
getNotifications,
} from '../utils/components/NotificationCenterUtils.js';
// Get icon for notification type
const getNotificationIcon = (type) => {
@ -139,7 +145,9 @@ const NotificationItem = ({ notification, onDismiss, onAction, onClose }) => {
color="gray"
size="sm"
onClick={handleDismiss}
style={{ position: 'absolute', top: 8, right: 8 }}
pos='absolute'
top={8}
right={8}
>
<X size={14} />
</ActionIcon>
@ -149,7 +157,7 @@ const NotificationItem = ({ notification, onDismiss, onAction, onClose }) => {
<ThemeIcon color={typeColor} variant="light" size="md" radius="xl">
{getNotificationIcon(notification.notification_type)}
</ThemeIcon>
<Box style={{ flex: 1 }}>
<Box flex={1}>
<Group gap="xs" mb={4}>
<Text size="sm" fw={600} lineClamp={1}>
{notification.title}
@ -249,7 +257,7 @@ const NotificationCenter = ({ onSettingAction }) => {
// Fetch notifications on mount and periodically
const fetchNotifications = useCallback(async () => {
try {
await API.getNotifications(showDismissed);
await getNotifications(showDismissed);
} catch (error) {
console.error('Failed to fetch notifications:', error);
}
@ -265,7 +273,7 @@ const NotificationCenter = ({ onSettingAction }) => {
const handleDismiss = async (notificationId, actionTaken = null) => {
try {
await API.dismissNotification(notificationId, actionTaken);
await dismissNotification(notificationId, actionTaken);
} catch (error) {
console.error('Failed to dismiss notification:', error);
}
@ -273,7 +281,7 @@ const NotificationCenter = ({ onSettingAction }) => {
const handleDismissAll = async () => {
try {
await API.dismissAllNotifications();
await dismissAllNotifications();
} catch (error) {
console.error('Failed to dismiss all notifications:', error);
}
@ -302,7 +310,7 @@ const NotificationCenter = ({ onSettingAction }) => {
shadow="lg"
withArrow
>
<Popover.Target>
<PopoverTarget>
<Indicator
color="red"
size={16}
@ -321,9 +329,9 @@ const NotificationCenter = ({ onSettingAction }) => {
<Bell size={20} />
</ActionIcon>
</Indicator>
</Popover.Target>
</PopoverTarget>
<Popover.Dropdown p={0}>
<PopoverDropdown p={0}>
{/* Header */}
<Group justify="space-between" p="sm" pb="xs">
<Group gap="xs">
@ -367,7 +375,7 @@ const NotificationCenter = ({ onSettingAction }) => {
<Divider />
{/* Notification list */}
<ScrollArea.Autosize mah={400} type="auto" offsetScrollbars>
<ScrollAreaAutosize mah={400} type="auto" offsetScrollbars>
{displayedNotifications.length === 0 ? (
<Box p="lg" ta="center">
<ThemeIcon
@ -403,7 +411,7 @@ const NotificationCenter = ({ onSettingAction }) => {
))}
</Stack>
)}
</ScrollArea.Autosize>
</ScrollAreaAutosize>
{/* Footer with info text */}
{!showDismissed &&
@ -421,7 +429,7 @@ const NotificationCenter = ({ onSettingAction }) => {
</Box>
</>
)}
</Popover.Dropdown>
</PopoverDropdown>
</Popover>
);
};

View file

@ -84,18 +84,16 @@ function NavGroup({ label, icon, paths, location, collapsed }) {
.includes(location.pathname);
return (
<Box
style={{ width: '100%', paddingRight: 2 }}
<Box w='100%' pr={2}
className={open ? 'navgroup-open' : ''}
>
<UnstyledButton
<UnstyledButton w='100%'
onClick={() => setOpen((o) => !o)}
className={`navlink ${parentActive ? 'navlink-parent-active' : ''} ${open ? 'navlink-collapsed' : ''}`}
style={{ width: '100%' }}
>
{icon}
{!collapsed && (
<Group justify="space-between" style={{ width: '100%' }}>
<Group justify="space-between" w='100%'>
<Text
sx={{
opacity: open ? 0 : 1,
@ -109,7 +107,7 @@ function NavGroup({ label, icon, paths, location, collapsed }) {
{label}
</Text>
<Box alignItems="center" style={{ display: 'flex' }}>
<Box alignItems="center" display='flex'>
{open ? <ChevronDown size={16} /> : <ChevronRight size={16} />}
</Box>
</Group>
@ -117,13 +115,13 @@ function NavGroup({ label, icon, paths, location, collapsed }) {
</UnstyledButton>
{open && (
<Box style={{ paddingTop: 10 }}>
<Box pt={10}>
<Stack gap="xs" pl={open ? 0 : 'lg'}>
{paths.map((child) => {
const active = location.pathname === child.path;
return (
<Box
style={{ paddingLeft: collapsed ? 0 : 35 }}
pl={collapsed ? 0 : 35}
key={child.path}
>
<NavLink
@ -251,9 +249,9 @@ const Sidebar = ({ collapsed, toggleDrawer, drawerWidth, miniDrawerWidth }) => {
p="xs"
mih="100vh"
display='flex'
br='1px solid #2A2A2E'
style={{
backgroundColor: '#1A1A1E',
borderRight: '1px solid #2A2A2E',
flexDirection: 'column',
}}
>
@ -297,9 +295,9 @@ const Sidebar = ({ collapsed, toggleDrawer, drawerWidth, miniDrawerWidth }) => {
<Stack
gap="xs"
mt="lg"
flex={1}
mih={0}
style={{
flex: 1,
minHeight: 0,
overflowY: 'auto',
overflowX: 'hidden',
}}
@ -337,10 +335,10 @@ const Sidebar = ({ collapsed, toggleDrawer, drawerWidth, miniDrawerWidth }) => {
mt='auto'
p={16}
display='flex'
bt='1px solid #2A2A2E'
style={{
alignItems: 'center',
gap: 10,
borderTop: '1px solid #2A2A2E',
justifyContent: collapsed ? 'center' : 'flex-start',
}}
>
@ -378,7 +376,8 @@ const Sidebar = ({ collapsed, toggleDrawer, drawerWidth, miniDrawerWidth }) => {
{!collapsed && authUser && (
<Group
gap="xs"
style={{ justifyContent: 'space-between', width: '100%' }}
w='100%'
style={{ justifyContent: 'space-between' }}
>
<Group gap="xs">
<Avatar src="" radius="xl" />
@ -404,7 +403,8 @@ const Sidebar = ({ collapsed, toggleDrawer, drawerWidth, miniDrawerWidth }) => {
{!collapsed && (
<Group
gap="xs"
style={{ padding: '0 16px 16px', justifyContent: 'space-between' }}
p={'0 16px 16px'}
style={{ justifyContent: 'space-between' }}
>
<Text size="xs" c="dimmed">
v{appVersion?.version || '0.0.0'}
@ -415,9 +415,9 @@ const Sidebar = ({ collapsed, toggleDrawer, drawerWidth, miniDrawerWidth }) => {
)}
{collapsed && isAuthenticated && (
<Box
p={'0 16px 16px'}
display='flex'
style={{
padding: '0 16px 16px',
display: 'flex',
justifyContent: 'center',
}}
>