- number-поля теперь рендерятся как text + inputMode=numeric, чтобы браузер не округлял значения через input type=number - пробелы при вставке в number-поля удаляются - бэкенд нормализует значения number-полей в строку перед сохранением - добавлен хелпер normalizeFieldValueForStorage Closes: искажение расчётного счёта и других длинных числовых полей
77 lines
2.2 KiB
TypeScript
77 lines
2.2 KiB
TypeScript
import { useEffect, useRef } from 'react';
|
|
|
|
interface WebNotificationOptions {
|
|
title: string;
|
|
body: string;
|
|
icon?: string;
|
|
tag?: string;
|
|
}
|
|
|
|
export const useWebNotifications = () => {
|
|
const permissionRef = useRef<NotificationPermission>('default');
|
|
const isEnabledRef = useRef(false);
|
|
|
|
useEffect(() => {
|
|
// Проверяем поддержку браузера
|
|
if ('Notification' in window) {
|
|
permissionRef.current = Notification.permission;
|
|
isEnabledRef.current = Notification.permission === 'granted';
|
|
}
|
|
}, []);
|
|
|
|
const requestPermission = async (): Promise<boolean> => {
|
|
if (!('Notification' in window)) {
|
|
console.warn('Браузер не поддерживает Web Notifications API');
|
|
return false;
|
|
}
|
|
|
|
if (permissionRef.current === 'granted') {
|
|
return true;
|
|
}
|
|
|
|
try {
|
|
const permission = await Notification.requestPermission();
|
|
permissionRef.current = permission;
|
|
isEnabledRef.current = permission === 'granted';
|
|
return permission === 'granted';
|
|
} catch (error) {
|
|
console.error('Ошибка при запросе разрешения на уведомления:', error);
|
|
return false;
|
|
}
|
|
};
|
|
|
|
const showNotification = async (options: WebNotificationOptions): Promise<boolean> => {
|
|
if (!isEnabledRef.current) {
|
|
console.warn('Уведомления отключены или не поддерживаются');
|
|
return false;
|
|
}
|
|
|
|
try {
|
|
const notification = new Notification(options.title, {
|
|
body: options.body,
|
|
icon: options.icon || '/favicon.ico',
|
|
tag: options.tag,
|
|
silent: false,
|
|
requireInteraction: false
|
|
});
|
|
|
|
// Автоматически закрываем уведомление через 5 секунд
|
|
setTimeout(() => {
|
|
notification.close();
|
|
}, 5000);
|
|
|
|
return true;
|
|
} catch (error) {
|
|
console.error('Ошибка при показе уведомления:', error);
|
|
return false;
|
|
}
|
|
};
|
|
|
|
return {
|
|
isSupported: 'Notification' in window,
|
|
permission: permissionRef.current,
|
|
isEnabled: isEnabledRef.current,
|
|
requestPermission,
|
|
showNotification
|
|
};
|
|
}; |