Skip to content

Commit 3d8ba36

Browse files
committed
error handling
1 parent b61a7ec commit 3d8ba36

File tree

3 files changed

+140
-111
lines changed

3 files changed

+140
-111
lines changed

src/components/error.tsx

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,38 @@
11
import React from "react"
22

3-
const showError = (
3+
const showError = async (
44
setter: (value: React.SetStateAction<React.ReactNode>) => void,
5-
message: string
5+
response: Response
66
) => {
7-
console.log("Error message: ", message)
7+
const data =
8+
response.status < 500
9+
? JSON.stringify(await response.json(), null, 2)
10+
: await response.text()
811
setter(() => (
912
<div>
10-
<div className="alert alert-danger" role="alert">
11-
<p>
12-
There has been an error! The error details will be in the console log.
13-
Please reload the page to see if that resolves the issue. If the issue
14-
persists, go tell{" "}
15-
<a href="https://bsky.app/profile/coilysiren.me/" target="_blank">
16-
@coilysiren.me
17-
</a>{" "}
18-
about it.
19-
</p>
13+
<div
14+
className={
15+
response.status < 500 ? "alert alert-warning" : "alert alert-danger"
16+
}
17+
role="alert"
18+
>
19+
{response.status < 500 ? (
20+
<div>
21+
<pre className="error-message">{data}</pre>
22+
</div>
23+
) : (
24+
<p>
25+
<strong>
26+
There has been an error! The error details will be in the console
27+
log. Please reload the page to see if that resolves the issue. If
28+
the issue persists, go tell{" "}
29+
<a href="https://bsky.app/profile/coilysiren.me/" target="_blank">
30+
@coilysiren.me
31+
</a>{" "}
32+
about it.
33+
</strong>
34+
</p>
35+
)}
2036
</div>
2137
</div>
2238
))

src/pages/apps/bsky-follow-suggestions.tsx

Lines changed: 110 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import Closer from "../../components/closer"
55
import { ProfileViewDetailed } from "@atproto/api/dist/client/types/app/bsky/actor/defs"
66
import showError from "../../components/error"
77

8+
const requestFrequency = 100
9+
810
interface ISuggestionDetails {
911
myFollowersCount: number
1012
folledByMe: boolean
@@ -13,15 +15,21 @@ interface ISuggestionDetails {
1315
}
1416

1517
const Bsky = () => {
18+
// START: GENERIC STATE
19+
// This kind of state is likely to be used in most applications.
1620
const handleRef = useRef<HTMLInputElement | null>(null)
1721
const [searchParams, setSearchParams] =
1822
typeof window !== "undefined"
1923
? useSearchParams()
2024
: [new URLSearchParams(), () => {}]
2125
const [error, setError] = useState<React.ReactNode>()
26+
// END: GENERIC STATE
27+
28+
// START: APPLICATION STATE
29+
// Reset all of this stuff whenever there is an error
30+
// or whenever the user does something that implies a page refesh.
2231
const [following, setFollowing] = useState<string[]>([])
2332
const [followingCopy, setMyFollowingCopy] = useState<string[]>([])
24-
const [showFollowedByMe, setShowFollowedByMe] = useState<boolean>(true)
2533
const [suggestionCount, setSuggestionCount] = useState<{
2634
[key: string]: number
2735
}>({})
@@ -34,9 +42,22 @@ const Bsky = () => {
3442
const [suggestionDetailsByScore, setSuggestionDetailsByScore] = useState<
3543
ISuggestionDetails[]
3644
>([])
37-
const [showDetailsByScore, setShowDetailsByScore] = useState<boolean>(false)
45+
const clearApplicationState = () => {
46+
setFollowing([])
47+
setMyFollowingCopy([])
48+
setSuggestionCount({})
49+
setSuggestionCountSorted([])
50+
setSuggestionDetails([])
51+
setSuggestionDetailsByScore([])
52+
}
53+
// END: APPLICATION STATE
3854

39-
const requestFrequency = 100
55+
// START: UI STATE
56+
// This is similar to the application state,
57+
// different in that it doesn't need to be reset.
58+
const [showFollowedByMe, setShowFollowedByMe] = useState<boolean>(true)
59+
const [showDetailsByScore, setShowDetailsByScore] = useState<boolean>(false)
60+
// END: UI STATE
4061

4162
// Get the "handle" query parameter.
4263
// This should eventually be replaced with a user input field.
@@ -45,22 +66,18 @@ const Bsky = () => {
4566
const myHandle = searchParams.get("handle")
4667

4768
// Get the list of people that I follow.
48-
const handleFollowing = async () => {
49-
try {
50-
const response = await fetch(
51-
`${process.env.GATSBY_API_URL}/bsky/${myHandle}/following/handles`
52-
)
53-
if (!response.ok) {
54-
throw new Error(await response.text())
55-
}
56-
const data: string[] = await response.json()
57-
// This is done to prevent the same handles from being suggested in the same order.
58-
const dataRandomized = [...new Set(data.sort(() => Math.random() - 0.5))]
59-
setFollowing(() => dataRandomized)
60-
setMyFollowingCopy(() => dataRandomized)
61-
} catch (error) {
62-
showError(setError, error.toString())
69+
const handleFollowing = async (handle: string) => {
70+
const response = await fetch(
71+
`${process.env.GATSBY_API_URL}/bsky/${handle}/following/handles`
72+
)
73+
if (!response.ok) {
74+
clearApplicationState()
75+
showError(setError, response)
76+
return
6377
}
78+
const data: string[] = await response.json()
79+
setFollowing(() => data)
80+
setMyFollowingCopy(() => data)
6481
}
6582

6683
// When you have my followers ...
@@ -82,37 +99,35 @@ const Bsky = () => {
8299
// - C: 2
83100
// - D: 1
84101
const handleSuggestionCounts = async () => {
85-
try {
86-
var myFollowingCopy = [...following]
87-
const myFollowingHandle = myFollowingCopy.pop()
102+
var myFollowingCopy = [...following]
103+
const myFollowingHandle = myFollowingCopy.pop()
104+
105+
// Get for a person that I follow, get a list of the people they follow
106+
const response = await fetch(
107+
`${process.env.GATSBY_API_URL}/bsky/${myFollowingHandle}/following/handles`
108+
)
109+
if (!response.ok) {
110+
clearApplicationState()
111+
showError(setError, response)
112+
return
113+
}
114+
const data: string[] = await response.json()
88115

89-
// Get for a person that I follow, get a list of the people they follow
90-
const response = await fetch(
91-
`${process.env.GATSBY_API_URL}/bsky/${myFollowingHandle}/following/handles`
116+
// Generate a "suggestionCount" int for each handle that they follow
117+
// If the handle is already in the suggestions, increment the count.
118+
var suggestionsCopy = { ...suggestionCount }
119+
data.forEach((theirFollowingHandle) => {
120+
const validHandle = ![myHandle, "handle.invalid", ""].includes(
121+
theirFollowingHandle
92122
)
93-
if (!response.ok) {
94-
throw new Error(await response.text())
123+
if (validHandle) {
124+
var suggestionCount = suggestionsCopy[theirFollowingHandle]
125+
suggestionCount = suggestionCount ? suggestionCount + 1 : 1
126+
suggestionsCopy[theirFollowingHandle] = suggestionCount
95127
}
96-
const data: string[] = await response.json()
97-
98-
// Generate a "suggestionCount" int for each handle that they follow
99-
// If the handle is already in the suggestions, increment the count.
100-
var suggestionsCopy = { ...suggestionCount }
101-
data.forEach((theirFollowingHandle) => {
102-
const validHandle = ![myHandle, "handle.invalid", ""].includes(
103-
theirFollowingHandle
104-
)
105-
if (validHandle) {
106-
var suggestionCount = suggestionsCopy[theirFollowingHandle]
107-
suggestionCount = suggestionCount ? suggestionCount + 1 : 1
108-
suggestionsCopy[theirFollowingHandle] = suggestionCount
109-
}
110-
})
111-
setSuggestionCount(() => suggestionsCopy)
112-
setFollowing(() => myFollowingCopy)
113-
} catch (error) {
114-
showError(setError, error.toString())
115-
}
128+
})
129+
setSuggestionCount(() => suggestionsCopy)
130+
setFollowing(() => myFollowingCopy)
116131
}
117132

118133
// When you have the suggestionomendation counts ...
@@ -170,63 +185,61 @@ const Bsky = () => {
170185
// "Details" here means any profile information required to
171186
// display the suggestion to the user.
172187
const handleSuggestionDetails = async () => {
173-
try {
174-
const suggestionDetailsCopy = [...suggestionDetails]
175-
const suggestionCountSortedCopy = [...suggestionCountSorted]
176-
const shiftedItem = suggestionCountSortedCopy.shift()
188+
const suggestionDetailsCopy = [...suggestionDetails]
189+
const suggestionCountSortedCopy = [...suggestionCountSorted]
190+
const shiftedItem = suggestionCountSortedCopy.shift()
177191

178-
if (!shiftedItem) {
179-
console.error("No handle found to process.")
180-
suggestionCountSortedCopy.pop()
181-
setSuggestionCountSorted(() => suggestionCountSortedCopy)
182-
return
183-
}
192+
if (!shiftedItem) {
193+
console.error("No handle found to process.")
194+
suggestionCountSortedCopy.pop()
195+
setSuggestionCountSorted(() => suggestionCountSortedCopy)
196+
return
197+
}
184198

185-
const [handle, myFollowers] = shiftedItem
186-
if (!handle) {
187-
console.error("No handle found to process.")
188-
suggestionCountSortedCopy.pop()
189-
setSuggestionCountSorted(() => suggestionCountSortedCopy)
190-
return
191-
}
199+
const [handle, myFollowers] = shiftedItem
200+
if (!handle) {
201+
console.error("No handle found to process.")
202+
suggestionCountSortedCopy.pop()
203+
setSuggestionCountSorted(() => suggestionCountSortedCopy)
204+
return
205+
}
192206

193-
const tooManyDetails = suggestionDetailsCopy.length > 250
194-
if (tooManyDetails) {
195-
console.log("Too many details")
196-
setSuggestionCountSorted([])
197-
return
198-
}
207+
const tooManyDetails = suggestionDetailsCopy.length > 250
208+
if (tooManyDetails) {
209+
console.log("Too many details")
210+
setSuggestionCountSorted([])
211+
return
212+
}
199213

200-
const tooFewFollowers = followingCopy.length / 10 > myFollowers
201-
if (tooFewFollowers) {
202-
console.log("handle =>", handle)
203-
console.log("Too few followers =>", followingCopy.length, myFollowers)
204-
setSuggestionCountSorted([])
205-
return
206-
}
214+
const tooFewFollowers = followingCopy.length / 10 > myFollowers
215+
if (tooFewFollowers) {
216+
console.log("handle =>", handle)
217+
console.log("Too few followers =>", followingCopy.length, myFollowers)
218+
setSuggestionCountSorted([])
219+
return
220+
}
207221

208-
const response = await fetch(
209-
`${process.env.GATSBY_API_URL}/bsky/${handle}/profile`
210-
)
211-
if (!response.ok) {
212-
throw new Error(await response.text())
213-
}
214-
const data: { [key: string]: ProfileViewDetailed } = await response.json()
215-
const profile: ProfileViewDetailed = Object.values(data)[0]
222+
const response = await fetch(
223+
`${process.env.GATSBY_API_URL}/bsky/${handle}/profile`
224+
)
225+
if (!response.ok) {
226+
clearApplicationState()
227+
showError(setError, response)
228+
return
229+
}
230+
const data: { [key: string]: ProfileViewDetailed } = await response.json()
231+
const profile: ProfileViewDetailed = Object.values(data)[0]
216232

217-
suggestionDetailsCopy.push({
218-
myFollowersCount: myFollowers,
219-
score: myFollowers / (profile.followersCount ?? 1),
220-
profile: profile,
221-
folledByMe: followingCopy.includes(profile.handle),
222-
})
233+
suggestionDetailsCopy.push({
234+
myFollowersCount: myFollowers,
235+
score: myFollowers / (profile.followersCount ?? 1),
236+
profile: profile,
237+
folledByMe: followingCopy.includes(profile.handle),
238+
})
223239

224-
suggestionCountSortedCopy.pop()
225-
setSuggestionCountSorted(() => suggestionCountSortedCopy)
226-
setSuggestionDetails(() => suggestionDetailsCopy)
227-
} catch (error) {
228-
showError(setError, error.toString())
229-
}
240+
suggestionCountSortedCopy.pop()
241+
setSuggestionCountSorted(() => suggestionCountSortedCopy)
242+
setSuggestionDetails(() => suggestionDetailsCopy)
230243
}
231244

232245
// When you have the suggestionomendation details ...
@@ -380,7 +393,7 @@ const Bsky = () => {
380393
}
381394
onClick={() => {
382395
setSearchParams({ handle: handleRef.current?.value || "" })
383-
handleFollowing()
396+
handleFollowing(handleRef.current?.value || "")
384397
}}
385398
>
386399
Suggest!

src/sass/post.scss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ p > code {
163163
}
164164

165165
// Styling of triple ```
166-
pre {
166+
pre:not(.error-message) {
167167
background-color: vars.$dark-purple;
168168
background-image: url("../images/rows-triangles.svg");
169169
background-repeat: repeat-x;

0 commit comments

Comments
 (0)