+135
-27
src/routes/profile.$did/post.$rkey.tsx
+135
-27
src/routes/profile.$did/post.$rkey.tsx
···
1
1
import { AtUri } from "@atproto/api";
2
2
import { useInfiniteQuery, useQueryClient } from "@tanstack/react-query";
3
3
import { createFileRoute, Outlet } from "@tanstack/react-router";
4
-
import React, { useEffect, useLayoutEffect } from "react";
4
+
import React, { useLayoutEffect } from "react";
5
5
6
6
import { Header } from "~/components/Header";
7
7
import { UniversalPostRendererATURILoader } from "~/components/UniversalPostRenderer";
8
8
//import { usePersistentStore } from '~/providers/PersistentStoreProvider';
9
9
import {
10
10
constructPostQuery,
11
+
type linksAllResponse,
12
+
type linksRecordsResponse,
13
+
useQueryConstellation,
11
14
useQueryIdentity,
12
15
useQueryPost,
13
16
yknowIReallyHateThisButWhateverGuardedConstructConstellationInfiniteQueryLinks,
···
193
196
() =>
194
197
resolvedDid
195
198
? `at://${decodeURIComponent(resolvedDid)}/app.bsky.feed.post/${rkey}`
196
-
: "",
199
+
: undefined,
197
200
[resolvedDid, rkey]
198
201
);
199
202
200
203
const { data: mainPost } = useQueryPost(atUri);
201
204
205
+
console.log("atUri",atUri)
206
+
207
+
const opdid = React.useMemo(
208
+
() =>
209
+
atUri
210
+
? new AtUri(atUri).host
211
+
: undefined,
212
+
[atUri]
213
+
);
214
+
215
+
// @ts-expect-error i hate overloads
216
+
const { data: links } = useQueryConstellation(atUri?{
217
+
method: "/links/all",
218
+
target: atUri,
219
+
} : {
220
+
method: "undefined",
221
+
target: ""
222
+
})as { data: linksAllResponse | undefined };
223
+
224
+
//const [likes, setLikes] = React.useState<number | null>(null);
225
+
//const [reposts, setReposts] = React.useState<number | null>(null);
226
+
const [replyCount, setReplyCount] = React.useState<number | null>(null);
227
+
228
+
React.useEffect(() => {
229
+
// /*mass comment*/ console.log(JSON.stringify(links, null, 2));
230
+
// setLikes(
231
+
// links
232
+
// ? links?.links?.["app.bsky.feed.like"]?.[".subject.uri"]?.records || 0
233
+
// : null
234
+
// );
235
+
// setReposts(
236
+
// links
237
+
// ? links?.links?.["app.bsky.feed.repost"]?.[".subject.uri"]?.records || 0
238
+
// : null
239
+
// );
240
+
setReplyCount(
241
+
links
242
+
? links?.links?.["app.bsky.feed.post"]?.[".reply.parent.uri"]
243
+
?.records || 0
244
+
: null
245
+
);
246
+
}, [links]);
247
+
248
+
const { data: opreplies } = useQueryConstellation(
249
+
!!opdid && replyCount && replyCount >= 25
250
+
? {
251
+
method: "/links",
252
+
target: atUri,
253
+
// @ts-expect-error overloading sucks so much
254
+
collection: "app.bsky.feed.post",
255
+
path: ".reply.parent.uri",
256
+
//cursor?: string;
257
+
dids: [opdid],
258
+
}
259
+
: {
260
+
method: "undefined",
261
+
target: "",
262
+
}
263
+
) as { data: linksRecordsResponse | undefined };
264
+
265
+
const opReplyAturis =
266
+
opreplies?.linking_records.map(
267
+
(r) => `at://${r.did}/${r.collection}/${r.rkey}`,
268
+
) ?? [];
269
+
270
+
202
271
// const { data: repliesData } = useQueryConstellation({
203
272
// method: "/links",
204
273
// target: atUri,
···
219
288
});
220
289
221
290
const {
222
-
data: repliesData,
223
-
// fetchNextPage,
224
-
// hasNextPage,
225
-
// isFetchingNextPage,
291
+
data: infiniteRepliesData,
292
+
fetchNextPage,
293
+
hasNextPage,
294
+
isFetchingNextPage,
226
295
} = infinitequeryresults;
227
296
228
-
// auto-fetch all pages
229
-
useEffect(() => {
230
-
if (
231
-
infinitequeryresults.hasNextPage &&
232
-
!infinitequeryresults.isFetchingNextPage
233
-
) {
234
-
console.log("Fetching the next page...");
235
-
infinitequeryresults.fetchNextPage();
236
-
}
237
-
}, [infinitequeryresults]);
297
+
// // auto-fetch all pages
298
+
// useEffect(() => {
299
+
// if (
300
+
// infinitequeryresults.hasNextPage &&
301
+
// !infinitequeryresults.isFetchingNextPage
302
+
// ) {
303
+
// console.log("Fetching the next page...");
304
+
// infinitequeryresults.fetchNextPage();
305
+
// }
306
+
// }, [infinitequeryresults]);
238
307
239
-
const replyAturis = repliesData
240
-
? repliesData.pages.flatMap((page) =>
241
-
page
242
-
? page.linking_records.map((record) => {
243
-
const aturi = `at://${record.did}/${record.collection}/${record.rkey}`;
244
-
return aturi;
245
-
})
246
-
: []
247
-
)
248
-
: [];
308
+
// const replyAturis = repliesData
309
+
// ? repliesData.pages.flatMap((page) =>
310
+
// page
311
+
// ? page.linking_records.map((record) => {
312
+
// const aturi = `at://${record.did}/${record.collection}/${record.rkey}`;
313
+
// return aturi;
314
+
// })
315
+
// : []
316
+
// )
317
+
// : [];
249
318
250
-
const opdid = new AtUri(atUri).host;
319
+
const replyAturis = React.useMemo(() => {
320
+
// Get all replies from the standard infinite query
321
+
const allReplies =
322
+
infiniteRepliesData?.pages.flatMap(
323
+
(page) =>
324
+
page?.linking_records.map(
325
+
(r) => `at://${r.did}/${r.collection}/${r.rkey}`,
326
+
) ?? [],
327
+
) ?? [];
328
+
329
+
if (replyCount && (replyCount < 25)) {
330
+
// If count is low, just use the standard list and find the oldest OP reply to move to the top
331
+
const opdidFromUri = atUri ? new AtUri(atUri).host : undefined;
332
+
const oldestOpsIndex = allReplies.findIndex(
333
+
(aturi) => new AtUri(aturi).host === opdidFromUri,
334
+
);
335
+
if (oldestOpsIndex > 0) {
336
+
const [oldestOpsReply] = allReplies.splice(oldestOpsIndex, 1);
337
+
allReplies.unshift(oldestOpsReply);
338
+
}
339
+
return allReplies;
340
+
} else {
341
+
// If count is high, prioritize OP replies from the special query
342
+
// and filter them out from the main list to avoid duplication.
343
+
const opReplySet = new Set(opReplyAturis);
344
+
const otherReplies = allReplies.filter((uri) => !opReplySet.has(uri));
345
+
return [...opReplyAturis, ...otherReplies];
346
+
}
347
+
}, [infiniteRepliesData, opReplyAturis, replyCount, atUri]);
251
348
252
349
// Find oldest OP reply
253
350
const oldestOpsIndex = replyAturis.findIndex(
···
282
379
283
380
hasPerformedInitialLayout.current = true;
284
381
}
382
+
285
383
// todo idk what to do with this
384
+
// eslint-disable-next-line react-hooks/set-state-in-effect
286
385
setLayoutReady(true);
287
386
}
288
387
}, [parents, layoutReady]);
···
423
522
/>
424
523
);
425
524
})}
525
+
{hasNextPage && (
526
+
<button
527
+
onClick={() => fetchNextPage()}
528
+
disabled={isFetchingNextPage}
529
+
className="w-[calc(100%-2rem)] mx-4 my-4 px-4 py-2 bg-gray-100 dark:bg-gray-800 text-gray-800 dark:text-gray-200 rounded-lg hover:bg-gray-200 dark:hover:bg-gray-700 font-semibold disabled:opacity-50"
530
+
>
531
+
{isFetchingNextPage ? "Loading..." : "Load More"}
532
+
</button>
533
+
)}
426
534
</div>
427
535
</div>
428
536
</>
+4
-3
src/utils/followState.ts
+4
-3
src/utils/followState.ts
···
1
-
import { AtUri, type Agent } from "@atproto/api";
2
-
import { useQueryConstellation, type linksRecordsResponse } from "./useQuery";
1
+
import { type Agent,AtUri } from "@atproto/api";
2
+
import { TID } from "@atproto/common-web";
3
3
import type { QueryClient } from "@tanstack/react-query";
4
-
import { TID } from "@atproto/common-web";
4
+
5
+
import { type linksRecordsResponse,useQueryConstellation } from "./useQuery";
5
6
6
7
export function useGetFollowState({
7
8
target,