authorgravatar for julius0216@outlook.comJulius Marminge <julius0216@outlook.com> 2026-06-20 10:58:39-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-06-20 10:58:39-07:00
logf7867addbe18ebb55c916041dc168aa4b8f39335
treef99e004d8d1bee21c2b8d10d6982486aaf253cca
parent7a8bab5d9df80e06782033d1ee252400e6f048b1
signature Signed by PGP key B5690EEEBB952194

[codex] Structure mobile notification setting failures (#3391)

Co-authored-by: codex <codex@users.noreply.github.com>

2 files changed, 40 insertions(+), 4 deletions(-)

apps/mobile/src/features/agent-awareness/liveActivityPreferences.ts+14-1
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1import * as Effect from "effect/Effect";1import * as Effect from "effect/Effect";
2import * as Schema from "effect/Schema";
2import { HttpClient } from "effect/unstable/http";3import { HttpClient } from "effect/unstable/http";
3import { ManagedRelay } from "@t3tools/client-runtime/relay";4import { ManagedRelay } from "@t3tools/client-runtime/relay";
45
...@@ -7,6 +8,18 @@ import { savePreferencesPatch } from "../../lib/storage";...@@ -7,6 +8,18 @@ import { savePreferencesPatch } from "../../lib/storage";
7import { linkEnvironmentToCloud } from "../cloud/linkEnvironment";8import { linkEnvironmentToCloud } from "../cloud/linkEnvironment";
8import { refreshAgentAwarenessRegistration } from "./remoteRegistration";9import { refreshAgentAwarenessRegistration } from "./remoteRegistration";
910
11export class LiveActivityPreferenceSaveError extends Schema.TaggedErrorClass<LiveActivityPreferenceSaveError>()(
12 "LiveActivityPreferenceSaveError",
13 {
14 enabled: Schema.Boolean,
15 cause: Schema.Defect(),
16 },
17) {
18 override get message(): string {
19 return `Failed to save the Live Activity updates setting (enabled: ${this.enabled}).`;
20 }
21}
22
10export function setLiveActivityUpdatesEnabled(input: {23export function setLiveActivityUpdatesEnabled(input: {
11 readonly enabled: boolean;24 readonly enabled: boolean;
12 readonly clerkToken: string | null;25 readonly clerkToken: string | null;
...@@ -15,7 +28,7 @@ export function setLiveActivityUpdatesEnabled(input: {...@@ -15,7 +28,7 @@ export function setLiveActivityUpdatesEnabled(input: {
15 return Effect.gen(function* () {28 return Effect.gen(function* () {
16 yield* Effect.tryPromise({29 yield* Effect.tryPromise({
17 try: () => savePreferencesPatch({ liveActivitiesEnabled: input.enabled }),30 try: () => savePreferencesPatch({ liveActivitiesEnabled: input.enabled }),
18 catch: (error) => error,31 catch: (cause) => new LiveActivityPreferenceSaveError({ enabled: input.enabled, cause }),
19 });32 });
2033
21 yield* refreshAgentAwarenessRegistration();34 yield* refreshAgentAwarenessRegistration();
apps/mobile/src/features/agent-awareness/notificationPermissions.ts+26-3
...@@ -1,5 +1,6 @@...@@ -1,5 +1,6 @@
1import * as Notifications from "expo-notifications";1import * as Notifications from "expo-notifications";
2import * as Effect from "effect/Effect";2import * as Effect from "effect/Effect";
3import * as Schema from "effect/Schema";
3import { Platform } from "react-native";4import { Platform } from "react-native";
45
5export type NotificationPermissionResult =6export type NotificationPermissionResult =
...@@ -7,9 +8,31 @@ export type NotificationPermissionResult =...@@ -7,9 +8,31 @@ export type NotificationPermissionResult =
7 | { readonly type: "granted" }8 | { readonly type: "granted" }
8 | { readonly type: "denied"; readonly canAskAgain: boolean };9 | { readonly type: "denied"; readonly canAskAgain: boolean };
910
11export class NotificationPermissionReadError extends Schema.TaggedErrorClass<NotificationPermissionReadError>()(
12 "NotificationPermissionReadError",
13 {
14 cause: Schema.Defect(),
15 },
16) {
17 override get message(): string {
18 return "Failed to read notification permissions on iOS.";
19 }
20}
21
22export class NotificationPermissionRequestError extends Schema.TaggedErrorClass<NotificationPermissionRequestError>()(
23 "NotificationPermissionRequestError",
24 {
25 cause: Schema.Defect(),
26 },
27) {
28 override get message(): string {
29 return "Failed to request notification permissions on iOS.";
30 }
31}
32
10export const requestAgentNotificationPermission: Effect.Effect<33export const requestAgentNotificationPermission: Effect.Effect<
11 NotificationPermissionResult,34 NotificationPermissionResult,
12 unknown35 NotificationPermissionReadError | NotificationPermissionRequestError
13> = Effect.gen(function* () {36> = Effect.gen(function* () {
14 if (Platform.OS !== "ios") {37 if (Platform.OS !== "ios") {
15 return { type: "unsupported" };38 return { type: "unsupported" };
...@@ -17,7 +40,7 @@ export const requestAgentNotificationPermission: Effect.Effect<...@@ -17,7 +40,7 @@ export const requestAgentNotificationPermission: Effect.Effect<
1740
18 const existing = yield* Effect.tryPromise({41 const existing = yield* Effect.tryPromise({
19 try: () => Notifications.getPermissionsAsync(),42 try: () => Notifications.getPermissionsAsync(),
20 catch: (error) => error,43 catch: (cause) => new NotificationPermissionReadError({ cause }),
21 });44 });
22 if (existing.granted) {45 if (existing.granted) {
23 return { type: "granted" };46 return { type: "granted" };
...@@ -36,7 +59,7 @@ export const requestAgentNotificationPermission: Effect.Effect<...@@ -36,7 +59,7 @@ export const requestAgentNotificationPermission: Effect.Effect<
36 allowSound: true,59 allowSound: true,
37 },60 },
38 }),61 }),
39 catch: (error) => error,62 catch: (cause) => new NotificationPermissionRequestError({ cause }),
40 });63 });
41 return requested.granted64 return requested.granted
42 ? { type: "granted" }65 ? { type: "granted" }