Skip to content

Commit 7c13109

Browse files
authored
Use did instead of handle for all links (#24)
* ✨ Use dids in all links instead of handles * 🐛 Maintain search params when redirecting * 🐛 Wait for auth before attempting to resolve handle
1 parent 6b5e8f9 commit 7c13109

File tree

15 files changed

+312
-214
lines changed

15 files changed

+312
-214
lines changed

Diff for: app/repositories/[id]/[...record]/page-content.tsx

+196
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
'use client'
2+
import { useQuery } from '@tanstack/react-query'
3+
import {
4+
AppBskyFeedGetPostThread as GetPostThread,
5+
ComAtprotoAdminEmitModerationEvent,
6+
} from '@atproto/api'
7+
import { ReportPanel } from '@/reports/ReportPanel'
8+
import { RecordView } from '@/repositories/RecordView'
9+
import client from '@/lib/client'
10+
import { createAtUri } from '@/lib/util'
11+
import { createReport } from '@/repositories/createReport'
12+
import { Loading, LoadingFailed } from '@/common/Loader'
13+
import { CollectionId } from '@/reports/helpers/subject'
14+
import { usePathname, useRouter, useSearchParams } from 'next/navigation'
15+
import { ModActionPanelQuick } from 'app/actions/ModActionPanel/QuickAction'
16+
import { emitEvent } from '@/mod-event/helpers/emitEvent'
17+
import { useEffect } from 'react'
18+
import { useTitle } from 'react-use'
19+
20+
const buildPageTitle = ({
21+
handle,
22+
collection,
23+
rkey,
24+
}: {
25+
handle?: string
26+
collection?: string
27+
rkey?: string
28+
}) => {
29+
let title = `Record Details`
30+
31+
if (collection) {
32+
const titleFromCollection = collection.split('.').pop()
33+
if (titleFromCollection) {
34+
title =
35+
titleFromCollection[0].toUpperCase() + titleFromCollection.slice(1)
36+
}
37+
}
38+
39+
if (handle) {
40+
title += ` - ${handle}`
41+
}
42+
43+
if (rkey) {
44+
title += ` - ${rkey}`
45+
}
46+
return title
47+
}
48+
49+
export default function RecordViewPageContent({
50+
params,
51+
}: {
52+
params: { id: string; record: string[] }
53+
}) {
54+
const id = decodeURIComponent(params.id)
55+
const collection = params.record[0] && decodeURIComponent(params.record[0])
56+
const rkey = params.record[1] && decodeURIComponent(params.record[1])
57+
const {
58+
data,
59+
error,
60+
refetch,
61+
isLoading: isInitialLoading,
62+
} = useQuery({
63+
queryKey: ['record', { id, collection, rkey }],
64+
queryFn: async () => {
65+
let did: string
66+
if (id.startsWith('did:')) {
67+
did = id
68+
} else {
69+
const { data } = await client.api.com.atproto.identity.resolveHandle({
70+
handle: id,
71+
})
72+
did = data.did
73+
}
74+
const uri = createAtUri({ did, collection, rkey })
75+
const getRecord = async () => {
76+
const { data: record } = await client.api.com.atproto.admin.getRecord(
77+
{ uri },
78+
{ headers: client.adminHeaders() },
79+
)
80+
return record
81+
}
82+
const getThread = async () => {
83+
if (collection !== CollectionId.Post) {
84+
return undefined
85+
}
86+
try {
87+
const { data: thread } = await client.api.app.bsky.feed.getPostThread(
88+
{ uri },
89+
{ headers: client.adminHeaders() },
90+
)
91+
return thread
92+
} catch (err) {
93+
if (err instanceof GetPostThread.NotFoundError) {
94+
return undefined
95+
}
96+
throw err
97+
}
98+
}
99+
const getListProfiles = async () => {
100+
if (collection !== CollectionId.List) {
101+
return undefined
102+
}
103+
// TODO: We need pagination here, right? how come getPostThread doesn't need it?
104+
const { data: listData } = await client.api.app.bsky.graph.getList({
105+
list: uri,
106+
})
107+
return listData.items.map(({ subject }) => subject)
108+
}
109+
const [record, profiles, thread] = await Promise.all([
110+
getRecord(),
111+
getListProfiles(),
112+
getThread(),
113+
])
114+
return { record, thread, profiles }
115+
},
116+
})
117+
118+
const searchParams = useSearchParams()
119+
const router = useRouter()
120+
const pathname = usePathname()
121+
const quickOpenParam = searchParams.get('quickOpen') ?? ''
122+
const reportUri = searchParams.get('reportUri') || undefined
123+
const setQuickActionPanelSubject = (subject: string) => {
124+
// This route should not have any search params but in case it does, let's make sure original params are maintained
125+
const newParams = new URLSearchParams(searchParams)
126+
if (!subject) {
127+
newParams.delete('quickOpen')
128+
} else {
129+
newParams.set('quickOpen', subject)
130+
}
131+
router.push((pathname ?? '') + '?' + newParams.toString())
132+
}
133+
const setReportUri = (uri?: string) => {
134+
const newParams = new URLSearchParams(searchParams)
135+
if (uri) {
136+
newParams.set('reportUri', uri)
137+
} else {
138+
newParams.delete('reportUri')
139+
}
140+
router.push((pathname ?? '') + '?' + newParams.toString())
141+
}
142+
143+
useEffect(() => {
144+
if (reportUri === 'default' && data?.record) {
145+
setReportUri(data?.record.uri)
146+
}
147+
}, [data, reportUri])
148+
149+
const pageTitle = buildPageTitle({
150+
handle: data?.record?.repo.handle,
151+
rkey,
152+
collection,
153+
})
154+
useTitle(pageTitle)
155+
156+
if (error) {
157+
return <LoadingFailed error={error} />
158+
}
159+
if (!data) {
160+
return <Loading />
161+
}
162+
return (
163+
<>
164+
<ModActionPanelQuick
165+
open={!!quickOpenParam}
166+
onClose={() => setQuickActionPanelSubject('')}
167+
setSubject={setQuickActionPanelSubject}
168+
subject={quickOpenParam} // select first subject if there are multiple
169+
subjectOptions={[quickOpenParam]}
170+
isInitialLoading={isInitialLoading}
171+
onSubmit={async (
172+
vals: ComAtprotoAdminEmitModerationEvent.InputSchema,
173+
) => {
174+
await emitEvent(vals)
175+
refetch()
176+
}}
177+
/>
178+
<ReportPanel
179+
open={!!reportUri}
180+
onClose={() => setReportUri(undefined)}
181+
subject={reportUri}
182+
onSubmit={async (vals) => {
183+
await createReport(vals)
184+
refetch()
185+
}}
186+
/>
187+
<RecordView
188+
record={data.record}
189+
thread={data.thread}
190+
profiles={data.profiles}
191+
onReport={setReportUri}
192+
onShowActionPanel={(subject) => setQuickActionPanelSubject(subject)}
193+
/>
194+
</>
195+
)
196+
}

0 commit comments

Comments
 (0)