import { fetchWrapper } from '@KTXC/utils/helpers/fetch-wrapper'; /** * User Service * Provides methods for managing user profile and settings with batched updates */ // Pending updates for profile and settings let pendingProfileUpdates: Record = {}; let pendingSettingsUpdates: Record = {}; let profileUpdateTimer: ReturnType | null = null; let settingsUpdateTimer: ReturnType | null = null; // Default debounce delay in milliseconds const DEBOUNCE_DELAY = 500; export const userService = { /** * Update profile field(s) with debouncing * Multiple calls within the debounce window will be batched into a single request */ updateProfile(fields: Record): Promise { return new Promise((resolve, reject) => { // Merge new fields with pending updates Object.assign(pendingProfileUpdates, fields); // Clear existing timer if (profileUpdateTimer) { clearTimeout(profileUpdateTimer); } // Set new timer to batch updates profileUpdateTimer = setTimeout(async () => { const updates = { ...pendingProfileUpdates }; pendingProfileUpdates = {}; profileUpdateTimer = null; try { await fetchWrapper.put('/user/profile', { data: updates }); resolve(); } catch (error) { reject(error); } }, DEBOUNCE_DELAY); }); }, /** * Update profile field(s) immediately without debouncing */ async updateProfileImmediate(fields: Record): Promise { // Cancel pending debounced update if (profileUpdateTimer) { clearTimeout(profileUpdateTimer); profileUpdateTimer = null; } // Merge with pending updates and send immediately const updates = { ...pendingProfileUpdates, ...fields }; pendingProfileUpdates = {}; return fetchWrapper.put('/user/profile', { data: updates }); }, /** * Flush any pending profile updates immediately */ async flushProfileUpdates(): Promise { if (profileUpdateTimer) { clearTimeout(profileUpdateTimer); profileUpdateTimer = null; } if (Object.keys(pendingProfileUpdates).length > 0) { const updates = { ...pendingProfileUpdates }; pendingProfileUpdates = {}; return fetchWrapper.put('/user/profile', { data: updates }); } }, /** * Update setting(s) with debouncing * Multiple calls within the debounce window will be batched into a single request */ updateSettings(settings: Record): Promise { return new Promise((resolve, reject) => { // Merge new settings with pending updates Object.assign(pendingSettingsUpdates, settings); // Clear existing timer if (settingsUpdateTimer) { clearTimeout(settingsUpdateTimer); } // Set new timer to batch updates settingsUpdateTimer = setTimeout(async () => { const updates = { ...pendingSettingsUpdates }; pendingSettingsUpdates = {}; settingsUpdateTimer = null; try { await fetchWrapper.put('/user/settings', { data: updates }); resolve(); } catch (error) { reject(error); } }, DEBOUNCE_DELAY); }); }, /** * Update setting(s) immediately without debouncing */ async updateSettingsImmediate(settings: Record): Promise { // Cancel pending debounced update if (settingsUpdateTimer) { clearTimeout(settingsUpdateTimer); settingsUpdateTimer = null; } // Merge with pending updates and send immediately const updates = { ...pendingSettingsUpdates, ...settings }; pendingSettingsUpdates = {}; return fetchWrapper.put('/user/settings', { data: updates }); }, /** * Flush any pending settings updates immediately */ async flushSettingsUpdates(): Promise { if (settingsUpdateTimer) { clearTimeout(settingsUpdateTimer); settingsUpdateTimer = null; } if (Object.keys(pendingSettingsUpdates).length > 0) { const updates = { ...pendingSettingsUpdates }; pendingSettingsUpdates = {}; return fetchWrapper.put('/user/settings', { data: updates }); } }, /** * Flush all pending updates (profile and settings) */ async flushAll(): Promise { await Promise.all([ this.flushProfileUpdates(), this.flushSettingsUpdates(), ]); }, };