fix: AIPresetModal merge backend presets instead of overwrite

Backend sync effect (useEffect mount) was unconditionally
replacing mgr.presets with data.presets, destroying:
- Frontend-only default presets (12 vs backend's 7)
- User-defined presets in localStorage not yet synced to backend

Fix: merge backend presets by id — keep all local presets,
append any backend presets whose id doesn't exist locally.
User presets + frontend defaults are never lost.
This commit is contained in:
2026-07-28 20:17:52 +07:00
parent 71edf7ffb3
commit 6a46b1ffe4
2 changed files with 17 additions and 9 deletions
+15 -7
View File
@@ -4308,19 +4308,27 @@ const AIPresetModal = ({ isOpen, onClose }) => {
const [formScale, setFormScale] = React.useState('C Minor');
const [formTemplate, setFormTemplate] = React.useState('');
// Try to sync from backend on mount
// Sync from backend on mount merge into local presets, never overwrite
React.useEffect(() => {
if (!window.SonicAPI) return;
setSyncing(true);
window.SonicAPI.getAIPresets()
.then(data => {
if (data && data.presets && data.presets.length > 0) {
mgr.presets = data.presets;
setPresets([...data.presets]);
}
if (!data || !data.presets || data.presets.length === 0) return;
var existing = mgr.presets;
var existingIds = new Set(existing.map(function(p) { return p.id; }));
var merged = existing.slice();
data.presets.forEach(function(bp) {
if (!existingIds.has(bp.id)) {
merged.push(bp);
existingIds.add(bp.id);
}
});
mgr.presets = merged;
setPresets(merged);
})
.catch(() => {})
.finally(() => setSyncing(false));
.catch(function() {})
.finally(function() { setSyncing(false); });
}, []);
const savePresets = (newPresets) => {