Files
IdP/apps/frontend/components/id/firebase-settings-section.tsx
2026-07-07 13:58:01 +03:00

124 lines
5.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'use client';
import { Bell, Loader2, Save, Send } from 'lucide-react';
import { useMemo, useState } from 'react';
import { Button } from '@/components/ui/button';
import { apiFetch, SystemSetting } from '@/lib/api';
import { FIREBASE_SETTING_KEYS, isSettingVisible } from '@/lib/system-settings-catalog';
import { SettingsFieldRow } from '@/components/id/settings-field-row';
function parseBoolean(value: string) {
return ['true', '1', 'yes'].includes(value.trim().toLowerCase());
}
function getSettingValue(settings: SystemSetting[], key: string) {
return settings.find((item) => item.key === key)?.value ?? '';
}
interface FirebaseSettingsSectionProps {
settings: SystemSetting[];
token: string | null;
savingGroup: string | null;
onUpdateValue: (key: string, value: string) => void;
onSaveGroup: (groupKey: string, groupSettings: SystemSetting[]) => Promise<void>;
showToast: (message: string) => void;
}
export function FirebaseSettingsSection({
settings,
token,
savingGroup,
onUpdateValue,
onSaveGroup,
showToast
}: FirebaseSettingsSectionProps) {
const [testing, setTesting] = useState(false);
const firebaseSettings = useMemo(
() => settings.filter((item) => FIREBASE_SETTING_KEYS.includes(item.key)),
[settings]
);
const visibleSettings = firebaseSettings.filter((setting) => isSettingVisible(setting, settings));
const saving = savingGroup === 'firebase';
const pushEnabled = parseBoolean(getSettingValue(firebaseSettings, 'FIREBASE_PUSH_ENABLED'));
const hasServerCredentials =
Boolean(getSettingValue(firebaseSettings, 'FIREBASE_PROJECT_ID').trim()) &&
Boolean(getSettingValue(firebaseSettings, 'FIREBASE_CLIENT_EMAIL').trim()) &&
Boolean(getSettingValue(firebaseSettings, 'FIREBASE_PRIVATE_KEY').trim());
const hasWebConfig =
Boolean(getSettingValue(firebaseSettings, 'FIREBASE_WEB_API_KEY').trim()) &&
Boolean(getSettingValue(firebaseSettings, 'FIREBASE_WEB_APP_ID').trim()) &&
Boolean(getSettingValue(firebaseSettings, 'FIREBASE_WEB_MESSAGING_SENDER_ID').trim()) &&
Boolean(getSettingValue(firebaseSettings, 'FIREBASE_WEB_VAPID_KEY').trim());
const canTest = pushEnabled && hasServerCredentials && hasWebConfig;
async function sendTestPush() {
if (!token) return;
setTesting(true);
try {
const response = await apiFetch<{ message?: string }>('/admin/settings/firebase/test', { method: 'POST' }, token);
showToast(response.message ?? 'Тестовое push-уведомление отправлено');
} catch (error) {
showToast(error instanceof Error ? error.message : 'Не удалось отправить тестовое push-уведомление');
} finally {
setTesting(false);
}
}
return (
<section className="mb-10">
<div className="mb-4 flex items-center gap-3">
<Bell className="h-6 w-6" />
<div>
<h3 className="text-xl font-medium">Firebase Push</h3>
<p className="mt-1 text-sm text-[#667085]">
Настройте Firebase Cloud Messaging для push-уведомлений в браузере и мобильных клиентах.
</p>
</div>
</div>
<div className="rounded-[24px] bg-[#f4f5f8] p-5">
<div className="mb-4 flex flex-col gap-3 border-b border-[#e0e3ea] pb-4 md:flex-row md:items-start md:justify-between">
<div>
<h4 className="text-lg font-medium">Параметры FCM</h4>
<p className="mt-1 text-sm text-[#667085]">
Сервисный аккаунт для отправки с сервера. Web API Key, App ID, Sender ID и VAPID для клиентского SDK.
</p>
</div>
<Button disabled={saving || visibleSettings.length === 0} onClick={() => void onSaveGroup('firebase', firebaseSettings)}>
{saving ? <Loader2 className="h-4 w-4 animate-spin" /> : <Save className="h-4 w-4" />}
Сохранить блок
</Button>
</div>
<div>
{visibleSettings.map((setting) => (
<SettingsFieldRow
key={setting.key}
setting={setting}
onChange={(value) => onUpdateValue(setting.key, value)}
/>
))}
</div>
</div>
<div className="mt-6 rounded-[24px] border border-[#e4e7ec] bg-white p-5">
<div className="flex items-center gap-2 font-semibold">
<Send className="h-5 w-5" />
Тест push-уведомления
</div>
<p className="mt-2 text-sm text-[#667085]">
{canTest
? 'Отправит тестовое уведомление на ваши зарегистрированные устройства. Сначала откройте IdP в браузере и разрешите уведомления.'
: 'Сохраните блок Firebase с включённым push и заполненными ключами, затем зарегистрируйте устройство в браузере.'}
</p>
<Button className="mt-3" disabled={!canTest || testing} onClick={() => void sendTestPush()}>
{testing ? <Loader2 className="h-4 w-4 animate-spin" /> : <Send className="h-4 w-4" />}
Отправить тест
</Button>
</div>
</section>
);
}