148 lines
4.3 KiB
TypeScript
148 lines
4.3 KiB
TypeScript
/**
|
||
* Генератор временных ID для offline заметок
|
||
*/
|
||
export function generateTempId(): string {
|
||
return `temp-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
||
}
|
||
|
||
/**
|
||
* Проверка, является ли ID временным
|
||
*/
|
||
export function isTempId(id: number | string): boolean {
|
||
return typeof id === 'string' && id.startsWith('temp-');
|
||
}
|
||
|
||
/**
|
||
* Ожидание доступности IndexedDB
|
||
*/
|
||
export function waitForIndexedDB(): Promise<IDBDatabase> {
|
||
return new Promise((resolve, reject) => {
|
||
const request = indexedDB.open('test-db', 1);
|
||
|
||
request.onerror = () => {
|
||
reject(request.error);
|
||
};
|
||
|
||
request.onsuccess = () => {
|
||
const db = request.result;
|
||
db.close();
|
||
indexedDB.deleteDatabase('test-db');
|
||
resolve(request.result);
|
||
};
|
||
|
||
request.onupgradeneeded = (event) => {
|
||
const db = (event.target as IDBOpenDBRequest).result;
|
||
db.createObjectStore('test');
|
||
};
|
||
});
|
||
}
|
||
|
||
/**
|
||
* Проверка состояния сети (более надежный метод)
|
||
*/
|
||
export async function checkNetworkStatus(): Promise<boolean> {
|
||
// Простая проверка navigator.onLine
|
||
if (!navigator.onLine) {
|
||
return false;
|
||
}
|
||
|
||
// Дополнительная проверка через fetch с коротким таймаутом
|
||
try {
|
||
const controller = new AbortController();
|
||
const timeoutId = setTimeout(() => controller.abort(), 2000);
|
||
|
||
// Используем /auth/status так как он всегда доступен при наличии сети
|
||
const response = await fetch('/api/auth/status', {
|
||
method: 'GET',
|
||
signal: controller.signal,
|
||
cache: 'no-cache',
|
||
credentials: 'include', // Важно для cookie-based auth
|
||
});
|
||
|
||
clearTimeout(timeoutId);
|
||
return response.ok;
|
||
} catch (error) {
|
||
// Если запрос не удался, но navigator.onLine = true, считаем что онлайн
|
||
// (возможно, просто таймаут или другая проблема)
|
||
return navigator.onLine;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Проверка, доступна ли БД на клиенте
|
||
*/
|
||
export function isDatabaseAvailable(): boolean {
|
||
return typeof indexedDB !== 'undefined';
|
||
}
|
||
|
||
/**
|
||
* Сохранение blob в base64
|
||
*/
|
||
export function fileToBase64(file: File): Promise<string> {
|
||
return new Promise((resolve, reject) => {
|
||
const reader = new FileReader();
|
||
reader.onload = () => {
|
||
if (typeof reader.result === 'string') {
|
||
resolve(reader.result);
|
||
} else {
|
||
reject(new Error('Failed to convert file to base64'));
|
||
}
|
||
};
|
||
reader.onerror = reject;
|
||
reader.readAsDataURL(file);
|
||
});
|
||
}
|
||
|
||
/**
|
||
* Конвертация base64 обратно в Blob
|
||
*/
|
||
export function base64ToBlob(base64: string, mimeType: string): Blob {
|
||
const byteCharacters = atob(base64.split(',')[1] || base64);
|
||
const byteNumbers = new Array(byteCharacters.length);
|
||
for (let i = 0; i < byteCharacters.length; i++) {
|
||
byteNumbers[i] = byteCharacters.charCodeAt(i);
|
||
}
|
||
const byteArray = new Uint8Array(byteNumbers);
|
||
return new Blob([byteArray], { type: mimeType });
|
||
}
|
||
|
||
/**
|
||
* Получение размера base64 строки в байтах
|
||
*/
|
||
export function getBase64Size(base64: string): number {
|
||
const base64String = base64.split(',')[1] || base64;
|
||
return Math.ceil((base64String.length * 3) / 4);
|
||
}
|
||
|
||
/**
|
||
* Создание Listener для событий сети
|
||
*/
|
||
export class NetworkListener {
|
||
private onlineHandler: ((event: Event) => void) | null = null;
|
||
private offlineHandler: ((event: Event) => void) | null = null;
|
||
|
||
onOnline(callback: (event: Event) => void): void {
|
||
this.onlineHandler = callback;
|
||
window.addEventListener('online', callback);
|
||
}
|
||
|
||
onOffline(callback: (event: Event) => void): void {
|
||
this.offlineHandler = callback;
|
||
window.addEventListener('offline', callback);
|
||
}
|
||
|
||
removeListeners(): void {
|
||
if (this.onlineHandler) {
|
||
window.removeEventListener('online', this.onlineHandler);
|
||
this.onlineHandler = null;
|
||
}
|
||
if (this.offlineHandler) {
|
||
window.removeEventListener('offline', this.offlineHandler);
|
||
this.offlineHandler = null;
|
||
}
|
||
}
|
||
}
|
||
|
||
export const networkListener = new NetworkListener();
|
||
|