fix add to playlist modal not checking songs, making playlist causes big issues
This commit is contained in:
parent
0b6c1a4230
commit
de86337e3e
4 changed files with 138 additions and 38 deletions
|
|
@ -928,6 +928,13 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||||
ui.renderLibraryPage();
|
ui.renderLibraryPage();
|
||||||
} else if (hash === '#home' || hash === '') {
|
} else if (hash === '#home' || hash === '') {
|
||||||
ui.renderHomePage();
|
ui.renderHomePage();
|
||||||
|
} else if (hash.startsWith('#userplaylist/')) {
|
||||||
|
const playlistId = hash.split('/')[1];
|
||||||
|
const content = document.querySelector('.main-content');
|
||||||
|
const scroll = content ? content.scrollTop : 0;
|
||||||
|
ui.renderPlaylistPage(playlistId, 'user').then(() => {
|
||||||
|
if (content) content.scrollTop = scroll;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
window.addEventListener('history-changed', () => {
|
window.addEventListener('history-changed', () => {
|
||||||
|
|
|
||||||
55
js/db.js
55
js/db.js
|
|
@ -168,27 +168,27 @@ export class MusicDatabase {
|
||||||
if (type === 'track') {
|
if (type === 'track') {
|
||||||
return {
|
return {
|
||||||
...base,
|
...base,
|
||||||
title: item.title,
|
title: item.title || null,
|
||||||
duration: item.duration,
|
duration: item.duration || null,
|
||||||
explicit: item.explicit,
|
explicit: item.explicit || false,
|
||||||
// Keep minimal artist info
|
// Keep minimal artist info
|
||||||
artist: item.artist || (item.artists && item.artists.length > 0 ? item.artists[0] : null),
|
artist: item.artist || (item.artists && item.artists.length > 0 ? item.artists[0] : null) || null,
|
||||||
artists: item.artists?.map((a) => ({ id: a.id, name: a.name })) || [],
|
artists: item.artists?.map((a) => ({ id: a.id, name: a.name || null })) || [],
|
||||||
// Keep minimal album info
|
// Keep minimal album info
|
||||||
album: item.album
|
album: item.album
|
||||||
? {
|
? {
|
||||||
id: item.album.id,
|
id: item.album.id,
|
||||||
title: item.album.title,
|
title: item.album.title || null,
|
||||||
cover: item.album.cover,
|
cover: item.album.cover || null,
|
||||||
releaseDate: item.album.releaseDate || null,
|
releaseDate: item.album.releaseDate || null,
|
||||||
vibrantColor: item.album.vibrantColor || null,
|
vibrantColor: item.album.vibrantColor || null,
|
||||||
artist: item.album.artist,
|
artist: item.album.artist || null,
|
||||||
numberOfTracks: item.album.numberOfTracks,
|
numberOfTracks: item.album.numberOfTracks || null,
|
||||||
}
|
}
|
||||||
: null,
|
: null,
|
||||||
copyright: item.copyright,
|
copyright: item.copyright || null,
|
||||||
isrc: item.isrc,
|
isrc: item.isrc || null,
|
||||||
trackNumber: item.trackNumber,
|
trackNumber: item.trackNumber || null,
|
||||||
// Fallback date
|
// Fallback date
|
||||||
streamStartDate: item.streamStartDate || null,
|
streamStartDate: item.streamStartDate || null,
|
||||||
// Keep version if exists
|
// Keep version if exists
|
||||||
|
|
@ -201,26 +201,26 @@ export class MusicDatabase {
|
||||||
if (type === 'album') {
|
if (type === 'album') {
|
||||||
return {
|
return {
|
||||||
...base,
|
...base,
|
||||||
title: item.title,
|
title: item.title || null,
|
||||||
cover: item.cover,
|
cover: item.cover || null,
|
||||||
releaseDate: item.releaseDate || null,
|
releaseDate: item.releaseDate || null,
|
||||||
explicit: item.explicit,
|
explicit: item.explicit || false,
|
||||||
// UI uses singular 'artist'
|
// UI uses singular 'artist'
|
||||||
artist: item.artist
|
artist: item.artist
|
||||||
? { name: item.artist.name, id: item.artist.id }
|
? { name: item.artist.name || null, id: item.artist.id }
|
||||||
: item.artists?.[0]
|
: item.artists?.[0]
|
||||||
? { name: item.artists[0].name, id: item.artists[0].id }
|
? { name: item.artists[0].name || null, id: item.artists[0].id }
|
||||||
: null,
|
: null,
|
||||||
// Keep type and track count for UI labels
|
// Keep type and track count for UI labels
|
||||||
type: item.type || null,
|
type: item.type || null,
|
||||||
numberOfTracks: item.numberOfTracks,
|
numberOfTracks: item.numberOfTracks || null,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type === 'artist') {
|
if (type === 'artist') {
|
||||||
return {
|
return {
|
||||||
...base,
|
...base,
|
||||||
name: item.name,
|
name: item.name || null,
|
||||||
picture: item.picture || item.image || null, // Handle both just in case
|
picture: item.picture || item.image || null, // Handle both just in case
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -229,11 +229,11 @@ export class MusicDatabase {
|
||||||
return {
|
return {
|
||||||
uuid: item.uuid || item.id,
|
uuid: item.uuid || item.id,
|
||||||
addedAt: item.addedAt || item.createdAt || null,
|
addedAt: item.addedAt || item.createdAt || null,
|
||||||
title: item.title || item.name,
|
title: item.title || item.name || null,
|
||||||
// UI checks squareImage || image || uuid
|
// UI checks squareImage || image || uuid
|
||||||
image: item.image || item.squareImage || item.cover || null,
|
image: item.image || item.squareImage || item.cover || null,
|
||||||
numberOfTracks: item.numberOfTracks || (item.tracks ? item.tracks.length : 0),
|
numberOfTracks: item.numberOfTracks || (item.tracks ? item.tracks.length : 0),
|
||||||
user: item.user ? { name: item.user.name } : null,
|
user: item.user ? { name: item.user.name || null } : null,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -260,7 +260,7 @@ export class MusicDatabase {
|
||||||
const mixes = await this.getFavorites('mix');
|
const mixes = await this.getFavorites('mix');
|
||||||
const history = await this.getHistory();
|
const history = await this.getHistory();
|
||||||
|
|
||||||
const userPlaylists = await this.getPlaylists();
|
const userPlaylists = await this.getPlaylists(true);
|
||||||
const data = {
|
const data = {
|
||||||
favorites_tracks: tracks.map((t) => this._minifyItem('track', t)),
|
favorites_tracks: tracks.map((t) => this._minifyItem('track', t)),
|
||||||
favorites_albums: albums.map((a) => this._minifyItem('album', a)),
|
favorites_albums: albums.map((a) => this._minifyItem('album', a)),
|
||||||
|
|
@ -339,6 +339,7 @@ export class MusicDatabase {
|
||||||
tracks: tracks.map((t) => this._minifyItem('track', t)),
|
tracks: tracks.map((t) => this._minifyItem('track', t)),
|
||||||
cover: cover,
|
cover: cover,
|
||||||
createdAt: Date.now(),
|
createdAt: Date.now(),
|
||||||
|
updatedAt: Date.now(),
|
||||||
};
|
};
|
||||||
this._updatePlaylistMetadata(playlist);
|
this._updatePlaylistMetadata(playlist);
|
||||||
await this.performTransaction('user_playlists', 'readwrite', (store) => store.put(playlist));
|
await this.performTransaction('user_playlists', 'readwrite', (store) => store.put(playlist));
|
||||||
|
|
@ -352,6 +353,7 @@ export class MusicDatabase {
|
||||||
const minifiedTrack = this._minifyItem('track', track);
|
const minifiedTrack = this._minifyItem('track', track);
|
||||||
if (playlist.tracks.some((t) => t.id === track.id)) return;
|
if (playlist.tracks.some((t) => t.id === track.id)) return;
|
||||||
playlist.tracks.push(minifiedTrack);
|
playlist.tracks.push(minifiedTrack);
|
||||||
|
playlist.updatedAt = Date.now();
|
||||||
this._updatePlaylistMetadata(playlist);
|
this._updatePlaylistMetadata(playlist);
|
||||||
await this.performTransaction('user_playlists', 'readwrite', (store) => store.put(playlist));
|
await this.performTransaction('user_playlists', 'readwrite', (store) => store.put(playlist));
|
||||||
return playlist;
|
return playlist;
|
||||||
|
|
@ -362,6 +364,7 @@ export class MusicDatabase {
|
||||||
if (!playlist) throw new Error('Playlist not found');
|
if (!playlist) throw new Error('Playlist not found');
|
||||||
playlist.tracks = playlist.tracks || [];
|
playlist.tracks = playlist.tracks || [];
|
||||||
playlist.tracks = playlist.tracks.filter((t) => t.id !== trackId);
|
playlist.tracks = playlist.tracks.filter((t) => t.id !== trackId);
|
||||||
|
playlist.updatedAt = Date.now();
|
||||||
this._updatePlaylistMetadata(playlist);
|
this._updatePlaylistMetadata(playlist);
|
||||||
await this.performTransaction('user_playlists', 'readwrite', (store) => store.put(playlist));
|
await this.performTransaction('user_playlists', 'readwrite', (store) => store.put(playlist));
|
||||||
return playlist;
|
return playlist;
|
||||||
|
|
@ -375,7 +378,7 @@ export class MusicDatabase {
|
||||||
return await this.performTransaction('user_playlists', 'readonly', (store) => store.get(playlistId));
|
return await this.performTransaction('user_playlists', 'readonly', (store) => store.get(playlistId));
|
||||||
}
|
}
|
||||||
|
|
||||||
async getPlaylists() {
|
async getPlaylists(includeTracks = false) {
|
||||||
const db = await this.open();
|
const db = await this.open();
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const transaction = db.transaction('user_playlists', 'readwrite'); // Changed to readwrite for lazy migration
|
const transaction = db.transaction('user_playlists', 'readwrite'); // Changed to readwrite for lazy migration
|
||||||
|
|
@ -408,6 +411,10 @@ export class MusicDatabase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (includeTracks) {
|
||||||
|
return playlist;
|
||||||
|
}
|
||||||
|
|
||||||
// Return lightweight copy without tracks
|
// Return lightweight copy without tracks
|
||||||
// eslint-disable-next-line no-unused-vars
|
// eslint-disable-next-line no-unused-vars
|
||||||
const { tracks, ...minified } = playlist;
|
const { tracks, ...minified } = playlist;
|
||||||
|
|
@ -423,6 +430,7 @@ export class MusicDatabase {
|
||||||
const playlist = await this.performTransaction('user_playlists', 'readonly', (store) => store.get(playlistId));
|
const playlist = await this.performTransaction('user_playlists', 'readonly', (store) => store.get(playlistId));
|
||||||
if (!playlist) throw new Error('Playlist not found');
|
if (!playlist) throw new Error('Playlist not found');
|
||||||
playlist.name = newName;
|
playlist.name = newName;
|
||||||
|
playlist.updatedAt = Date.now();
|
||||||
await this.performTransaction('user_playlists', 'readwrite', (store) => store.put(playlist));
|
await this.performTransaction('user_playlists', 'readwrite', (store) => store.put(playlist));
|
||||||
return playlist;
|
return playlist;
|
||||||
}
|
}
|
||||||
|
|
@ -441,6 +449,7 @@ export class MusicDatabase {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
playlist.tracks = tracks;
|
playlist.tracks = tracks;
|
||||||
|
playlist.updatedAt = Date.now();
|
||||||
this._updatePlaylistMetadata(playlist);
|
this._updatePlaylistMetadata(playlist);
|
||||||
const putRequest = store.put(playlist);
|
const putRequest = store.put(playlist);
|
||||||
putRequest.onsuccess = () => {
|
putRequest.onsuccess = () => {
|
||||||
|
|
|
||||||
|
|
@ -659,7 +659,7 @@ export async function handleTrackAction(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (action === 'add-to-playlist') {
|
} else if (action === 'add-to-playlist') {
|
||||||
const playlists = await db.getPlaylists();
|
const playlists = await db.getPlaylists(true);
|
||||||
if (playlists.length === 0) {
|
if (playlists.length === 0) {
|
||||||
showNotification('No playlists yet. Create one first.');
|
showNotification('No playlists yet. Create one first.');
|
||||||
return;
|
return;
|
||||||
|
|
@ -675,7 +675,7 @@ export async function handleTrackAction(
|
||||||
const playlistsWithTrack = new Set();
|
const playlistsWithTrack = new Set();
|
||||||
|
|
||||||
for (const playlist of playlists) {
|
for (const playlist of playlists) {
|
||||||
if (playlist.tracks && playlist.tracks.some((track) => track.id === trackId)) {
|
if (playlist.tracks && playlist.tracks.some((track) => track.id == trackId)) {
|
||||||
playlistsWithTrack.add(playlist.id);
|
playlistsWithTrack.add(playlist.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,9 @@ import {
|
||||||
child,
|
child,
|
||||||
remove,
|
remove,
|
||||||
runTransaction,
|
runTransaction,
|
||||||
|
onChildAdded,
|
||||||
|
onChildChanged,
|
||||||
|
onChildRemoved,
|
||||||
} from 'https://www.gstatic.com/firebasejs/10.7.1/firebase-database.js';
|
} from 'https://www.gstatic.com/firebasejs/10.7.1/firebase-database.js';
|
||||||
import { db } from '../db.js';
|
import { db } from '../db.js';
|
||||||
|
|
||||||
|
|
@ -19,6 +22,7 @@ export class SyncManager {
|
||||||
this.userRef = null;
|
this.userRef = null;
|
||||||
this.unsubscribeFunctions = [];
|
this.unsubscribeFunctions = [];
|
||||||
this.isSyncing = false;
|
this.isSyncing = false;
|
||||||
|
this.listenersSetup = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
initialize(user) {
|
initialize(user) {
|
||||||
|
|
@ -38,6 +42,7 @@ export class SyncManager {
|
||||||
}
|
}
|
||||||
this.user = null;
|
this.user = null;
|
||||||
this.userRef = null;
|
this.userRef = null;
|
||||||
|
this.listenersSetup = false;
|
||||||
console.log('SyncManager disconnected');
|
console.log('SyncManager disconnected');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -83,12 +88,10 @@ export class SyncManager {
|
||||||
await db.importData(importData, true);
|
await db.importData(importData, true);
|
||||||
|
|
||||||
console.log('Initial sync complete.');
|
console.log('Initial sync complete.');
|
||||||
|
|
||||||
// 6. Setup Listeners for future changes
|
|
||||||
this.setupListeners();
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Initial sync failed:', error);
|
console.error('Initial sync failed:', error);
|
||||||
} finally {
|
} finally {
|
||||||
|
this.setupListeners();
|
||||||
this.isSyncing = false;
|
this.isSyncing = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -110,13 +113,48 @@ export class SyncManager {
|
||||||
|
|
||||||
// Add/Overwrite with cloud items (Union Strategy)
|
// Add/Overwrite with cloud items (Union Strategy)
|
||||||
if (cloudItems) {
|
if (cloudItems) {
|
||||||
|
const processItem = (item, key) => {
|
||||||
|
if (!item || typeof item !== 'object') return;
|
||||||
|
|
||||||
|
if (item.tracks && typeof item.tracks === 'object' && !Array.isArray(item.tracks)) {
|
||||||
|
item.tracks = Object.values(item.tracks);
|
||||||
|
}
|
||||||
|
|
||||||
|
const id = item[idKey] || key;
|
||||||
|
const localItem = map.get(id);
|
||||||
|
|
||||||
|
if (localItem) {
|
||||||
|
const localTime = localItem.updatedAt || 0;
|
||||||
|
const cloudTime = item.updatedAt || 0;
|
||||||
|
|
||||||
|
|
||||||
|
if (cloudTime > localTime) {
|
||||||
|
const localTracks = Array.isArray(localItem.tracks) ? localItem.tracks.length : 0;
|
||||||
|
const cloudTracks = Array.isArray(item.tracks) ? item.tracks.length : 0;
|
||||||
|
|
||||||
|
if (localTracks > 0 && cloudTracks === 0) {
|
||||||
|
} else {
|
||||||
|
map.set(id, item);
|
||||||
|
}
|
||||||
|
} else if (cloudTime === localTime) {
|
||||||
|
const localTracks = Array.isArray(localItem.tracks) ? localItem.tracks.length : 0;
|
||||||
|
const cloudTracks = Array.isArray(item.tracks) ? item.tracks.length : 0;
|
||||||
|
if (cloudTracks >= localTracks) {
|
||||||
|
map.set(id, item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
map.set(id, item);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
if (Array.isArray(cloudItems)) {
|
if (Array.isArray(cloudItems)) {
|
||||||
cloudItems.forEach((item) => map.set(item[idKey], item));
|
cloudItems.forEach((item) => processItem(item));
|
||||||
} else {
|
} else {
|
||||||
Object.keys(cloudItems).forEach((key) => {
|
Object.keys(cloudItems).forEach((key) => {
|
||||||
const val = cloudItems[key];
|
const val = cloudItems[key];
|
||||||
if (typeof val === 'object') {
|
if (typeof val === 'object') {
|
||||||
map.set(val[idKey] || key, val);
|
processItem(val, key);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -162,6 +200,9 @@ export class SyncManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
setupListeners() {
|
setupListeners() {
|
||||||
|
if (!this.userRef || this.listenersSetup) return;
|
||||||
|
this.listenersSetup = true;
|
||||||
|
|
||||||
// Listen for changes in library
|
// Listen for changes in library
|
||||||
const libraryRef = child(this.userRef, 'library');
|
const libraryRef = child(this.userRef, 'library');
|
||||||
|
|
||||||
|
|
@ -208,22 +249,42 @@ export class SyncManager {
|
||||||
// Listen for changes in user playlists
|
// Listen for changes in user playlists
|
||||||
const userPlaylistsRef = child(this.userRef, 'user_playlists');
|
const userPlaylistsRef = child(this.userRef, 'user_playlists');
|
||||||
|
|
||||||
const unsubUserPlaylists = onValue(userPlaylistsRef, (snapshot) => {
|
const handlePlaylistUpdate = (snapshot) => {
|
||||||
if (this.isSyncing) return;
|
if (this.isSyncing) return;
|
||||||
|
|
||||||
const val = snapshot.val();
|
const val = snapshot.val();
|
||||||
if (val) {
|
if (val) {
|
||||||
|
if (val.tracks && typeof val.tracks === 'object' && !Array.isArray(val.tracks)) {
|
||||||
|
val.tracks = Object.values(val.tracks);
|
||||||
|
}
|
||||||
|
|
||||||
const importData = {
|
const importData = {
|
||||||
user_playlists: Object.values(val),
|
user_playlists: [val],
|
||||||
};
|
};
|
||||||
db.importData(importData, true).then(() => {
|
db.importData(importData, false).then(() => {
|
||||||
// Notify UI to refresh library
|
// Notify UI to refresh library
|
||||||
window.dispatchEvent(new Event('library-changed'));
|
window.dispatchEvent(new Event('library-changed'));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const unsubChildAdded = onChildAdded(userPlaylistsRef, handlePlaylistUpdate);
|
||||||
|
const unsubChildChanged = onChildChanged(userPlaylistsRef, handlePlaylistUpdate);
|
||||||
|
const unsubChildRemoved = onChildRemoved(userPlaylistsRef, (snapshot) => {
|
||||||
|
if (this.isSyncing) return;
|
||||||
|
const key = snapshot.key;
|
||||||
|
if (key) {
|
||||||
|
db.deletePlaylist(key).then(() => {
|
||||||
|
window.dispatchEvent(new Event('library-changed'));
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.unsubscribeFunctions.push(() => off(userPlaylistsRef, 'value', unsubUserPlaylists));
|
this.unsubscribeFunctions.push(() => {
|
||||||
|
off(userPlaylistsRef, 'child_added', unsubChildAdded);
|
||||||
|
off(userPlaylistsRef, 'child_changed', unsubChildChanged);
|
||||||
|
off(userPlaylistsRef, 'child_removed', unsubChildRemoved);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Public API for Broadcasters ---
|
// --- Public API for Broadcasters ---
|
||||||
|
|
@ -258,7 +319,7 @@ export class SyncManager {
|
||||||
...minified,
|
...minified,
|
||||||
addedAt: item.addedAt || minified.addedAt || Date.now(),
|
addedAt: item.addedAt || minified.addedAt || Date.now(),
|
||||||
};
|
};
|
||||||
await set(itemRef, entry);
|
await set(itemRef, this.sanitizeForFirebase(entry));
|
||||||
} else {
|
} else {
|
||||||
await remove(itemRef);
|
await remove(itemRef);
|
||||||
}
|
}
|
||||||
|
|
@ -269,7 +330,7 @@ export class SyncManager {
|
||||||
|
|
||||||
const itemRef = child(this.userRef, `history/recentTracks/${track.timestamp}`);
|
const itemRef = child(this.userRef, `history/recentTracks/${track.timestamp}`);
|
||||||
try {
|
try {
|
||||||
await set(itemRef, track);
|
await set(itemRef, this.sanitizeForFirebase(track));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to sync history item:', error);
|
console.error('Failed to sync history item:', error);
|
||||||
}
|
}
|
||||||
|
|
@ -283,7 +344,11 @@ export class SyncManager {
|
||||||
const itemRef = child(this.userRef, path);
|
const itemRef = child(this.userRef, path);
|
||||||
|
|
||||||
if (action === 'create' || action === 'update') {
|
if (action === 'create' || action === 'update') {
|
||||||
await set(itemRef, playlist);
|
const dataToSync = {
|
||||||
|
...playlist,
|
||||||
|
updatedAt: Date.now(),
|
||||||
|
};
|
||||||
|
await set(itemRef, this.sanitizeForFirebase(dataToSync));
|
||||||
// Ensure it's not in deleted_playlists (just in case)
|
// Ensure it's not in deleted_playlists (just in case)
|
||||||
const deletedRef = child(this.userRef, `deleted_playlists/${id}`);
|
const deletedRef = child(this.userRef, `deleted_playlists/${id}`);
|
||||||
await remove(deletedRef);
|
await remove(deletedRef);
|
||||||
|
|
@ -323,7 +388,7 @@ export class SyncManager {
|
||||||
|
|
||||||
// Use a global 'public_playlists' node
|
// Use a global 'public_playlists' node
|
||||||
const publicRef = ref(database, `public_playlists/${playlistId}`);
|
const publicRef = ref(database, `public_playlists/${playlistId}`);
|
||||||
await set(publicRef, publicData);
|
await set(publicRef, this.sanitizeForFirebase(publicData));
|
||||||
}
|
}
|
||||||
|
|
||||||
async unpublishPlaylist(playlistId) {
|
async unpublishPlaylist(playlistId) {
|
||||||
|
|
@ -352,6 +417,25 @@ export class SyncManager {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sanitizeForFirebase(obj) {
|
||||||
|
if (obj === undefined) return null;
|
||||||
|
if (obj === null) return null;
|
||||||
|
if (typeof obj !== 'object') return obj;
|
||||||
|
if (Array.isArray(obj)) {
|
||||||
|
return obj.map((v) => this.sanitizeForFirebase(v));
|
||||||
|
}
|
||||||
|
const newObj = {};
|
||||||
|
for (const key in obj) {
|
||||||
|
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
||||||
|
const val = this.sanitizeForFirebase(obj[key]);
|
||||||
|
if (val !== undefined) {
|
||||||
|
newObj[key] = val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return newObj;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const syncManager = new SyncManager();
|
export const syncManager = new SyncManager();
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue