Skip to content

Commit 21b2c80

Browse files
committed
Consolidated coll/want data.
1 parent 46b1ba2 commit 21b2c80

File tree

5 files changed

+119
-200
lines changed

5 files changed

+119
-200
lines changed

frontend/src/api/discogs.ts

Lines changed: 85 additions & 152 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { isNullOrBlank } from "../utils"
2-
import { ICollections, IIdentify, IProfile, IReleases, VinylAPIImageMap } from "./interface"
2+
import { ICollections, IIdentify, IProfile, IReleases, IReleaseSet, VinylAPIImageMap } from "./interface"
33

44
const API_URL = "https://api.discogs.com"
55

@@ -29,172 +29,105 @@ export const getProfile = async (username: string, password: string): Promise<IP
2929
return response.json()
3030
}
3131

32-
export const getCollectionWants = async (
32+
export const getCollectionAndWants = async (
3333
username: string,
3434
password: string,
3535
imageQuality: boolean,
3636
onProgress?: (page: number, pages: number) => void
37-
): Promise<IReleases[]> => {
38-
let allReleases: IReleases[] = []
39-
let url: string | undefined = `${API_URL}/users/${username}/wants?per_page=100`
37+
): Promise<IReleaseSet> => {
4038
const vinylURL = import.meta.env.VITE_VINYL_API_URL
41-
42-
while (url) {
43-
const response = await fetch(url, {
44-
headers: {
45-
"Content-Type": "application/json",
46-
Authorization: `Discogs token=${password}`,
47-
},
48-
})
49-
50-
if (!response.ok) {
51-
throw new Error("Network response was not ok")
52-
}
53-
54-
const data: ICollections = await response.json()
55-
56-
let imageMap: Record<number, VinylAPIImageMap> = {}
57-
if (vinylURL && vinylURL !== "") {
58-
try {
59-
const secondaryResponse = await fetch(`${vinylURL}/api/queue`, {
60-
method: "POST",
61-
headers: {
62-
"Content-Type": "application/json",
63-
},
64-
// @ts-expect-error Cheating a bit - converting the reference to keep the same models.
65-
body: JSON.stringify(data.wants.map((item) => item.basic_information.id) ?? []),
66-
})
67-
68-
if (secondaryResponse.ok) {
69-
const imageData = await secondaryResponse.json()
70-
71-
imageMap = imageData.available.reduce((acc: Record<number, VinylAPIImageMap>, record: any) => {
72-
acc[record.recordID] = {
73-
image: record.image,
74-
imageHigh: record.imageHigh,
75-
barcode: record.barcode,
76-
}
77-
return acc
78-
}, {})
79-
} else {
80-
console.warn("Vinyl API response was not ok, skipping.")
81-
}
82-
} catch (error) {
83-
console.error("Vinyl API response hit an error, skipping.", error)
39+
40+
const fetchReleases = async (
41+
url: string,
42+
releaseType: 'collection' | 'wants'
43+
): Promise<IReleases[]> => {
44+
let allReleases: IReleases[] = []
45+
while (url) {
46+
const response = await fetch(url, {
47+
headers: {
48+
"Content-Type": "application/json",
49+
Authorization: `Discogs token=${password}`,
50+
},
51+
})
52+
53+
if (!response.ok) {
54+
throw new Error("Network response was not ok")
8455
}
85-
}
8656

87-
// @ts-expect-error Cheating a bit - converting the reference to keep the same models.
88-
const releasesExtraData = data.wants.map((release) => {
89-
const imageRecord = imageMap[release.basic_information.id] || {
90-
image: null,
91-
imageHigh: null,
92-
barcode: null,
93-
}
94-
return {
95-
...release,
96-
image_base64: imageQuality
97-
? !isNullOrBlank(imageRecord.imageHigh)
98-
? imageRecord.imageHigh
99-
: imageRecord.image
100-
: imageRecord.image,
101-
barcode: imageRecord.barcode,
57+
const data: ICollections = await response.json()
58+
59+
let imageMap: Record<number, VinylAPIImageMap> = {}
60+
if (vinylURL && vinylURL !== "") {
61+
try {
62+
const secondaryResponse = await fetch(`${vinylURL}/api/queue`, {
63+
method: "POST",
64+
headers: {
65+
"Content-Type": "application/json",
66+
},
67+
body: JSON.stringify(
68+
// @ts-expect-error Cheating a bit - converting the reference to keep the same models.
69+
(releaseType === 'wants' ? data.wants : data.releases).map((item) => item.basic_information.id) ?? []
70+
),
71+
})
72+
73+
if (secondaryResponse.ok) {
74+
const imageData = await secondaryResponse.json()
75+
76+
imageMap = imageData.available.reduce((acc: Record<number, VinylAPIImageMap>, record: any) => {
77+
acc[record.recordID] = {
78+
image: record.image,
79+
imageHigh: record.imageHigh,
80+
barcode: record.barcode,
81+
}
82+
return acc
83+
}, {})
84+
} else {
85+
console.warn("Vinyl API response was not ok, skipping.")
86+
}
87+
} catch (error) {
88+
console.error("Vinyl API response hit an error, skipping.", error)
89+
}
10290
}
103-
})
104-
105-
allReleases = [...allReleases, ...releasesExtraData]
106-
107-
if (onProgress) {
108-
onProgress(data.pagination.page, data.pagination.pages)
109-
}
110-
111-
// Set the url to the next page, or undefined if there are no more pages
112-
url = data.pagination.urls.next
113-
}
114-
115-
return allReleases
116-
}
117-
118-
export const getCollectionReleases = async (
119-
username: string,
120-
password: string,
121-
imageQuality: boolean,
122-
onProgress?: (page: number, pages: number) => void
123-
): Promise<IReleases[]> => {
124-
let allReleases: IReleases[] = []
125-
let url: string | undefined = `${API_URL}/users/${username}/collection/folders/0/releases?per_page=100`
126-
const vinylURL = import.meta.env.VITE_VINYL_API_URL
127-
128-
while (url) {
129-
const response = await fetch(url, {
130-
headers: {
131-
"Content-Type": "application/json",
132-
Authorization: `Discogs token=${password}`,
133-
},
134-
})
135-
136-
if (!response.ok) {
137-
throw new Error("Network response was not ok")
138-
}
13991

140-
const data: ICollections = await response.json()
141-
142-
let imageMap: Record<number, VinylAPIImageMap> = {}
143-
if (vinylURL && vinylURL !== "") {
144-
try {
145-
const secondaryResponse = await fetch(`${vinylURL}/api/queue`, {
146-
method: "POST",
147-
headers: {
148-
"Content-Type": "application/json",
149-
},
150-
body: JSON.stringify(data.releases.map((item) => item.basic_information.id) ?? []),
151-
})
152-
153-
if (secondaryResponse.ok) {
154-
const imageData = await secondaryResponse.json()
155-
156-
imageMap = imageData.available.reduce((acc: Record<number, VinylAPIImageMap>, record: any) => {
157-
acc[record.recordID] = {
158-
image: record.image,
159-
imageHigh: record.imageHigh,
160-
barcode: record.barcode,
161-
}
162-
return acc
163-
}, {})
164-
} else {
165-
console.warn("Vinyl API response was not ok, skipping.")
92+
// @ts-expect-error Cheating a bit - converting the reference to keep the same models.
93+
const releasesExtraData = (releaseType === 'wants' ? data.wants : data.releases).map((release) => {
94+
const imageRecord = imageMap[release.basic_information.id] || {
95+
image: null,
96+
imageHigh: null,
97+
barcode: null,
16698
}
167-
} catch (error) {
168-
console.error("Vinyl API response hit an error, skipping.", error)
169-
}
170-
}
99+
return {
100+
...release,
101+
image_base64: imageQuality
102+
? !isNullOrBlank(imageRecord.imageHigh)
103+
? imageRecord.imageHigh
104+
: imageRecord.image
105+
: imageRecord.image,
106+
barcode: imageRecord.barcode,
107+
}
108+
})
171109

172-
const releasesExtraData = data.releases.map((release) => {
173-
const imageRecord = imageMap[release.basic_information.id] || {
174-
image: null,
175-
imageHigh: null,
176-
barcode: null,
177-
}
178-
return {
179-
...release,
180-
image_base64: imageQuality
181-
? !isNullOrBlank(imageRecord.imageHigh)
182-
? imageRecord.imageHigh
183-
: imageRecord.image
184-
: imageRecord.image,
185-
barcode: imageRecord.barcode,
186-
}
187-
})
110+
allReleases = [...allReleases, ...releasesExtraData]
188111

189-
allReleases = [...allReleases, ...(releasesExtraData as IReleases[])]
112+
if (onProgress) {
113+
onProgress(data.pagination.page, data.pagination.pages)
114+
}
190115

191-
if (onProgress) {
192-
onProgress(data.pagination.page, data.pagination.pages)
116+
// @ts-expect-error not sure?
117+
url = data.pagination.urls.next
193118
}
194119

195-
// Set the url to the next page, or undefined if there are no more pages
196-
url = data.pagination.urls.next
120+
return allReleases
197121
}
198122

199-
return allReleases
123+
// Fetch wants and collection in parallel
124+
const [wantsReleases, collectionReleases] = await Promise.all([
125+
fetchReleases(`${API_URL}/users/${username}/wants?per_page=100`, 'wants'),
126+
fetchReleases(`${API_URL}/users/${username}/collection/folders/0/releases?per_page=100`, 'collection'),
127+
])
128+
129+
return {
130+
collection: collectionReleases,
131+
wants: wantsReleases,
132+
}
200133
}

frontend/src/api/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
export { getCollectionReleases, getCollectionWants, getMe, getProfile } from "./discogs"
1+
export { getCollectionAndWants, getMe, getProfile } from "./discogs"
22
export type {
33
ICollections,
44
IWants,
55
IIdentify,
66
IProfile,
77
IPagination,
88
IReleases,
9+
IReleaseSet,
910
IVinylResponse,
1011
IAvailableItem,
1112
VinylAPIImageMap,

frontend/src/api/interface.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,11 @@ export interface IReleases {
6161
barcode?: string
6262
}
6363

64+
export interface IReleaseSet {
65+
collection: IReleases[]
66+
wants: IReleases[]
67+
}
68+
6469
export interface ICollections {
6570
pagination: IPagination
6671
releases: IReleases[]

frontend/src/pages/Collection.tsx

Lines changed: 13 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import {
1818
} from "@ionic/react"
1919
import { useQuery, useQueryClient } from "@tanstack/react-query"
2020
import { filterOutline, personOutline, pricetagOutline, timeOutline, listOutline, gridOutline } from "ionicons/icons"
21-
import { IReleases, getCollectionReleases, getCollectionWants } from "../api"
21+
import { IReleaseSet, IReleases, getCollectionAndWants } from "../api"
2222
import { FullpageLoading, AlbumGrid, FullpageInfo, AlbumListGroups } from "../components"
2323
import { ViewAlbumDetails } from "../modal"
2424
import { useAuth, useSettings } from "../hooks"
@@ -74,7 +74,7 @@ const CollectionPage: React.FC = () => {
7474
}>()
7575
const betaBanner = import.meta.env.VITE_BETA_BANNER
7676

77-
const [{ username, token }, saveAuth, clearAuth] = useAuth()
77+
const [{ username, token }] = useAuth()
7878

7979
const getFilterIcon = (filter: string) => {
8080
switch (filter) {
@@ -112,45 +112,36 @@ const CollectionPage: React.FC = () => {
112112

113113
const handleRefresh = async (event: CustomEvent<RefresherEventDetail>) => {
114114
await queryClient.invalidateQueries({
115-
queryKey: [`${username}collection`, `${username}want`],
115+
queryKey: [`${username}collectionv2`],
116116
})
117117
event.detail.complete()
118118
}
119119

120-
const collectionData = useQuery<IReleases[]>({
121-
queryKey: [`${username}collection`],
120+
const { isLoading, isError, data } = useQuery<IReleaseSet>({
121+
queryKey: [`${username}collectionv2`],
122122
queryFn: () =>
123-
getCollectionReleases(username, token ?? "", imageQuality, (page, pages) =>
124-
setLoading({ page: page, pages: pages })
125-
),
126-
staleTime: Infinity,
127-
})
128-
129-
const wantData = useQuery<IReleases[]>({
130-
queryKey: [`${username}want`],
131-
queryFn: () =>
132-
getCollectionWants(username, token ?? "", imageQuality, (page, pages) =>
123+
getCollectionAndWants(username, token ?? "", imageQuality, (page, pages) =>
133124
setLoading({ page: page, pages: pages })
134125
),
135126
staleTime: Infinity,
136127
})
137128

138129
useEffect(() => {
139130
setDataSorted({
140-
collected: masterSort(filter, collectionData.data ?? []),
141-
wanted: masterSort(filter, wantData.data ?? []),
131+
collected: masterSort(filter, data?.collection ?? []),
132+
wanted: masterSort(filter, data?.wants ?? []),
142133
})
143-
}, [filter, collectionData.data, wantData.data])
134+
}, [filter, data])
144135

145-
if (collectionData.isLoading || wantData.isLoading) {
136+
if (isLoading) {
146137
return (
147138
<IonPage>
148139
<FullpageLoading loadingProgress={loading.page + 1} loadingComplete={loading.pages} />
149140
</IonPage>
150141
)
151142
}
152143

153-
if (collectionData.isError || wantData.isError) {
144+
if (isError) {
154145
return (
155146
<IonPage>
156147
<FullpageInfo text="An error occurred when loading information." />
@@ -219,7 +210,7 @@ const CollectionPage: React.FC = () => {
219210
<IonRefresher slot="fixed" onIonRefresh={handleRefresh}>
220211
<IonRefresherContent></IonRefresherContent>
221212
</IonRefresher>
222-
{viewState === "collection" && collectionData.data && dataSorted && (
213+
{viewState === "collection" && data && dataSorted && (
223214
<>
224215
{layout === "grid" ? (
225216
<AlbumGrid data={dataSorted?.collected} onClickAlbum={(album) => setModalInfo(album)} />
@@ -232,7 +223,7 @@ const CollectionPage: React.FC = () => {
232223
</>
233224
)}
234225

235-
{viewState === "want" && wantData.data && dataSorted && (
226+
{viewState === "want" && data && dataSorted && (
236227
<>
237228
{layout === "grid" ? (
238229
<AlbumGrid data={dataSorted?.wanted} onClickAlbum={(album) => setModalInfo(album)} />

0 commit comments

Comments
 (0)