tangled
alpha
login
or
join now
leaflet.pub
/
leaflet
289
fork
atom
a tool for shared writing and social publishing
289
fork
atom
overview
issues
28
pulls
pipelines
ping notifications and fix reply notifications
awarm.space
4 months ago
32ddb793
1ee32442
+42
-20
4 changed files
expand all
collapse all
unified
split
app
(home-pages)
notifications
NotificationList.tsx
lish
[did]
[publication]
[rkey]
Interactions
Comments
commentAction.ts
components
IdentityProvider.tsx
src
notifications.ts
+5
-2
app/(home-pages)/notifications/NotificationList.tsx
···
5
5
import { useEffect, createContext } from "react";
6
6
import { markAsRead } from "./getNotifications";
7
7
import { ReplyNotification } from "./ReplyNotification";
8
8
+
import { useIdentityData } from "components/IdentityProvider";
8
9
9
10
export function NotificationList({
10
11
notifications,
···
13
14
notifications: HydratedNotification[];
14
15
compact?: boolean;
15
16
}) {
17
17
+
let { mutate } = useIdentityData();
16
18
useEffect(() => {
17
17
-
setTimeout(() => {
18
18
-
markAsRead();
19
19
+
setTimeout(async () => {
20
20
+
await markAsRead();
21
21
+
mutate();
19
22
}, 500);
20
23
}, []);
21
24
+13
-17
app/lish/[did]/[publication]/[rkey]/Interactions/Comments/commentAction.ts
···
8
8
import { AtUri, lexToJson, Un$Typed } from "@atproto/api";
9
9
import { supabaseServerClient } from "supabase/serverClient";
10
10
import { Json } from "supabase/database.types";
11
11
-
import { Notification } from "src/notifications";
11
11
+
import {
12
12
+
Notification,
13
13
+
pingIdentityToUpdateNotification,
14
14
+
} from "src/notifications";
12
15
import { v7 } from "uuid";
13
16
14
17
export async function publishComment(args: {
···
68
71
})
69
72
.select();
70
73
let notifications: Notification[] = [];
71
71
-
if (
72
72
-
!args.comment.replyTo &&
73
73
-
new AtUri(args.document).host !== credentialSession.did
74
74
-
)
74
74
+
let recipient = args.comment.replyTo
75
75
+
? new AtUri(args.comment.replyTo).host
76
76
+
: new AtUri(args.document).host;
77
77
+
if (recipient !== credentialSession.did) {
75
78
notifications.push({
76
79
id: v7(),
77
77
-
recipient: new AtUri(args.document).host,
78
78
-
data: { type: "comment", comment_uri: uri.toString() },
79
79
-
});
80
80
-
if (
81
81
-
args.comment.replyTo &&
82
82
-
new AtUri(args.comment.replyTo).host !== credentialSession.did
83
83
-
)
84
84
-
notifications.push({
85
85
-
id: v7(),
86
86
-
recipient: new AtUri(args.comment.replyTo).host,
80
80
+
recipient,
87
81
data: {
88
82
type: "comment",
89
83
comment_uri: uri.toString(),
90
84
parent_uri: args.comment.replyTo,
91
85
},
92
86
});
93
93
-
// SOMEDAY: move this out the action with inngest or workflows
94
94
-
await supabaseServerClient.from("notifications").insert(notifications);
87
87
+
// SOMEDAY: move this out the action with inngest or workflows
88
88
+
await supabaseServerClient.from("notifications").insert(notifications);
89
89
+
await pingIdentityToUpdateNotification(recipient);
90
90
+
}
95
91
96
92
return {
97
93
record: data?.[0].record as Json,
+14
-1
components/IdentityProvider.tsx
···
1
1
"use client";
2
2
import { getIdentityData } from "actions/getIdentityData";
3
3
-
import { createContext, useContext } from "react";
3
3
+
import { createContext, useContext, useEffect } from "react";
4
4
import useSWR, { KeyedMutator, mutate } from "swr";
5
5
import { DashboardState } from "./PageLayouts/DashboardLayout";
6
6
+
import { supabaseBrowserClient } from "supabase/browserClient";
6
7
7
8
export type InterfaceState = {
8
9
dashboards: { [id: string]: DashboardState | undefined };
···
20
21
let { data: identity, mutate } = useSWR("identity", () => getIdentityData(), {
21
22
fallbackData: props.initialValue,
22
23
});
24
24
+
useEffect(() => {
25
25
+
if (!identity?.atp_did) return;
26
26
+
let supabase = supabaseBrowserClient();
27
27
+
let channel = supabase.channel(`identity.atp_did:${identity.atp_did}`);
28
28
+
channel.on("broadcast", { event: "notification" }, () => {
29
29
+
mutate();
30
30
+
});
31
31
+
channel.subscribe();
32
32
+
return () => {
33
33
+
channel.unsubscribe();
34
34
+
};
35
35
+
}, [identity?.atp_did]);
23
36
return (
24
37
<IdentityContext.Provider value={{ identity, mutate }}>
25
38
{props.children}
+10
src/notifications.ts
···
127
127
),
128
128
}));
129
129
}
130
130
+
131
131
+
export async function pingIdentityToUpdateNotification(did: string) {
132
132
+
let channel = supabaseServerClient.channel(`identity.atp_did:${did}`);
133
133
+
await channel.send({
134
134
+
type: "broadcast",
135
135
+
event: "notification",
136
136
+
payload: { message: "poke" },
137
137
+
});
138
138
+
await supabaseServerClient.removeChannel(channel);
139
139
+
}