From ee8cf74384ce32fa421909f9d59bb1ce6f33087e Mon Sep 17 00:00:00 2001 From: Sam Chau Date: Wed, 8 Jan 2025 16:17:40 +1030 Subject: [PATCH] fix: ensure data_to_sync has a safe structure and improve sync method handling --- .../src/components/settings/arrs/ArrModal.jsx | 53 ++++++--- .../settings/arrs/DataSelectorModal.jsx | 107 ++++++++++-------- frontend/src/hooks/useArrModal.js | 78 +++++++++---- 3 files changed, 152 insertions(+), 86 deletions(-) diff --git a/frontend/src/components/settings/arrs/ArrModal.jsx b/frontend/src/components/settings/arrs/ArrModal.jsx index c0a735d..ac08250 100644 --- a/frontend/src/components/settings/arrs/ArrModal.jsx +++ b/frontend/src/components/settings/arrs/ArrModal.jsx @@ -39,6 +39,33 @@ const ArrModal = ({isOpen, onClose, onSubmit, editingArr}) => { {value: 'schedule', label: 'Scheduled'} ]; + // Ensure data_to_sync always has the required structure + const safeSelectedData = { + profiles: formData.data_to_sync?.profiles || [], + customFormats: formData.data_to_sync?.customFormats || [] + }; + + // Handle sync method change + const handleSyncMethodChange = e => { + const newMethod = e.target.value; + handleInputChange({ + target: { + id: 'sync_method', + value: newMethod + } + }); + + // Reset data_to_sync when switching to manual + if (newMethod === 'manual') { + handleInputChange({ + target: { + id: 'data_to_sync', + value: {profiles: [], customFormats: []} + } + }); + } + }; + const inputClasses = errorKey => `w-full px-3 py-2 text-sm rounded-lg border ${ errors[errorKey] @@ -261,7 +288,7 @@ const ArrModal = ({isOpen, onClose, onSubmit, editingArr}) => { - onDataToggle( - 'profiles', + - - {profile.content.name} - - - ))} + {profile.content.name} + + + ) + )} @@ -75,45 +81,46 @@ const DataSelectorModal = ({ Custom Formats - {selectedData.customFormats.length}{' '} - selected + {customFormats.length} selected

Note: Custom formats used in selected quality profiles are automatically imported - and do't need to be selected here. + and don't need to be selected here.

- {availableData.customFormats.map(format => ( - - ))} + {format.content.name} + + + ) + )}
diff --git a/frontend/src/hooks/useArrModal.js b/frontend/src/hooks/useArrModal.js index cb29309..9088e5f 100644 --- a/frontend/src/hooks/useArrModal.js +++ b/frontend/src/hooks/useArrModal.js @@ -97,10 +97,12 @@ export const useArrModal = ({isOpen, onSubmit, editingArr}) => { const validateForm = () => { const newErrors = {}; + if (formData.arrServer && !validateUrl(formData.arrServer)) { newErrors.arrServer = 'Please enter a valid URL (e.g., http://localhost:7878)'; } + if ( formData.sync_method === 'schedule' && (!formData.sync_interval || formData.sync_interval < 1) @@ -108,14 +110,18 @@ export const useArrModal = ({isOpen, onSubmit, editingArr}) => { newErrors.sync_interval = 'Please enter a valid interval (minimum 1 minute)'; } - if ( - formData.sync_method !== 'manual' && - !formData.data_to_sync.profiles.length && - !formData.data_to_sync.customFormats.length - ) { - newErrors.data_to_sync = - 'Please select at least one profile or custom format to sync'; + + // Safely check data_to_sync structure + if (formData.sync_method !== 'manual') { + const profiles = formData.data_to_sync?.profiles || []; + const customFormats = formData.data_to_sync?.customFormats || []; + + if (profiles.length === 0 && customFormats.length === 0) { + newErrors.data_to_sync = + 'Please select at least one profile or custom format to sync'; + } } + setErrors(newErrors); return Object.keys(newErrors).length === 0; }; @@ -240,28 +246,54 @@ export const useArrModal = ({isOpen, onSubmit, editingArr}) => { const handleInputChange = e => { const {id, value} = e.target; - setFormData(prev => ({ - ...prev, - [id]: id === 'sync_interval' ? parseInt(value) || 0 : value, - ...(id === 'sync_method' && value === 'manual' - ? {data_to_sync: {profiles: [], customFormats: []}} - : {}) - })); + setFormData(prev => { + // Handle sync method changes + if (id === 'sync_method') { + return { + ...prev, + [id]: value, + data_to_sync: + value === 'manual' + ? {profiles: [], customFormats: []} + : prev.data_to_sync || { + profiles: [], + customFormats: [] + } + }; + } + + // Handle other input changes + return { + ...prev, + [id]: id === 'sync_interval' ? parseInt(value) || 0 : value + }; + }); + if (errors[id]) { setErrors(prev => ({...prev, [id]: ''})); } }; const handleDataToggle = (type, name) => { - setFormData(prev => ({ - ...prev, - data_to_sync: { - ...prev.data_to_sync, - [type]: prev.data_to_sync[type].includes(name) - ? prev.data_to_sync[type].filter(item => item !== name) - : [...prev.data_to_sync[type], name] - } - })); + setFormData(prev => { + // Ensure data_to_sync exists with proper structure + const currentData = prev.data_to_sync || { + profiles: [], + customFormats: [] + }; + const currentArray = currentData[type] || []; + + return { + ...prev, + data_to_sync: { + ...currentData, + [type]: currentArray.includes(name) + ? currentArray.filter(item => item !== name) + : [...currentArray, name] + } + }; + }); + if (errors.data_to_sync) { setErrors(prev => ({...prev, data_to_sync: ''})); }