v0.12.26 iOS notification bug fix
This commit is contained in:
@@ -63,15 +63,19 @@ const isMobileDevice = isIOS || isAndroid;
|
||||
|
||||
function TestNotificationsModal({ onClose }) {
|
||||
const toast = useToast();
|
||||
const { user } = useAuth();
|
||||
const isAdmin = user?.role === 'admin';
|
||||
const [debugData, setDebugData] = useState(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [testing, setTesting] = useState(false);
|
||||
|
||||
const permission = (typeof Notification !== 'undefined') ? Notification.permission : 'unsupported';
|
||||
const [permission, setPermission] = useState(
|
||||
(typeof Notification !== 'undefined') ? Notification.permission : 'unsupported'
|
||||
);
|
||||
const [cachedToken, setCachedToken] = useState(localStorage.getItem('rc_fcm_token'));
|
||||
const [lastError, setLastError] = useState(localStorage.getItem('rc_fcm_error'));
|
||||
|
||||
const load = async () => {
|
||||
if (!isAdmin) return; // debug endpoint is admin-only
|
||||
setLoading(true);
|
||||
try {
|
||||
const data = await api.pushDebug();
|
||||
@@ -83,7 +87,22 @@ function TestNotificationsModal({ onClose }) {
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => { load(); }, []);
|
||||
useEffect(() => { load(); }, []); // eslint-disable-line react-hooks/exhaustive-deps
|
||||
|
||||
const handleGrantPermission = async () => {
|
||||
if (typeof Notification === 'undefined') {
|
||||
toast('Notifications not supported on this device/browser', 'error');
|
||||
return;
|
||||
}
|
||||
const result = await Notification.requestPermission();
|
||||
setPermission(result);
|
||||
if (result === 'granted') {
|
||||
window.dispatchEvent(new CustomEvent('rosterchirp:push-init'));
|
||||
toast('Permission granted — registering…', 'success');
|
||||
} else {
|
||||
toast('Permission denied', 'error');
|
||||
}
|
||||
};
|
||||
|
||||
const doTest = async (mode) => {
|
||||
setTesting(true);
|
||||
@@ -112,6 +131,7 @@ function TestNotificationsModal({ onClose }) {
|
||||
const reregister = () => {
|
||||
localStorage.removeItem('rc_fcm_token');
|
||||
localStorage.removeItem('rc_fcm_error');
|
||||
localStorage.removeItem('rc_webpush_endpoint'); // clear iOS webpush cache too
|
||||
setCachedToken(null);
|
||||
setLastError(null);
|
||||
window.dispatchEvent(new CustomEvent('rosterchirp:push-init'));
|
||||
@@ -147,6 +167,11 @@ function TestNotificationsModal({ onClose }) {
|
||||
{!isIOS && debugData && <DebugRow label="Firebase Admin" value={debugData.firebaseAdminReady ? 'Ready' : 'Not ready'} ok={debugData.firebaseAdminReady} bad={!debugData.firebaseAdminReady} />}
|
||||
{lastError && <DebugRow label="Last reg. error" value={lastError} bad={true} />}
|
||||
</div>
|
||||
{permission === 'default' && (
|
||||
<button className="btn btn-sm btn-primary" onClick={handleGrantPermission} style={{ marginBottom: 8 }}>
|
||||
Grant Permission
|
||||
</button>
|
||||
)}
|
||||
<div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
|
||||
<button className="btn btn-sm btn-primary" onClick={reregister}>Re-register</button>
|
||||
{!isIOS && <button className="btn btn-sm btn-secondary" onClick={clearToken}>Clear token</button>}
|
||||
@@ -325,7 +350,8 @@ export default function UserFooter({ onProfile, onHelp, onAbout, mobileCompact=f
|
||||
|
||||
{showMenu && (
|
||||
<div ref={menuRef} className="footer-menu">
|
||||
<div style={{ display: 'flex', justifyContent: 'flex-end', marginBottom: 4 }}>
|
||||
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 4 }}>
|
||||
<span style={{ fontWeight: 700, fontSize: 14, color: 'var(--text-primary)', paddingLeft: 4 }}>User Menu</span>
|
||||
<button onClick={() => setShowMenu(false)} style={{ background: 'none', border: 'none', cursor: 'pointer', padding: '2px 4px', color: 'var(--text-tertiary)', lineHeight: 1 }} aria-label="Close menu">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
|
||||
</button>
|
||||
|
||||
@@ -262,7 +262,15 @@ export default function Chat() {
|
||||
const handleVisibility = () => {
|
||||
if (document.visibilityState === 'visible') registerPush();
|
||||
};
|
||||
const handlePushInit = () => registerPush();
|
||||
// When the user explicitly requests push (via the Notifications toggle or
|
||||
// re-register button), ask for permission if it hasn't been granted yet.
|
||||
const handlePushInit = async () => {
|
||||
if (typeof Notification !== 'undefined' && Notification.permission === 'default') {
|
||||
const result = await Notification.requestPermission();
|
||||
if (result !== 'granted') return;
|
||||
}
|
||||
registerPush();
|
||||
};
|
||||
document.addEventListener('visibilitychange', handleVisibility);
|
||||
window.addEventListener('rosterchirp:push-init', handlePushInit);
|
||||
return () => {
|
||||
|
||||
Reference in New Issue
Block a user