···
14
14
const router = useRouter();
15
15
const requireAuth = useAuthAction();
16
16
17
17
-
const createAction = async () => {
18
18
-
requireAuth();
17
17
+
const createAction = requireAuth(async () => {
19
18
const rkey = await createDraft();
20
19
router.push(`/drafts/${rkey}`);
21
21
-
};
20
20
+
});
22
21
23
22
return (
24
23
<ActionButton action={createAction} className="NewTrailButton" pendingChildren="creating...">
···
50
50
const lastStop = trail.stops[trail.stops.length - 1];
51
51
const shouldShowAddButton = lastStop?.title?.trim() && trail.stops.length < 12;
52
52
53
53
-
const startWalkAction = async () => {
54
54
-
requireAuth();
53
53
+
const startWalkAction = requireAuth(async () => {
55
54
if (!trail.yourWalk && !isEditing) {
56
55
await startWalk(trail.header.uri, trail.header.cid);
57
56
}
58
57
onModeChange("walk");
59
59
-
};
58
58
+
});
60
59
61
61
-
const abandonAction = async () => {
60
60
+
const abandonAction = requireAuth(async () => {
62
61
if (confirm("abandon this trail? your progress will be lost")) {
63
62
if (trail.yourWalk) {
64
63
await abandonWalk(trail.yourWalk!.uri);
65
64
}
66
65
}
67
67
-
};
66
66
+
});
68
67
69
69
-
const deleteTrailAction = async () => {
68
68
+
const deleteTrailAction = requireAuth(async () => {
70
69
if (confirm("delete this trail? it will be gone for everyone forever")) {
71
70
await deleteTrail(trail.header.uri);
72
71
router.push("/");
73
72
}
74
74
-
};
73
73
+
});
75
74
76
75
const handleStopTitleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>, stopId: string) => {
77
76
const currentIndex = trail.stops.findIndex((s) => s.tid === stopId);
···
163
163
setQueuedScroll({ pending: target });
164
164
};
165
165
166
166
-
const handleContinue = async () => {
167
167
-
requireAuth();
166
166
+
const handleContinue = requireAuth(async () => {
168
167
if (currentStopIndex < stops.length - 1) {
169
168
const nextIndex = currentStopIndex + 1;
170
169
setFurthestStopIndex(Math.max(nextIndex, furthestStopIndex));
···
183
182
}, 100);
184
183
}
185
184
}
186
186
-
};
185
185
+
});
187
186
188
188
-
const handleGoToStop = async (index: number) => {
187
187
+
const handleGoToStop = requireAuth(async (index: number) => {
189
188
setCurrentStopIndex(index);
190
189
queueScroll(index);
191
190
if (!isEditMode && yourWalk) {
192
191
const stopTid = stops[index].tid;
193
192
await visitStop(yourWalk.uri, stopTid);
194
193
}
195
195
-
};
194
194
+
});
196
195
197
196
const handleWriteReflection = () => {
198
197
const trailUrl = `${window.location.origin}/@${header.creator.handle}/trail/${header.rkey}`;
···
202
201
window.open(`https://bsky.app/intent/compose?text=${text}`, "_blank");
203
202
};
204
203
205
205
-
const abandonAction = async () => {
204
204
+
const abandonAction = requireAuth(async () => {
206
205
if (confirm("abandon this trail? your progress will be lost")) {
207
206
if (yourWalk) {
208
207
await abandonWalk(yourWalk.uri);
···
211
210
});
212
211
}
213
212
}
214
214
-
};
213
213
+
});
215
214
216
215
const isAvatarsActive = !isHoveringStopContent && !isHoveringContainer;
217
216
···
201
201
const [publishError, setPublishError] = useState<string[] | null>(null);
202
202
const [inlineErrors, setInlineErrors] = useState<Record<string, string>>({});
203
203
204
204
-
const publishAction = async () => {
205
205
-
requireAuth();
204
204
+
const publishAction = requireAuth(async () => {
206
205
setPublishError(null);
207
206
setInlineErrors({});
208
207
···
229
228
const message = error instanceof Error ? error.message : "something went wrong";
230
229
setPublishError([message]);
231
230
}
232
232
-
};
231
231
+
});
233
232
234
233
const trailDetailData = {
235
234
header: {
···
79
79
<h1>lost the trail</h1>
80
80
<p>no worries. reload to get back on track</p>
81
81
<button onClick={() => window.location.reload()}>reload</button>
82
82
-
<p>if this didn't help, try logging out and back in (sorry!)</p>
83
82
</div>
84
83
</body>
85
84
</html>
···
3
3
import { useLoginModal } from "@/app/LoginModalContext";
4
4
import { useAuthContext } from "@/app/AuthContext";
5
5
6
6
-
export class AuthRequiredError extends Error {
7
7
-
constructor() {
8
8
-
super("Authentication required");
9
9
-
this.name = "AuthRequiredError";
10
10
-
}
11
11
-
}
12
12
-
13
6
export function useAuthAction() {
14
7
const { openLoginModal } = useLoginModal();
15
8
const { did } = useAuthContext();
16
9
17
17
-
return () => {
18
18
-
if (!did) {
19
19
-
openLoginModal();
20
20
-
throw new AuthRequiredError();
21
21
-
}
22
22
-
};
10
10
+
return <Args extends unknown[], R>(action: (...args: Args) => Promise<R>) =>
11
11
+
async (...args: Args): Promise<R | undefined> => {
12
12
+
if (did) {
13
13
+
return action(...args);
14
14
+
} else {
15
15
+
openLoginModal();
16
16
+
return undefined;
17
17
+
}
18
18
+
};
23
19
}
···
3
3
import { useTransition, type ReactNode } from "react";
4
4
5
5
type Props = {
6
6
-
action: () => Promise<void> | void;
6
6
+
action: () => Promise<void>;
7
7
children: ReactNode;
8
8
pendingChildren?: ReactNode;
9
9
className?: string;