Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { useMutation, useQueryClient } from '@tanstack/react-query';

import { type paths } from '@schema';
import { client, TanstackQueryClient } from '@/apis/client';

type UpdateStudyHandwritingRequest =
paths['/api/student/study/problem/{publishId}/{problemId}/handwriting']['put']['requestBody']['content']['application/json'];
type UpdateStudyHandwritingResponse =
paths['/api/student/study/problem/{publishId}/{problemId}/handwriting']['put']['responses']['200']['content']['*/*'];

interface UpdateStudyHandwritingParams {
publishId: number;
problemId: number;
request: UpdateStudyHandwritingRequest;
}

export const useUpdateStudyHandwriting = () => {
const queryClient = useQueryClient();

return useMutation({
mutationFn: async ({
publishId,
problemId,
request,
}: UpdateStudyHandwritingParams): Promise<UpdateStudyHandwritingResponse> => {
const { data } = await client.PUT(
'/api/student/study/problem/{publishId}/{problemId}/handwriting',
{
params: {
path: { publishId, problemId },
},
body: request,
}
);
return data as UpdateStudyHandwritingResponse;
},
onSuccess: (_, { publishId, problemId, request }) => {
queryClient.setQueryData(
TanstackQueryClient.queryOptions(
'get',
'/api/student/study/problem/{publishId}/{problemId}/handwriting',
{
params: { path: { publishId, problemId } },
}
).queryKey,
{ data: request.data }
);
Comment on lines +37 to +47
Copy link

Copilot AI Apr 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

onSuccess updates the handwriting query cache with { data: request.data }, which does not match the query’s response type (StudyHandwritingResp includes publishId, problemId, and optionally updatedAt). This can leave the cache in an inconsistent shape and break consumers that expect those fields. Update the cache with the actual mutation response (or merge with existing cached value while preserving required fields).

Copilot uses AI. Check for mistakes.
},
});
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { TanstackQueryClient } from '@/apis/client';

export const useGetStudyHandwriting = (publishId: number, problemId: number, enabled = true) => {
return TanstackQueryClient.useQuery(
'get',
'/api/student/study/problem/{publishId}/{problemId}/handwriting',
{
params: {
path: { publishId, problemId },
},
},
{
enabled,
staleTime: Infinity,
Copy link

Copilot AI Apr 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This query sets staleTime: Infinity but omits gcTime: Infinity, unlike other study hooks (e.g. useGetProblem) that keep these caches from being garbage-collected. With the default gcTime, handwriting may be evicted after inactivity and refetched unexpectedly. Consider setting gcTime: Infinity here as well to align with the surrounding study query caching strategy.

Suggested change
staleTime: Infinity,
staleTime: Infinity,
gcTime: Infinity,

Copilot uses AI. Check for mistakes.
refetchOnWindowFocus: false,
}
);
};
3 changes: 3 additions & 0 deletions apps/native/src/apis/controller/student/study/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ import useGetWeeklyPublish from './useGetWeeklyPublish';
import useGetEntireProblemPointing from './useGetEntireProblemPointing';
import useGetEntireProblem from './useGetEntireProblem';

export { useGetStudyHandwriting } from './handwriting/useGetStudyHandwriting';
export { useUpdateStudyHandwriting } from './handwriting/putUpdateStudyHandwriting';

export {
getPublishDetailById,
postAnswer,
Expand Down
148 changes: 140 additions & 8 deletions apps/native/src/types/api/schema.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,25 @@ export interface paths {
patch?: never;
trace?: never;
};
'/api/student/study/problem/{publishId}/{problemId}/handwriting': {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
/** 필기 데이터 조회 */
get: operations['getHandwriting'];
/** 필기 데이터 저장/수정 */
put: operations['updateHandwriting'];
post?: never;
/** 필기 데이터 삭제 */
delete: operations['deleteHandwriting'];
options?: never;
head?: never;
patch?: never;
trace?: never;
};
'/api/student/scrap/{scrapId}': {
parameters: {
query?: never;
Expand Down Expand Up @@ -157,12 +176,12 @@ export interface paths {
cookie?: never;
};
/** 필기 데이터 조회 */
get: operations['getHandwriting'];
get: operations['getHandwriting_1'];
/** 필기 데이터 저장/수정 */
put: operations['updateHandwriting'];
put: operations['updateHandwriting_1'];
post?: never;
/** 필기 데이터 삭제 */
delete: operations['deleteHandwriting'];
delete: operations['deleteHandwriting_1'];
options?: never;
head?: never;
patch?: never;
Expand Down Expand Up @@ -2974,6 +2993,30 @@ export interface components {
/** @description 마케팅 알림 허용 여부 (이벤트 및 업데이트 관련 알림) */
isAllowMarketingPush?: boolean;
};
StudyHandwritingUpdateRequest: {
/** @description 필기 데이터 (Base64 인코딩) */
data: string;
};
/** @description 학습 필기 데이터 응답 */
StudyHandwritingResp: {
/**
* Format: int64
* @description 발행 ID
*/
publishId: number;
/**
* Format: int64
* @description 문제 ID
*/
problemId: number;
/** @description 필기 데이터 (Base64 인코딩) */
data: string;
/**
* Format: date-time
* @description 필기 데이터 수정일시 (필기 없으면 null)
*/
updatedAt?: string;
};
ScrapUpdateRequest: {
/**
* Format: int64
Expand Down Expand Up @@ -3004,6 +3047,13 @@ export interface components {
name: string;
category: components['schemas']['ConceptCategoryResp'];
};
PointingCommentContentResp: {
/** Format: int64 */
id: number;
/** Format: int32 */
no: number;
contentJson: string;
};
/** @description 포인팅 목록 */
PointingResp: {
/** Format: int64 */
Expand All @@ -3012,6 +3062,7 @@ export interface components {
no: number;
questionContent: string;
commentContent: string;
commentContentList?: components['schemas']['PointingCommentContentResp'][];
concepts: components['schemas']['ConceptResp'][];
};
PracticeTestResp: {
Expand Down Expand Up @@ -3316,13 +3367,21 @@ export interface components {
TeacherStudentAssignReq: {
students: number[];
};
CommentContentRequest: {
/** Format: int64 */
id?: number;
/** Format: int32 */
no?: number;
contentJson?: string;
};
PointingUpdateRequest: {
/** Format: int64 */
id?: number;
/** Format: int32 */
no?: number;
questionContent?: string;
commentContent?: string;
commentContentList?: components['schemas']['CommentContentRequest'][];
concepts?: number[];
};
ProblemUpdateRequest: {
Expand Down Expand Up @@ -4026,6 +4085,7 @@ export interface components {
no: number;
questionContent: string;
commentContent: string;
commentContentList?: components['schemas']['PointingCommentContentResp'][];
concepts: components['schemas']['ConceptResp'][];
isQuestionUnderstood?: boolean;
isCommentUnderstood?: boolean;
Expand Down Expand Up @@ -4167,6 +4227,7 @@ export interface components {
no?: number;
questionContent?: string;
commentContent?: string;
commentContentList?: components['schemas']['CommentContentRequest'][];
concepts?: number[];
};
ProblemCreateRequest: {
Expand Down Expand Up @@ -4447,6 +4508,7 @@ export interface components {
no: number;
questionContent: string;
commentContent: string;
commentContentList?: components['schemas']['PointingCommentContentResp'][];
concepts: components['schemas']['ConceptResp'][];
isQuestionUnderstood?: boolean;
isCommentUnderstood?: boolean;
Expand Down Expand Up @@ -5023,8 +5085,7 @@ export interface components {
path?: string;
/** Format: date-time */
timestamp?: string;
rootCause?: string;
stackTrace?: string[];
requestId?: string;
};
};
responses: never;
Expand Down Expand Up @@ -5199,6 +5260,77 @@ export interface operations {
};
};
};
getHandwriting: {
parameters: {
query?: never;
header?: never;
path: {
publishId: number;
problemId: number;
};
cookie?: never;
};
requestBody?: never;
responses: {
/** @description OK */
200: {
headers: {
[name: string]: unknown;
};
content: {
'*/*': components['schemas']['StudyHandwritingResp'];
};
};
};
};
updateHandwriting: {
parameters: {
query?: never;
header?: never;
path: {
publishId: number;
problemId: number;
};
cookie?: never;
};
requestBody: {
content: {
'application/json': components['schemas']['StudyHandwritingUpdateRequest'];
};
};
responses: {
/** @description OK */
200: {
headers: {
[name: string]: unknown;
};
content: {
'*/*': components['schemas']['StudyHandwritingResp'];
};
};
};
};
deleteHandwriting: {
parameters: {
query?: never;
header?: never;
path: {
publishId: number;
problemId: number;
};
cookie?: never;
};
requestBody?: never;
responses: {
/** @description OK */
200: {
headers: {
[name: string]: unknown;
};
content?: never;
};
};
};
updateScrap: {
parameters: {
query?: never;
Expand Down Expand Up @@ -5303,7 +5435,7 @@ export interface operations {
};
};
};
getHandwriting: {
getHandwriting_1: {
parameters: {
query?: never;
header?: never;
Expand All @@ -5325,7 +5457,7 @@ export interface operations {
};
};
};
updateHandwriting: {
updateHandwriting_1: {
parameters: {
query?: never;
header?: never;
Expand All @@ -5351,7 +5483,7 @@ export interface operations {
};
};
};
deleteHandwriting: {
deleteHandwriting_1: {
parameters: {
query?: never;
header?: never;
Expand Down
Loading