diff --git a/frontend/src/components/forms/Channel.jsx b/frontend/src/components/forms/Channel.jsx
index b4c494e1..53ecddd2 100644
--- a/frontend/src/components/forms/Channel.jsx
+++ b/frontend/src/components/forms/Channel.jsx
@@ -11,7 +11,6 @@ import logo from '../../images/logo.png';
import { useChannelLogoSelection } from '../../hooks/useSmartLogos';
import useLogosStore from '../../store/logos';
import LazyLogo from '../LazyLogo';
-import LogoForm from './Logo';
import {
Box,
Button,
@@ -38,7 +37,7 @@ import {
import { notifications } from '@mantine/notifications';
import { ListOrdered, SquarePlus, SquareX, X, Zap } from 'lucide-react';
import useEPGsStore from '../../store/epgs';
-
+import { Dropzone } from '@mantine/dropzone';
import { FixedSizeList as List } from 'react-window';
import { USER_LEVELS, USER_LEVEL_LABELS } from '../../constants';
@@ -72,7 +71,7 @@ const ChannelForm = ({ channel = null, isOpen, onClose }) => {
const tvgs = useEPGsStore((s) => s.tvgs);
const tvgsById = useEPGsStore((s) => s.tvgsById);
- const [logoModalOpen, setLogoModalOpen] = useState(false);
+ const [logoPreview, setLogoPreview] = useState(null);
const [channelStreams, setChannelStreams] = useState([]);
const [channelGroupModelOpen, setChannelGroupModalOpen] = useState(false);
const [epgPopoverOpened, setEpgPopoverOpened] = useState(false);
@@ -98,12 +97,33 @@ const ChannelForm = ({ channel = null, isOpen, onClose }) => {
setChannelStreams(Array.from(streamSet));
};
- const handleLogoSuccess = ({ logo }) => {
- if (logo && logo.id) {
- formik.setFieldValue('logo_id', logo.id);
- ensureLogosLoaded(); // Refresh logos
+ const handleLogoChange = async (files) => {
+ if (files.length === 1) {
+ const file = files[0];
+
+ // Validate file size on frontend first
+ if (file.size > 5 * 1024 * 1024) {
+ // 5MB
+ notifications.show({
+ title: 'Error',
+ message: 'File too large. Maximum size is 5MB.',
+ color: 'red',
+ });
+ return;
+ }
+
+ try {
+ const retval = await API.uploadLogo(file);
+ // Note: API.uploadLogo already adds the logo to the store, no need to fetch
+ setLogoPreview(retval.cache_url);
+ formik.setFieldValue('logo_id', retval.id);
+ } catch (error) {
+ console.error('Logo upload failed:', error);
+ // Error notification is already handled in API.uploadLogo
+ }
+ } else {
+ setLogoPreview(null);
}
- setLogoModalOpen(false);
};
const handleAutoMatchEpg = async () => {
@@ -789,13 +809,35 @@ const ChannelForm = ({ channel = null, isOpen, onClose }) => {
-
+
+
+
+ OR
+
+
+
+
+
+ Upload Logo
+ console.log('rejected files', files)}
+ maxSize={5 * 1024 ** 2}
+ >
+
+
+ Drag images here or click to select files
+
+
+
+
+
+
@@ -1015,12 +1057,6 @@ const ChannelForm = ({ channel = null, isOpen, onClose }) => {
isOpen={channelGroupModelOpen}
onClose={handleChannelGroupModalClose}
/>
-
- setLogoModalOpen(false)}
- onSuccess={handleLogoSuccess}
- />
>
);
};
diff --git a/frontend/src/components/forms/Logo.jsx b/frontend/src/components/forms/Logo.jsx
index cb7f385e..25847ce8 100644
--- a/frontend/src/components/forms/Logo.jsx
+++ b/frontend/src/components/forms/Logo.jsx
@@ -106,12 +106,13 @@ const LogoForm = ({ logo = null, isOpen, onClose, onSuccess }) => {
onSuccess?.({ type: 'create', logo: newLogo }); // Call onSuccess for creates
} else {
// File was uploaded and logo was already created
+ // Note: API.uploadLogo already calls addLogo() in the store, so no need to call onSuccess
notifications.show({
title: 'Success',
message: 'Logo uploaded successfully',
color: 'green',
});
- onSuccess?.({ type: 'create', logo: uploadResponse });
+ // No onSuccess call needed - API.uploadLogo already updated the store
}
onClose();
} catch (error) {