Improve error handling and validation for playlist profiles in M3UProfiles component

This commit is contained in:
SergeantPanda 2025-05-07 10:57:21 -05:00
parent 72ed1ff4f4
commit 95277679b0

View file

@ -29,8 +29,19 @@ const M3UProfiles = ({ playlist = null, isOpen, onClose }) => {
const [profiles, setProfiles] = useState([]);
useEffect(() => {
setProfiles(allProfiles[playlist.id]);
}, [allProfiles]);
try {
// Make sure playlist exists, has an id, and profiles exist for this playlist
if (playlist && playlist.id && allProfiles && allProfiles[playlist.id]) {
setProfiles(allProfiles[playlist.id]);
} else {
// Reset profiles if none are available
setProfiles([]);
}
} catch (error) {
console.error('Error setting profiles:', error);
setProfiles([]);
}
}, [allProfiles, playlist]);
const editProfile = (profile = null) => {
if (profile) {
@ -41,21 +52,36 @@ const M3UProfiles = ({ playlist = null, isOpen, onClose }) => {
};
const deleteProfile = async (id) => {
await API.deleteM3UProfile(playlist.id, id);
if (!playlist || !playlist.id) return;
try {
await API.deleteM3UProfile(playlist.id, id);
} catch (error) {
console.error('Error deleting profile:', error);
}
};
const toggleActive = async (values) => {
await API.updateM3UProfile(playlist.id, {
...values,
is_active: !values.is_active,
});
if (!playlist || !playlist.id) return;
try {
await API.updateM3UProfile(playlist.id, {
...values,
is_active: !values.is_active,
});
} catch (error) {
console.error('Error toggling profile active state:', error);
}
};
const modifyMaxStreams = async (value, item) => {
await API.updateM3UProfile(playlist.id, {
...item,
max_streams: value,
});
if (!playlist || !playlist.id) return;
try {
await API.updateM3UProfile(playlist.id, {
...item,
max_streams: value,
});
} catch (error) {
console.error('Error updating max streams:', error);
}
};
const closeEditor = () => {
@ -63,80 +89,75 @@ const M3UProfiles = ({ playlist = null, isOpen, onClose }) => {
setProfileEditorOpen(false);
};
if (!isOpen || !profiles) {
// Don't render if modal is not open, or if playlist data is invalid
if (!isOpen || !playlist || !playlist.id) {
return <></>;
}
// Make sure profiles is always an array even if we have no data
const profilesArray = Array.isArray(profiles) ? profiles : [];
return (
<>
<Modal opened={isOpen} onClose={onClose} title="Profiles">
{profiles
// .filter((playlist) => playlist.is_default == false)
.map((item) => (
<Card
key={item.id} // Uncomment/add key prop to fix the list warning
// sx={{
// display: 'flex',
// alignItems: 'center',
// marginBottom: 2,
// }}
>
<Box sx={{ display: 'flex', alignItems: 'center' }}>
<Group justify="space-between">
<Text fw={600}>{item.name}</Text>
<Switch
checked={item.is_active}
onChange={() => toggleActive(item)}
disabled={item.is_default}
style={{ paddingTop: 6 }}
/>
</Group>
{profilesArray.map((item) => (
<Card key={item.id}>
<Box sx={{ display: 'flex', alignItems: 'center' }}>
<Group justify="space-between">
<Text fw={600}>{item.name}</Text>
<Switch
checked={item.is_active}
onChange={() => toggleActive(item)}
disabled={item.is_default}
style={{ paddingTop: 6 }}
/>
</Group>
<Flex gap="sm">
<NumberInput
label="Max Streams"
value={item.max_streams}
disabled={item.is_default}
onChange={(value) => modifyMaxStreams(value, item)}
style={{ flex: 1 }}
/>
<Flex gap="sm">
<NumberInput
label="Max Streams"
value={item.max_streams}
disabled={item.is_default}
onChange={(value) => modifyMaxStreams(value, item)}
style={{ flex: 1 }}
/>
{!item.is_default && (
<Group
align="flex-end"
gap="xs"
style={{ paddingBottom: 8 }}
{!item.is_default && (
<Group
align="flex-end"
gap="xs"
style={{ paddingBottom: 8 }}
>
<ActionIcon
size="sm"
variant="transparent"
color={theme.tailwind.yellow[3]}
onClick={() => editProfile(item)}
>
<ActionIcon
size="sm"
variant="transparent"
color={theme.tailwind.yellow[3]}
onClick={() => editProfile(item)}
>
<SquarePen size="=20" />
</ActionIcon>
<SquarePen size="20" />
</ActionIcon>
<ActionIcon
color={theme.tailwind.red[6]}
onClick={() => deleteProfile(item.id)}
size="small"
variant="transparent"
>
<SquareMinus size="20" />
</ActionIcon>
</Group>
)}
</Flex>
</Box>
</Card>
))}
<ActionIcon
color={theme.tailwind.red[6]}
onClick={() => deleteProfile(item.id)}
size="small"
variant="transparent"
>
<SquareMinus size="20" />
</ActionIcon>
</Group>
)}
</Flex>
</Box>
</Card>
))}
<Flex mih={50} gap="xs" justify="flex-end" align="flex-end">
<Button
variant="contained"
color="primary"
size="small"
onClick={editProfile}
onClick={() => editProfile()}
style={{ width: '100%' }}
>
New