Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 | import { Alert, Button, styled } from "@mui/material";
import { useAuthContext } from "features/auth/AuthProvider";
import { Trans, useTranslation } from "i18n";
import { NOTIFICATIONS } from "i18n/namespaces";
import { usePersistedState } from "platform/usePersistedState";
import React, { useEffect, useState } from "react";
import { theme } from "theme";
import { useIsNativeEmbed } from "../../platform/nativeLink";
import { checkPushEnabled, turnPushNotificationsOn } from "./utils/helpers";
const TIME_BETWEEN_NAGS_MS = 180 * 86400 * 1_000; // 180 days
const Wrapper = styled("div")({
display: "flex",
justifyContent: "space-between",
alignItems: "center",
width: "100%",
});
export function PushNotificationBanner() {
const { t } = useTranslation(NOTIFICATIONS);
const isNativeEmbed = useIsNativeEmbed();
// the epoch value of the last time this banner was dismissed
const [lastDismissedEpoch, setLastDismissedEpoch] = usePersistedState<
number | null
>("notification_banner.dismissed", null);
const [bannerVisible, setBannerVisible] = useState<boolean>(false);
const [shouldPromptAllow, setShouldPromptAllow] = useState<boolean>(false);
const [errorMessage, setErrorMessage] = useState<string | null>(null);
const {
authState: { authenticated },
} = useAuthContext();
useEffect(() => {
const checkPush = async () => {
Iif (!authenticated) return;
// Skip push notification check in native embed (WebView doesn't support it)
Iif (isNativeEmbed) return;
try {
Iif (!(await checkPushEnabled())) {
setBannerVisible(
!lastDismissedEpoch ||
new Date().getTime() - lastDismissedEpoch > TIME_BETWEEN_NAGS_MS,
);
}
} catch (error) {
// Only log errors for web browsers, not mobile WebView
if (isNativeEmbed) {
console.debug(
"Push notifications not available in mobile app:",
error,
);
} else {
console.error("Error checking for push notification state:", error);
}
}
};
checkPush();
}, [authenticated, lastDismissedEpoch, isNativeEmbed]);
const dismiss = () => {
setLastDismissedEpoch(new Date().getTime());
setBannerVisible(false);
};
const turnPushNotificationsOnWrap = async () => {
const result = await turnPushNotificationsOn(setShouldPromptAllow);
if (!result.success) {
setErrorMessage(t(result.errorMessage));
} else {
setBannerVisible(false);
}
};
Iif (!bannerVisible) return null;
Iif (errorMessage) {
return (
<Alert severity="error" onClose={dismiss}>
{errorMessage}
</Alert>
);
}
return shouldPromptAllow ? (
<Alert severity="info" onClose={dismiss}>
{t("notifications:notification_settings.push_notifications.allow_push")}
</Alert>
) : (
<Alert
severity="info"
onClose={dismiss}
sx={{ alignItems: "center", ".MuiAlert-message": { width: "100%" } }}
>
<Wrapper>
<Trans i18nKey="notifications:push_notification_banner.message" />
<Button
variant="outlined"
sx={{ backgroundColor: theme.palette.common.white }}
onClick={turnPushNotificationsOnWrap}
>
{t("notifications:push_notification_banner.confirm")}
</Button>
</Wrapper>
</Alert>
);
}
|