Skip to content

Commit fd98f6e

Browse files
committed
fix: problem list
1 parent f59eecc commit fd98f6e

File tree

4 files changed

+98
-57
lines changed

4 files changed

+98
-57
lines changed

atcoder-problems-frontend/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@
6464
"reactstrap": "8.2.0",
6565
"recharts": "2.0.0-beta.1",
6666
"sass": "1.37.0",
67-
"swr": "0.5.3"
67+
"swr": "1.3.0"
6868
},
6969
"devDependencies": {
7070
"@types/jest": "27.4.1",
@@ -96,4 +96,4 @@
9696
"sort-package-json": "1.42.2",
9797
"typescript": "3.7.3"
9898
}
99-
}
99+
}

atcoder-problems-frontend/src/api/APIClient.ts

Lines changed: 90 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { useMemo } from "react";
2+
import useSWR from "swr";
13
import { fetchSubmissionsFromDatabaseAndServer } from "../database/SubmissionsDB";
24
import Contest, { isContest } from "../interfaces/Contest";
35
import { isContestParticipation } from "../interfaces/ContestParticipation";
@@ -15,9 +17,9 @@ import { isSubmission } from "../interfaces/Submission";
1517
import { isUserRankEntry, UserRankEntry } from "../interfaces/UserRankEntry";
1618
import { clipDifficulty, isValidResult } from "../utils";
1719
import { toChunks } from "../utils/Chunk";
20+
import { classifyContest } from "../utils/ContestClassifier";
1821
import { ratingInfoOf } from "../utils/RatingInfo";
1922
import { hasPropertyAsType, isString } from "../utils/TypeUtils";
20-
import { useSWRData } from "./index";
2123

2224
const STATIC_API_BASE_URL = "https://kenkoooo.com/atcoder/resources";
2325
const PROXY_API_URL = "https://kenkoooo.com/atcoder/proxy";
@@ -65,9 +67,7 @@ function fetchTypedArray<T>(
6567
}
6668

6769
const useRankingV3 = (url: string) => {
68-
return useSWRData(url, (u) =>
69-
fetchTypedArray<RankingEntry>(u, isRankingEntry)
70-
);
70+
return useSWR(url, (u) => fetchTypedArray<RankingEntry>(u, isRankingEntry));
7171
};
7272

7373
export const useACRanking = (from: number, to: number) => {
@@ -79,7 +79,7 @@ export const useUserACRank = (user: string) => {
7979
const url = `${ATCODER_API_URL}/v3/user/ac_rank?user=${encodeURIComponent(
8080
user
8181
)}`;
82-
return useSWRData(url, (url) =>
82+
return useSWR(url, (url) =>
8383
fetchTypedValue<UserRankEntry>(url, isUserRankEntry)
8484
);
8585
};
@@ -93,7 +93,7 @@ export const useUserStreakRank = (user: string) => {
9393
const url = `${ATCODER_API_URL}/v3/user/streak_rank?user=${encodeURIComponent(
9494
user
9595
)}`;
96-
return useSWRData(url, (url) =>
96+
return useSWR(url, (url) =>
9797
fetchTypedValue<UserRankEntry>(url, isUserRankEntry)
9898
);
9999
};
@@ -107,26 +107,40 @@ export const useUserSumRank = (user: string) => {
107107
const url = `${ATCODER_API_URL}/v3/user/rated_point_sum_rank?user=${encodeURIComponent(
108108
user
109109
)}`;
110-
return useSWRData(url, (url) =>
110+
return useSWR(url, (url) =>
111111
fetchTypedValue<UserRankEntry>(url, isUserRankEntry)
112112
);
113113
};
114114

115115
export const useMergedProblemMap = () => {
116+
const fetcher = (url: string) => fetchTypedArray(url, isMergedProblem);
116117
const url = STATIC_API_BASE_URL + "/merged-problems.json";
117-
return useSWRData(url, (url) =>
118-
fetchTypedArray(url, isMergedProblem).then((problems) =>
119-
problems.reduce((map, problem) => {
118+
const problems = useSWR(url, fetcher);
119+
const contests = useContestMap();
120+
121+
const map = useMemo(() => {
122+
const map = new Map<ProblemId, MergedProblem>();
123+
problems.data?.forEach((problem) => {
124+
const contest = contests?.get(problem.contest_id);
125+
if (!contest) {
126+
return;
127+
}
128+
129+
const contestType = classifyContest(contest);
130+
if (contestType === "AHC") {
131+
map.set(problem.id, { ...problem, point: undefined });
132+
} else {
120133
map.set(problem.id, problem);
121-
return map;
122-
}, new Map<ProblemId, MergedProblem>())
123-
)
124-
);
134+
}
135+
});
136+
return map;
137+
}, [contests, problems]);
138+
return { data: map };
125139
};
126140

127141
export const useLangList = () => {
128142
const url = `${ATCODER_API_URL}/v3/language_list`;
129-
return useSWRData(url, (url) => fetchTypedArray(url, isString));
143+
return useSWR(url, (url) => fetchTypedArray(url, isString));
130144
};
131145

132146
export const useOneLangRanking = (
@@ -156,8 +170,8 @@ export const useFirstRanking = () => {
156170
export const useRatingInfo = (user: string) => {
157171
const url = `${PROXY_API_URL}/users/${user}/history/json`;
158172
const history =
159-
useSWRData(url, (url) => fetchTypedArray(url, isContestParticipation))
160-
?.data ?? [];
173+
useSWR(url, (url) => fetchTypedArray(url, isContestParticipation))?.data ??
174+
[];
161175
return ratingInfoOf(history);
162176
};
163177

@@ -171,26 +185,24 @@ export const useMultipleUserSubmissions = (userIds: UserId[]) => {
171185
const arrays = await Promise.all(promises);
172186
return arrays.flat();
173187
};
174-
const users = userIds.join(",");
175-
return useSWRData(`multiple-user-submission ${users}`, (s) => {
176-
const users = s.split(" ")[1];
177-
return fetcher(users.split(","));
178-
});
188+
return useSWR({ key: "multiple-user-submission", userIds }, ({ userIds }) =>
189+
fetcher(userIds)
190+
);
179191
};
180192

181193
export const useContests = () => {
182194
const url = STATIC_API_BASE_URL + "/contests.json";
183-
return useSWRData(url, (url) => fetchTypedArray(url, isContest));
195+
return useSWR(url, (url) => fetchTypedArray(url, isContest));
184196
};
185197

186198
export const useProblems = () => {
187199
const url = STATIC_API_BASE_URL + "/problems.json";
188-
return useSWRData(url, (url) => fetchTypedArray(url, isProblem)).data;
200+
return useSWR(url, (url) => fetchTypedArray(url, isProblem)).data;
189201
};
190202

191203
const useContestProblemList = () => {
192204
const url = STATIC_API_BASE_URL + "/contest-problem.json";
193-
return useSWRData(url, (url) =>
205+
return useSWR(url, (url) =>
194206
fetchTypedArray(
195207
url,
196208
(
@@ -258,29 +270,58 @@ export const useProblemMap = () => {
258270
};
259271

260272
export const useProblemModelMap = () => {
261-
const fetcher = (url: string) =>
262-
fetch(url)
263-
.then((r) => r.json())
264-
.then((obj: { [p: string]: unknown }) =>
265-
Object.entries(obj)
266-
.filter((entry): entry is [string, ProblemModel] =>
267-
isProblemModel(entry[1])
268-
)
269-
.reduce((map, [problemId, problemModel]) => {
270-
if (problemModel.difficulty === undefined) {
271-
map.set(problemId, problemModel);
272-
} else {
273-
map.set(problemId, {
274-
...problemModel,
275-
difficulty: clipDifficulty(problemModel.difficulty),
276-
rawDifficulty: problemModel.difficulty,
277-
});
278-
}
279-
return map;
280-
}, new Map<ProblemId, ProblemModel>())
281-
);
273+
const fetcher = async (url: string) => {
274+
const response = await fetch(url);
275+
const result: unknown = await response.json();
276+
if (typeof result !== "object" || !result) {
277+
return [] as { problemId: ProblemId; model: ProblemModel }[];
278+
}
279+
280+
const models = [] as { problemId: ProblemId; model: ProblemModel }[];
281+
Object.entries(result).forEach(([key, value]) => {
282+
if (isProblemModel(value)) {
283+
models.push({ problemId: key, model: value });
284+
}
285+
});
286+
return models;
287+
};
288+
282289
const url = STATIC_API_BASE_URL + "/problem-models.json";
283-
return useSWRData(url, fetcher).data;
290+
const problemModels = useSWR(url, fetcher);
291+
const contests = useContestMap();
292+
const problems = useProblemMap();
293+
294+
const modelMap = useMemo(() => {
295+
const map = new Map<ProblemId, ProblemModel>();
296+
problemModels.data?.forEach(({ problemId, model }) => {
297+
const problem = problems?.get(problemId);
298+
if (!problem) {
299+
return;
300+
}
301+
const contest = contests?.get(problem.contest_id);
302+
if (!contest) {
303+
return;
304+
}
305+
const contestType = classifyContest(contest);
306+
if (contestType === "AHC") {
307+
return;
308+
}
309+
310+
if (model.difficulty === undefined) {
311+
map.set(problemId, model);
312+
} else {
313+
map.set(problemId, {
314+
...model,
315+
difficulty: clipDifficulty(model.difficulty),
316+
rawDifficulty: model.difficulty,
317+
});
318+
}
319+
});
320+
321+
return map;
322+
}, [problemModels, problems, contests]);
323+
324+
return modelMap;
284325
};
285326

286327
export const useVirtualContestSubmissions = (
@@ -348,10 +389,10 @@ export const useVirtualContestSubmissions = (
348389
: 1_000_000_000;
349390

350391
const customKey = serialize(users, problems);
351-
return useSWRData(customKey, fetcher, { refreshInterval });
392+
return useSWR(customKey, fetcher, { refreshInterval });
352393
};
353394

354395
export const useRecentSubmissions = () => {
355396
const url = `${ATCODER_API_URL}/v3/recent`;
356-
return useSWRData(url, (url) => fetchTypedArray(url, isSubmission));
397+
return useSWR(url, (url) => fetchTypedArray(url, isSubmission));
357398
};

atcoder-problems-frontend/src/pages/Internal/VirtualContest/ShowContest/index.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -445,7 +445,7 @@ export const ShowContest = (props: Props) => {
445445
<Button
446446
onClick={async () => {
447447
await joinContest(props.contestId);
448-
await virtualContestResponse.revalidate();
448+
await virtualContestResponse.mutate();
449449
}}
450450
>
451451
Join
@@ -455,7 +455,7 @@ export const ShowContest = (props: Props) => {
455455
<Button
456456
onClick={async () => {
457457
await leaveContest(props.contestId);
458-
await virtualContestResponse.revalidate();
458+
await virtualContestResponse.mutate();
459459
}}
460460
>
461461
Leave

atcoder-problems-frontend/yarn.lock

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12298,10 +12298,10 @@ svgo@^1.0.0, svgo@^1.2.2:
1229812298
unquote "~1.1.1"
1229912299
util.promisify "~1.0.0"
1230012300

12301-
swr@0.5.3:
12302-
version "0.5.3"
12303-
resolved "https://registry.yarnpkg.com/swr/-/swr-0.5.3.tgz#7290a9a61329d930583ef365317e636b8dbaa8bb"
12304-
integrity sha512-RUE3RWn3jt9e4qLPat2A9vbHG/5N6konsc27xKjE65jFSiGv0P7HLD8IGvwAv6DRKktL7Od2UcayX0plKb2awg==
12301+
swr@1.3.0:
12302+
version "1.3.0"
12303+
resolved "https://registry.yarnpkg.com/swr/-/swr-1.3.0.tgz#c6531866a35b4db37b38b72c45a63171faf9f4e8"
12304+
integrity sha512-dkghQrOl2ORX9HYrMDtPa7LTVHJjCTeZoB1dqTbnnEDlSvN8JEKpYIYurDfvbQFUUS8Cg8PceFVZNkW0KNNYPw==
1230512305

1230612306
symbol-observable@^1.1.0:
1230712307
version "1.2.0"

0 commit comments

Comments
 (0)