| 130 | } |
| 131 | |
| 132 | export function useRuntimeLabProgramProgress(programId: string) { |
| 133 | const { authenticated, ready } = useAuth(); |
| 134 | const enabled = ready && authenticated; |
| 135 | const key = detailKey(enabled, programId); |
| 136 | |
| 137 | const swr = useSWR< |
| 138 | RuntimeLabProgressDetailResponse, |
| 139 | Error & { status?: number }, |
| 140 | RuntimeLabProgressDetailKey | null |
| 141 | >( |
| 142 | key, |
| 143 | ([, id]) => |
| 144 | fetchJson<RuntimeLabProgressDetailResponse>( |
| 145 | `/api/tools/runtime-lab/progress?${new URLSearchParams({ programId: id })}` |
| 146 | ), |
| 147 | swrOptions |
| 148 | ); |
| 149 | |
| 150 | const saveProgress = useCallback( |
| 151 | async (progress: RuntimeLabProgress) => { |
| 152 | const detailCacheKey = detailKey(true, progress.programId); |
| 153 | |
| 154 | const saveRequest = authFetch("/api/tools/runtime-lab/progress", { |
| 155 | method: "PUT", |
| 156 | body: JSON.stringify(progress), |
| 157 | }).then(async (response) => { |
| 158 | if (!response.ok) { |
| 159 | throw new Error(`runtime lab progress save failed with status ${response.status}`); |
| 160 | } |
| 161 | return response.json() as Promise<RuntimeLabProgressDetailResponse>; |
| 162 | }); |
| 163 | |
| 164 | const nextDetail = await globalMutate(detailCacheKey, saveRequest, { |
| 165 | optimisticData: (current?: RuntimeLabProgressDetailResponse) => ({ |
| 166 | userId: current?.userId ?? "", |
| 167 | progress, |
| 168 | }), |
| 169 | rollbackOnError: true, |
| 170 | populateCache: true, |
| 171 | revalidate: false, |
| 172 | }); |
| 173 | |
| 174 | if (nextDetail?.progress) { |
| 175 | await globalMutate( |
| 176 | listKey(true), |
| 177 | (current?: RuntimeLabProgressListResponse) => ({ |
| 178 | userId: current?.userId ?? nextDetail.userId, |
| 179 | progress: { |
| 180 | ...(current?.progress ?? {}), |
| 181 | [nextDetail.progress!.programId]: nextDetail.progress!, |
| 182 | }, |
| 183 | }), |
| 184 | { revalidate: false } |
| 185 | ); |
| 186 | } |
| 187 | |
| 188 | return nextDetail; |
| 189 | }, |