add push settings
This commit is contained in:
123
apps/frontend/components/id/firebase-settings-section.tsx
Normal file
123
apps/frontend/components/id/firebase-settings-section.tsx
Normal file
@@ -0,0 +1,123 @@
|
||||
'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>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user