154 lines
4.4 KiB
TypeScript
154 lines
4.4 KiB
TypeScript
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<string, any> = {};
|
|
let pendingSettingsUpdates: Record<string, any> = {};
|
|
let profileUpdateTimer: ReturnType<typeof setTimeout> | null = null;
|
|
let settingsUpdateTimer: ReturnType<typeof setTimeout> | 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<string, any>): Promise<void> {
|
|
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<string, any>): Promise<void> {
|
|
// 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<void> {
|
|
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<string, any>): Promise<void> {
|
|
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<string, any>): Promise<void> {
|
|
// 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<void> {
|
|
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<void> {
|
|
await Promise.all([
|
|
this.flushProfileUpdates(),
|
|
this.flushSettingsUpdates(),
|
|
]);
|
|
},
|
|
};
|