Skip to content

Commit 1f69077

Browse files
committed
fix: dedupe api calls
1 parent e265f88 commit 1f69077

5 files changed

Lines changed: 59 additions & 21 deletions

File tree

lib/Controller/ChecklistController.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -412,8 +412,8 @@ public function reorderItems(int $houseId, int $listId, array $items = []): Data
412412
/**
413413
* Upload an image for an item
414414
*
415-
* Uploads the request body as an image into the user's configured pantry
416-
* image folder and attaches it to the item.
415+
* Expects a multipart/form-data request with the image file in a field
416+
* named **image**.
417417
*
418418
* @param int $houseId House id.
419419
* @param int $listId List id.

lib/Controller/PhotoController.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,10 @@ public function indexPhotos(int $houseId, string $sortBy = 'custom', int $limit
193193
/**
194194
* Upload a photo
195195
*
196+
* Expects a multipart/form-data request with the image file in a field
197+
* named **image**. The optional folderId and caption may be sent as
198+
* additional form fields.
199+
*
196200
* @param int $houseId House id.
197201
* @param int|null $folderId Optional folder id to place the photo in.
198202
* @param string|null $caption Optional caption.

openapi.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2509,7 +2509,7 @@
25092509
"post": {
25102510
"operationId": "checklist-upload-item-image",
25112511
"summary": "Upload an image for an item",
2512-
"description": "Uploads the request body as an image into the user's configured pantry image folder and attaches it to the item.",
2512+
"description": "Expects a multipart/form-data request with the image file in a field named **image**.",
25132513
"tags": [
25142514
"checklist"
25152515
],
@@ -5576,6 +5576,7 @@
55765576
"post": {
55775577
"operationId": "photo-upload-photo",
55785578
"summary": "Upload a photo",
5579+
"description": "Expects a multipart/form-data request with the image file in a field named **image**. The optional folderId and caption may be sent as additional form fields.",
55795580
"tags": [
55805581
"photo"
55815582
],

src/api/prefs.ts

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,19 @@ export interface UserPrefs {
88
firstDayOfWeek: number
99
}
1010

11-
export async function getUserPrefs(): Promise<UserPrefs> {
12-
const resp = await ocs.get<UserPrefs>('/prefs')
13-
return resp.data ?? { lastHouseId: null, firstDayOfWeek: 1 }
11+
let userPrefsInflight: Promise<UserPrefs> | null = null
12+
13+
export function getUserPrefs(): Promise<UserPrefs> {
14+
if (userPrefsInflight) return userPrefsInflight
15+
16+
userPrefsInflight = ocs
17+
.get<UserPrefs>('/prefs')
18+
.then((resp) => resp.data ?? { lastHouseId: null, firstDayOfWeek: 1 })
19+
.finally(() => {
20+
userPrefsInflight = null
21+
})
22+
23+
return userPrefsInflight
1424
}
1525

1626
export async function setUserPrefs(patch: Partial<UserPrefs>): Promise<UserPrefs> {
@@ -70,15 +80,27 @@ const housePrefsDefaults: HousePrefs = {
7080
notifyItemDone: true,
7181
}
7282

73-
export async function getHousePrefs(houseId: number): Promise<HousePrefs> {
74-
const resp = await ocs.get<HousePrefs>(`/houses/${houseId}/prefs`)
75-
return { ...housePrefsDefaults, ...resp.data }
83+
// Deduplicate concurrent getHousePrefs calls for the same house.
84+
const housePrefsInflight = new Map<number, Promise<HousePrefs>>()
85+
86+
export function getHousePrefs(houseId: number): Promise<HousePrefs> {
87+
const existing = housePrefsInflight.get(houseId)
88+
if (existing) return existing
89+
90+
const promise = ocs
91+
.get<HousePrefs>(`/houses/${houseId}/prefs`)
92+
.then((resp) => ({ ...housePrefsDefaults, ...resp.data }))
93+
.finally(() => housePrefsInflight.delete(houseId))
94+
95+
housePrefsInflight.set(houseId, promise)
96+
return promise
7697
}
7798

7899
export async function setHousePrefs(
79100
houseId: number,
80101
patch: Partial<HousePrefs>,
81102
): Promise<HousePrefs> {
103+
housePrefsInflight.delete(houseId)
82104
const resp = await ocs.put<HousePrefs>(`/houses/${houseId}/prefs`, patch)
83105
return { ...housePrefsDefaults, ...resp.data }
84106
}

src/composables/useHouses.ts

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,31 @@ const loaded = ref(false)
77
const loading = ref(false)
88
const error = ref<string | null>(null)
99

10-
async function load(force = false): Promise<House[]> {
11-
if (loaded.value && !force) return houses.value
10+
let inflight: Promise<House[]> | null = null
11+
12+
function load(force = false): Promise<House[]> {
13+
if (loaded.value && !force) return Promise.resolve(houses.value)
14+
if (inflight && !force) return inflight
15+
1216
loading.value = true
1317
error.value = null
14-
try {
15-
houses.value = await api.listHouses()
16-
loaded.value = true
17-
} catch (e) {
18-
error.value = (e as Error).message
19-
throw e
20-
} finally {
21-
loading.value = false
22-
}
23-
return houses.value
18+
inflight = api
19+
.listHouses()
20+
.then((result) => {
21+
houses.value = result
22+
loaded.value = true
23+
return result
24+
})
25+
.catch((e) => {
26+
error.value = (e as Error).message
27+
throw e
28+
})
29+
.finally(() => {
30+
loading.value = false
31+
inflight = null
32+
})
33+
34+
return inflight
2435
}
2536

2637
async function create(name: string, description?: string | null): Promise<House> {

0 commit comments

Comments
 (0)