Skip to content

Commit a72b9e3

Browse files
authored
feat(fe): integrate question shortening API (#69)
* fix: update isValidBodyLength function to accept number type for body length validation * feat: add question shortening feature and integrate into question creation UI * feat: add support type state for question improvement and shortening in CreateQuestionModal
1 parent 54be6d0 commit a72b9e3

File tree

6 files changed

+69
-29
lines changed

6 files changed

+69
-29
lines changed

apps/client/src/entities/session/model/qna.util.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,6 @@ export const getContentBodyLength = (body: string) => {
88
}, body.trim().length);
99
};
1010

11-
export const isValidBodyLength = (body: string) => {
12-
return body.trim().length > 0 && body.trim().length <= 500;
11+
export const isValidBodyLength = (body: number) => {
12+
return body > 0 && body <= 500;
1313
};
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import axios from 'axios';
2+
import { z } from 'zod';
3+
4+
export const QuestionShorteningRequestSchema = z.object({
5+
token: z.string(),
6+
sessionId: z.string(),
7+
body: z.string().min(0),
8+
});
9+
10+
export const QuestionShorteningResponseSchema = z.object({
11+
result: z.object({
12+
question: z.string(),
13+
}),
14+
});
15+
16+
export type QuestionShorteningRequest = z.infer<typeof QuestionShorteningRequestSchema>;
17+
18+
export type QuestionShorteningResponse = z.infer<typeof QuestionShorteningResponseSchema>;
19+
20+
export const postQuestionShortening = (body: QuestionShorteningRequest) =>
21+
axios
22+
.post<QuestionShorteningResponse>('/api/ai/question-shorten', QuestionShorteningRequestSchema.parse(body))
23+
.then((res) => QuestionShorteningResponseSchema.parse(res.data));

apps/client/src/features/create-update-question/model/useQuestionWritingSupport.ts

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,19 @@
11
import { useMutation } from '@tanstack/react-query';
22
import { useState } from 'react';
33

4-
import {
5-
postQuestionImprovement,
6-
QuestionImprovementRequest,
7-
} from '@/features/create-update-question/api/improve-question.api';
4+
import { postQuestionImprovement } from '@/features/create-update-question/api/improve-question.api';
5+
import { postQuestionShortening } from '@/features/create-update-question/api/shortening-question.api';
86

97
export const useQuestionWritingSupport = ({ handleAccept }: { handleAccept: (body: string) => void }) => {
108
const { mutate: questionImprovement, isPending: isQuestionImprovementInProgress } = useMutation({
11-
mutationFn: (request: QuestionImprovementRequest) => {
12-
return postQuestionImprovement(request);
9+
mutationFn: postQuestionImprovement,
10+
onSuccess: (data) => {
11+
setSupportResult(data.result.question);
1312
},
13+
});
14+
15+
const { mutate: questionShortening, isPending: isQuestionShorteningInProgress } = useMutation({
16+
mutationFn: postQuestionShortening,
1417
onSuccess: (data) => {
1518
setSupportResult(data.result.question);
1619
},
@@ -29,10 +32,11 @@ export const useQuestionWritingSupport = ({ handleAccept }: { handleAccept: (bod
2932
setSupportResult(null);
3033
};
3134

32-
const requestEnable = !isQuestionImprovementInProgress;
35+
const requestEnable = !isQuestionImprovementInProgress && !isQuestionShorteningInProgress;
3336

3437
return {
3538
questionImprovement,
39+
questionShortening,
3640
isQuestionImprovementInProgress,
3741
requestEnable,
3842
supportResult,

apps/client/src/features/create-update-question/ui/CreateQuestionModal.tsx

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,45 +9,55 @@ import QuestionContentView from '@/features/create-update-question/ui/QuestionCo
99
import { Question, useSessionStore } from '@/entities/session';
1010
import { getContentBodyLength, isValidBodyLength } from '@/entities/session/model/qna.util';
1111

12-
import { useToastStore } from '@/shared/ui/toast';
13-
1412
interface CreateQuestionModalProps {
1513
question?: Question;
1614
}
1715

1816
function CreateQuestionModal({ question }: Readonly<CreateQuestionModalProps>) {
19-
const addToast = useToastStore((state) => state.addToast);
20-
2117
const token = useSessionStore((state) => state.sessionToken);
2218
const sessionId = useSessionStore((state) => state.sessionId);
2319

2420
const { body, setBody, handleSubmit, submitDisabled } = useQuestionMutation(question);
25-
const { questionImprovement, requestEnable, supportResult, accept, reject } = useQuestionWritingSupport({
26-
handleAccept: setBody,
27-
});
21+
const { questionImprovement, questionShortening, requestEnable, supportResult, accept, reject } =
22+
useQuestionWritingSupport({
23+
handleAccept: setBody,
24+
});
2825

26+
const [supportType, setSupportType] = useState<'improve' | 'shorten' | null>(null);
2927
const [openPreview, setOpenPreview] = useState(false);
3028

3129
const bodyLength = getContentBodyLength(supportResult ?? body);
3230

33-
const buttonEnabled = !submitDisabled && requestEnable && isValidBodyLength(body);
31+
const isValidLength = isValidBodyLength(bodyLength);
32+
const buttonEnabled = !submitDisabled && requestEnable;
3433

3534
const handleCreateOrUpdate = () => {
36-
if (buttonEnabled) handleSubmit();
35+
if (buttonEnabled && isValidLength) handleSubmit();
3736
};
3837

3938
const handleQuestionImprovement = () => {
40-
if (buttonEnabled && sessionId && token) {
39+
if (buttonEnabled && isValidLength && sessionId && token) {
40+
setSupportType('improve');
4141
questionImprovement({ token, sessionId, body });
4242
}
4343
};
4444

45-
const handleQuestionSummary = () => {
46-
if (buttonEnabled) addToast({ type: 'INFO', message: '추후 업데이트 예정입니다.', duration: 3000 });
45+
const handleQuestionShortening = () => {
46+
if (buttonEnabled && sessionId && token) {
47+
setSupportType('shorten');
48+
questionShortening({ token, sessionId, body });
49+
}
4750
};
4851

4952
const handleRetry = () => {
50-
if (sessionId && token) questionImprovement({ token, sessionId, body });
53+
if (sessionId && token) {
54+
if (supportType === 'improve') {
55+
questionImprovement({ token, sessionId, body });
56+
}
57+
if (supportType === 'shorten') {
58+
questionShortening({ token, sessionId, body });
59+
}
60+
}
5161
};
5262

5363
return (
@@ -65,9 +75,10 @@ function CreateQuestionModal({ question }: Readonly<CreateQuestionModalProps>) {
6575
<CreateQuestionModalFooter
6676
supportResult={supportResult}
6777
question={question}
78+
isValidLength={isValidLength}
6879
buttonEnabled={buttonEnabled}
6980
handleQuestionImprovement={handleQuestionImprovement}
70-
handleQuestionSummary={handleQuestionSummary}
81+
handleQuestionShortening={handleQuestionShortening}
7182
handleCreateOrUpdate={handleCreateOrUpdate}
7283
handleRetry={handleRetry}
7384
accept={accept}

apps/client/src/features/create-update-question/ui/CreateQuestionModalFooter.tsx

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@ import { useModalContext } from '@/shared/ui/modal';
66
interface CreateQuestionModalFooterProps {
77
supportResult: string | null;
88
question?: Question;
9+
isValidLength: boolean;
910
buttonEnabled: boolean;
1011
handleQuestionImprovement: () => void;
11-
handleQuestionSummary: () => void;
12+
handleQuestionShortening: () => void;
1213
handleCreateOrUpdate: () => void;
1314
handleRetry: () => void;
1415
accept: () => void;
@@ -18,9 +19,10 @@ interface CreateQuestionModalFooterProps {
1819
export default function CreateQuestionModalFooter({
1920
supportResult,
2021
question,
22+
isValidLength,
2123
buttonEnabled,
2224
handleQuestionImprovement,
23-
handleQuestionSummary,
25+
handleQuestionShortening,
2426
handleCreateOrUpdate,
2527
handleRetry,
2628
accept,
@@ -34,14 +36,14 @@ export default function CreateQuestionModalFooter({
3436
<>
3537
<div className='flex flex-row gap-2'>
3638
<Button
37-
className={`${buttonEnabled ? 'bg-indigo-600' : 'cursor-not-allowed bg-indigo-300'}`}
39+
className={`${buttonEnabled && isValidLength ? 'bg-indigo-600' : 'cursor-not-allowed bg-indigo-300'}`}
3840
onClick={handleQuestionImprovement}
3941
>
4042
<div className='text-sm font-bold text-white'>질문 개선하기</div>
4143
</Button>
4244
<Button
4345
className={`${buttonEnabled ? 'bg-indigo-600' : 'cursor-not-allowed bg-indigo-300'}`}
44-
onClick={handleQuestionSummary}
46+
onClick={handleQuestionShortening}
4547
>
4648
<div className='text-sm font-bold text-white'>질문 축약하기</div>
4749
</Button>
@@ -51,7 +53,7 @@ export default function CreateQuestionModalFooter({
5153
<div className='text-sm font-bold text-white'>취소하기</div>
5254
</Button>
5355
<Button
54-
className={`${buttonEnabled ? 'bg-indigo-600' : 'cursor-not-allowed bg-indigo-300'}`}
56+
className={`${buttonEnabled && isValidLength ? 'bg-indigo-600' : 'cursor-not-allowed bg-indigo-300'}`}
5557
onClick={handleCreateOrUpdate}
5658
>
5759
<div className='text-sm font-bold text-white'>{question ? '수정하기' : '생성하기'}</div>

apps/client/src/features/create-update-reply/ui/CreateReplyModal.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ function CreateReplyModal({ question, reply }: Readonly<CreateReplyModalProps>)
2121

2222
const bodyLength = getContentBodyLength(body);
2323

24-
const buttonEnabled = !submitDisabled && isValidBodyLength(body) && contentType !== 'question';
24+
const buttonEnabled = !submitDisabled && isValidBodyLength(bodyLength) && contentType !== 'question';
2525

2626
return (
2727
<div className='relative flex h-[20rem] w-[40rem] flex-col rounded-lg bg-gray-50 p-4'>

0 commit comments

Comments
 (0)