fix desktop notification handling on macos

This commit is contained in:
Mohamed Boudra
2026-03-19 16:43:34 +07:00
parent a952112910
commit efb3df8233
9 changed files with 486 additions and 53 deletions
@@ -10,6 +10,10 @@ export interface DesktopPermissionRowProps {
isRequesting: boolean;
showBorder?: boolean;
onRequest: () => void;
extraActionLabel?: string;
isExtraActionBusy?: boolean;
isExtraActionDisabled?: boolean;
onExtraAction?: () => void;
}
export function DesktopPermissionRow({
@@ -18,6 +22,10 @@ export function DesktopPermissionRow({
isRequesting,
showBorder,
onRequest,
extraActionLabel,
isExtraActionBusy = false,
isExtraActionDisabled = false,
onExtraAction,
}: DesktopPermissionRowProps) {
const { theme } = useUnistyles();
const state = status?.state ?? "unknown";
@@ -36,9 +44,21 @@ export function DesktopPermissionRow({
</View>
<View style={styles.permissionRowActions}>
{isGranted ? (
<View style={styles.permissionStatusPill}>
<Check size={theme.iconSize.sm} color={theme.colors.foregroundMuted} />
<Text style={styles.permissionStatusText}>Granted</Text>
<View style={styles.permissionGrantedActions}>
<View style={styles.permissionStatusPill}>
<Check size={theme.iconSize.sm} color={theme.colors.foregroundMuted} />
<Text style={styles.permissionStatusText}>Granted</Text>
</View>
{extraActionLabel && onExtraAction ? (
<Button
variant="outline"
size="sm"
onPress={onExtraAction}
disabled={isExtraActionDisabled || isExtraActionBusy}
>
{isExtraActionBusy ? `${extraActionLabel}...` : extraActionLabel}
</Button>
) : null}
</View>
) : (
<Button variant="outline" size="sm" onPress={onRequest} disabled={isRequesting}>
@@ -75,6 +95,11 @@ const styles = StyleSheet.create((theme) => ({
alignItems: "flex-end",
gap: theme.spacing[1],
},
permissionGrantedActions: {
flexDirection: "row",
alignItems: "center",
gap: theme.spacing[2],
},
permissionStatusPill: {
flexDirection: "row",
alignItems: "center",
@@ -13,8 +13,10 @@ export function DesktopPermissionsSection() {
snapshot,
isRefreshing,
requestingPermission,
isSendingTestNotification,
refreshPermissions,
requestPermission,
sendTestNotification,
} = useDesktopPermissions();
if (!isDesktop) {
@@ -22,6 +24,7 @@ export function DesktopPermissionsSection() {
}
const isBusy = isRefreshing || requestingPermission !== null;
const notificationsGranted = snapshot?.notifications.state === "granted";
return (
<View style={settingsStyles.section}>
@@ -48,6 +51,12 @@ export function DesktopPermissionsSection() {
onRequest={() => {
void requestPermission("notifications");
}}
extraActionLabel="Test"
isExtraActionBusy={isSendingTestNotification}
isExtraActionDisabled={!notificationsGranted || isBusy}
onExtraAction={() => {
void sendTestNotification();
}}
/>
<DesktopPermissionRow
title="Microphone"
@@ -6,14 +6,17 @@ import {
type DesktopPermissionKind,
type DesktopPermissionSnapshot,
} from "@/desktop/permissions/desktop-permissions";
import { sendOsNotification } from "@/utils/os-notifications";
export interface UseDesktopPermissionsReturn {
isDesktop: boolean;
snapshot: DesktopPermissionSnapshot | null;
isRefreshing: boolean;
requestingPermission: DesktopPermissionKind | null;
isSendingTestNotification: boolean;
refreshPermissions: () => Promise<void>;
requestPermission: (kind: DesktopPermissionKind) => Promise<void>;
sendTestNotification: () => Promise<void>;
}
const EMPTY_NOTIFICATION_STATUS = {
@@ -34,6 +37,7 @@ export function useDesktopPermissions(): UseDesktopPermissionsReturn {
const [requestingPermission, setRequestingPermission] = useState<DesktopPermissionKind | null>(
null
);
const [isSendingTestNotification, setIsSendingTestNotification] = useState(false);
useEffect(() => {
return () => {
@@ -109,6 +113,29 @@ export function useDesktopPermissions(): UseDesktopPermissionsReturn {
[isDesktop, refreshPermissions]
);
const sendTestNotification = useCallback(async () => {
if (!isDesktop) {
return;
}
setIsSendingTestNotification(true);
try {
const sent = await sendOsNotification({
title: "Paseo notification test",
body: "If you can see this, delivery works. Click it to verify the open flow.",
});
if (!sent) {
console.warn("[Settings] Desktop test notification was not delivered");
}
} catch (error) {
console.error("[Settings] Failed to send desktop test notification", error);
} finally {
if (isMountedRef.current) {
setIsSendingTestNotification(false);
}
}
}, [isDesktop]);
useEffect(() => {
if (!isDesktop) {
return;
@@ -122,7 +149,9 @@ export function useDesktopPermissions(): UseDesktopPermissionsReturn {
snapshot,
isRefreshing,
requestingPermission,
isSendingTestNotification,
refreshPermissions,
requestPermission,
sendTestNotification,
};
}