tangled
alpha
login
or
join now
djara.dev
/
watproto
2
fork
atom
Testing implementation for private data in ATProto with ATPKeyserver and ATCute tools
2
fork
atom
overview
issues
pulls
pipelines
refactor error handling
Juan D. Jara
4 months ago
344e4c4a
88f12d25
+23
-31
1 changed file
expand all
collapse all
unified
split
packages
client
app
routes
settings.delegation.tsx
+23
-31
packages/client/app/routes/settings.delegation.tsx
···
1
1
-
import { Form, redirect, data } from 'react-router'
1
1
+
import { Form, data } from 'react-router'
2
2
import type { Route } from './+types/settings.delegation'
3
3
import { getOAuthSession } from '@www/lib/oauth.server'
4
4
import { env } from '@www/lib/env.server'
5
5
import { createKeyClient } from '@www/lib/xrpcClient'
6
6
+
import asyncWrap from '@www/lib/asyncWrap'
6
7
7
7
-
interface DelegateInfo {
8
8
-
delegateDid: string
9
9
-
permissions: string[]
10
10
-
grantedAt: string
11
11
-
expiresAt?: string
8
8
+
const defaultData = {
9
9
+
delegates: [],
10
10
+
groupId: '',
11
11
+
apiServiceDid: '',
12
12
+
userDid: ''
12
13
}
13
14
14
15
export async function loader({ request }: Route.LoaderArgs) {
···
16
17
const groupId = `${session.did}#followers`
17
18
const keyClient = createKeyClient(session)
18
19
19
19
-
try {
20
20
+
const [data, error] = await asyncWrap(async () => {
20
21
const result = await keyClient.listDelegates({ group_id: groupId })
21
22
return {
22
23
delegates: result.delegates,
···
24
25
apiServiceDid: env.API_SERVICE_DID,
25
26
userDid: session.did
26
27
}
27
27
-
} catch (error) {
28
28
-
// If group doesn't exist yet or error listing, return empty
29
29
-
return {
30
30
-
delegates: [],
31
31
-
groupId,
32
32
-
apiServiceDid: env.API_SERVICE_DID,
33
33
-
userDid: session.did
34
34
-
}
35
35
-
}
28
28
+
})
29
29
+
return { data, error }
36
30
}
37
31
38
32
export async function action({ request }: Route.ActionArgs) {
···
49
43
delegate_did: env.API_SERVICE_DID,
50
44
permissions: ['add_member', 'remove_member']
51
45
})
52
52
-
return data(
53
53
-
{ success: true, message: 'Server authorized successfully!' },
54
54
-
{ status: 200 }
55
55
-
)
46
46
+
return data({ success: true, message: 'Server authorized successfully!' })
56
47
} else if (action === 'revoke') {
57
48
await keyClient.revokeDelegate({
58
49
group_id: groupId,
59
50
delegate_did: env.API_SERVICE_DID
60
51
})
61
61
-
return data(
62
62
-
{ success: true, message: 'Server authorization revoked!' },
63
63
-
{ status: 200 }
64
64
-
)
52
52
+
return data({ success: true, message: 'Server authorization revoked!' })
65
53
}
66
54
} catch (error) {
67
55
return data(
···
72
60
{ status: 500 }
73
61
)
74
62
}
75
75
-
76
76
-
return redirect('/settings/delegation')
77
63
}
78
64
79
65
export default function DelegationSettings({
80
66
loaderData,
81
67
actionData
82
68
}: Route.ComponentProps) {
83
83
-
const { delegates, groupId, apiServiceDid, userDid } = loaderData
69
69
+
const error = loaderData.error
70
70
+
const { delegates, groupId, apiServiceDid, userDid } =
71
71
+
loaderData.data ?? defaultData
84
72
const isAuthorized = delegates.some((d) => d.delegateDid === apiServiceDid)
85
73
86
74
return (
87
87
-
<div className="p-4 max-w-3xl mx-auto">
88
88
-
<h1 className="text-2xl font-bold mb-4">Delegation Settings</h1>
75
75
+
<div className="px-4 py-6 max-w-3xl mx-auto">
76
76
+
<h1 className="text-2xl font-bold mb-3">Delegation Settings</h1>
89
77
90
78
<div className="card bg-base-200 shadow-xl mb-4">
91
79
<div className="card-body">
···
116
104
</div>
117
105
</div>
118
106
119
119
-
{actionData?.message && (
107
107
+
{actionData?.message ? (
120
108
<div
121
109
className={`alert ${actionData.success ? 'alert-success' : 'alert-error'} mb-4`}
122
110
>
123
111
{actionData.message}
124
112
</div>
125
125
-
)}
113
113
+
) : null}
114
114
+
115
115
+
{error ? (
116
116
+
<div className="alert alert-error mb-4">{error.message}</div>
117
117
+
) : null}
126
118
127
119
<Form method="POST" className="card-actions">
128
120
{isAuthorized ? (