Skip to content

Commit 38b1e67

Browse files
river0525claude
andcommitted
feat(workbooks): enable voting from grade icons on workbook detail page
Replace GradeLabel with VotableGrade so users can vote directly from the grade icon on the workbook detail page. Fetches vote statistics in parallel with task results and adds the voteAbsoluteGrade form action. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 2abae1a commit 38b1e67

2 files changed

Lines changed: 20 additions & 11 deletions

File tree

src/routes/workbooks/[slug]/+page.server.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import type { TaskResult } from '$lib/types/task';
66
import * as taskResultsCrud from '$lib/services/task_results';
77
import { getWorkbookWithAuthor } from '$features/workbooks/services/workbooks';
88
import * as action from '$lib/actions/update_task_result';
9+
import { getVoteGradeStatistics } from '$features/votes/services/vote_statistics';
10+
import { voteAbsoluteGrade as voteAbsoluteGradeAction } from '$features/votes/actions/vote_actions';
911

1012
import { isAdmin, canRead } from '$lib/utils/authorship';
1113
import { getLoggedInUser } from '$features/auth/services/session';
@@ -36,16 +38,18 @@ export async function load({ locals, params, url }) {
3638
error(FORBIDDEN, `問題集id: ${slug} にアクセスする権限がありません。`);
3739
}
3840

39-
const taskResults: Map<string, TaskResult> = await taskResultsCrud.getTaskResultsByTaskId(
40-
workBook.workBookTasks,
41-
loggedInUser?.id as string,
42-
);
41+
const [taskResults, voteStatisticsMap] = await Promise.all([
42+
taskResultsCrud.getTaskResultsByTaskId(workBook.workBookTasks, loggedInUser?.id as string),
43+
getVoteGradeStatistics(),
44+
]);
4345

4446
return {
4547
isLoggedIn: loggedInUser !== null,
48+
isAtCoderVerified: locals.user?.is_validated === true,
4649
loggedInAsAdmin: loggedInAsAdmin,
4750
...workbookWithAuthor,
4851
taskResults: taskResults,
52+
voteStatisticsMap: voteStatisticsMap,
4953
};
5054
}
5155

@@ -54,4 +58,7 @@ export const actions = {
5458
const operationLog = 'workbook -> actions -> update';
5559
return await action.updateTaskResult({ request, locals }, operationLog);
5660
},
61+
voteAbsoluteGrade: async ({ request, locals }) => {
62+
return await voteAbsoluteGradeAction({ request, locals });
63+
},
5764
} satisfies Actions;

src/routes/workbooks/[slug]/+page.svelte

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@
1414
import HeadingOne from '$lib/components/HeadingOne.svelte';
1515
import UpdatingModal from '$lib/components/SubmissionStatus/UpdatingModal.svelte';
1616
import SubmissionStatusImage from '$lib/components/SubmissionStatus/SubmissionStatusImage.svelte';
17-
import GradeLabel from '$lib/components/GradeLabel.svelte';
1817
import ExternalLinkWrapper from '$lib/components/ExternalLinkWrapper.svelte';
18+
import VotableGrade from '$features/votes/components/VotableGrade.svelte';
1919
import PublicationStatusLabel from '$features/workbooks/components/shared/PublicationStatusLabel.svelte';
2020
import CommentAndHint from '$features/workbooks/components/detail/CommentAndHint.svelte';
2121
@@ -24,7 +24,6 @@
2424
import { addContestNameToTaskIndex } from '$lib/utils/contest';
2525
import { getTaskUrl, removeTaskIndexFromTitle } from '$lib/utils/task';
2626
27-
import { TaskGrade } from '$lib/types/task';
2827
import type { TaskResult } from '$lib/types/task';
2928
import type { WorkBookTaskBase } from '$features/workbooks/types/workbook';
3029
@@ -33,18 +32,16 @@
3332
let workBook = data.workBook;
3433
let workBookTasks: WorkBookTaskBase[] = $state([]);
3534
let taskResults: Map<string, TaskResult> = $derived(data.taskResults);
35+
let voteStatisticsMap = $derived(data.voteStatisticsMap);
3636
3737
let isLoggedIn = data.isLoggedIn;
38+
let isAtCoderVerified = $derived(data.isAtCoderVerified);
3839
3940
// TODO: 関数をutilへ移動させる
4041
const getTaskResult = (taskId: string): TaskResult => {
4142
return taskResults?.get(taskId) as TaskResult;
4243
};
4344
44-
const getTaskGrade = (taskId: string): TaskGrade => {
45-
return getTaskResult(taskId)?.grade ?? TaskGrade.PENDING;
46-
};
47-
4845
const getContestIdFrom = (taskId: string): string => {
4946
return getTaskResult(taskId)?.contest_id as string;
5047
};
@@ -164,7 +161,12 @@
164161
<!-- 問題のグレード -->
165162
<TableBodyCell class="justify-center w-16 px-0.5 xs:px-3">
166163
<div class="flex items-center justify-center min-w-[54px] max-w-[54px]">
167-
<GradeLabel taskGrade={getTaskGrade(workBookTask.taskId)} />
164+
<VotableGrade
165+
taskResult={getTaskResult(workBookTask.taskId)}
166+
{isLoggedIn}
167+
{isAtCoderVerified}
168+
estimatedGrade={voteStatisticsMap?.get(workBookTask.taskId)?.grade ?? null}
169+
/>
168170
</div>
169171
</TableBodyCell>
170172

0 commit comments

Comments
 (0)