v0.12.9 bug fixes (FCM and list ordering)
This commit is contained in:
@@ -18,7 +18,7 @@ function TeamManagementTab() {
|
||||
const [saving, setSaving] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
api.getUserGroups().then(({ groups }) => setUserGroups(groups || [])).catch(() => {});
|
||||
api.getUserGroups().then(({ groups }) => setUserGroups([...(groups||[])].sort((a, b) => a.name.localeCompare(b.name)))).catch(() => {});
|
||||
api.getSettings().then(({ settings }) => {
|
||||
// Read from unified key, fall back to legacy key
|
||||
setToolManagers(JSON.parse(settings.team_tool_managers || settings.team_group_managers || '[]'));
|
||||
@@ -313,80 +313,6 @@ function PushDebugTab() {
|
||||
);
|
||||
}
|
||||
|
||||
// ── Web Push Tab ──────────────────────────────────────────────────────────────
|
||||
function WebPushTab() {
|
||||
const toast = useToast();
|
||||
const [vapidPublic, setVapidPublic] = useState('');
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [generating, setGenerating] = useState(false);
|
||||
const [showRegenWarning, setShowRegenWarning] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
api.getSettings().then(({ settings }) => {
|
||||
setVapidPublic(settings.vapid_public || '');
|
||||
setLoading(false);
|
||||
}).catch(() => setLoading(false));
|
||||
}, []);
|
||||
|
||||
const doGenerate = async () => {
|
||||
setGenerating(true);
|
||||
setShowRegenWarning(false);
|
||||
try {
|
||||
const { publicKey } = await api.generateVapidKeys();
|
||||
setVapidPublic(publicKey);
|
||||
toast('VAPID keys generated. Push notifications are now active.', 'success');
|
||||
} catch (e) {
|
||||
toast(e.message || 'Failed to generate keys', 'error');
|
||||
} finally { setGenerating(false); }
|
||||
};
|
||||
|
||||
if (loading) return <p style={{ fontSize: 13, color: 'var(--text-secondary)' }}>Loading…</p>;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="settings-section-label" style={{ marginBottom: 12 }}>Web Push Notifications (VAPID)</div>
|
||||
|
||||
{vapidPublic ? (
|
||||
<div style={{ marginBottom: 16 }}>
|
||||
<div style={{ background: 'var(--surface-variant)', border: '1px solid var(--border)', borderRadius: 'var(--radius)', padding: '10px 12px', marginBottom: 10 }}>
|
||||
<div style={{ fontSize: 11, color: 'var(--text-tertiary)', marginBottom: 4, textTransform: 'uppercase', letterSpacing: '0.5px' }}>Public Key</div>
|
||||
<code style={{ fontSize: 11, color: 'var(--text-primary)', wordBreak: 'break-all', lineHeight: 1.5, display: 'block' }}>{vapidPublic}</code>
|
||||
</div>
|
||||
<span style={{ fontSize: 13, color: 'var(--success)', display: 'flex', alignItems: 'center', gap: 5 }}>
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5"><polyline points="20 6 9 17 4 12"/></svg>
|
||||
Push notifications active
|
||||
</span>
|
||||
</div>
|
||||
) : (
|
||||
<p style={{ fontSize: 13, color: 'var(--text-secondary)', marginBottom: 12 }}>
|
||||
No VAPID keys found. Generate keys to enable Web Push notifications.
|
||||
</p>
|
||||
)}
|
||||
|
||||
{showRegenWarning && (
|
||||
<div style={{ background: '#fce8e6', border: '1px solid #f5c6c2', borderRadius: 'var(--radius)', padding: '14px 16px', marginBottom: 16 }}>
|
||||
<p style={{ fontSize: 13, fontWeight: 600, color: 'var(--error)', marginBottom: 8 }}>⚠️ Regenerate VAPID keys?</p>
|
||||
<p style={{ fontSize: 13, color: '#5c2c28', marginBottom: 12, lineHeight: 1.5 }}>
|
||||
Generating new keys will <strong>invalidate all existing push subscriptions</strong>. Users will need to re-enable notifications.
|
||||
</p>
|
||||
<div style={{ display: 'flex', gap: 8 }}>
|
||||
<button className="btn btn-sm" style={{ background: 'var(--error)', color: 'white' }} onClick={doGenerate} disabled={generating}>{generating ? 'Generating…' : 'Yes, regenerate keys'}</button>
|
||||
<button className="btn btn-secondary btn-sm" onClick={() => setShowRegenWarning(false)}>Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{!showRegenWarning && (
|
||||
<button className="btn btn-primary btn-sm" onClick={() => vapidPublic ? setShowRegenWarning(true) : doGenerate()} disabled={generating}>
|
||||
{generating ? 'Generating…' : vapidPublic ? 'Regenerate Keys' : 'Generate Keys'}
|
||||
</button>
|
||||
)}
|
||||
<p style={{ fontSize: 12, color: 'var(--text-tertiary)', marginTop: 12, lineHeight: 1.5 }}>
|
||||
Requires HTTPS. On iOS, the app must be installed to the home screen first.
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// ── Main modal ────────────────────────────────────────────────────────────────
|
||||
export default function SettingsModal({ onClose, onFeaturesChanged }) {
|
||||
const [tab, setTab] = useState('registration');
|
||||
@@ -406,7 +332,6 @@ export default function SettingsModal({ onClose, onFeaturesChanged }) {
|
||||
const tabs = [
|
||||
isTeam && { id: 'team', label: 'Team Management' },
|
||||
{ id: 'registration', label: 'Registration' },
|
||||
{ id: 'webpush', label: 'Web Push' },
|
||||
{ id: 'pushdebug', label: 'Push Debug' },
|
||||
].filter(Boolean);
|
||||
|
||||
@@ -431,7 +356,6 @@ export default function SettingsModal({ onClose, onFeaturesChanged }) {
|
||||
|
||||
{tab === 'team' && <TeamManagementTab />}
|
||||
{tab === 'registration' && <RegistrationTab onFeaturesChanged={onFeaturesChanged} />}
|
||||
{tab === 'webpush' && <WebPushTab />}
|
||||
{tab === 'pushdebug' && <PushDebugTab />}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user