Skip to content
Merged
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
4 changes: 2 additions & 2 deletions apps/client/src/entities/session/model/qna.util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ export const getContentBodyLength = (body: string) => {
}, body.trim().length);
};

export const isValidBodyLength = (body: string) => {
return body.trim().length > 0 && body.trim().length <= 500;
export const isValidBodyLength = (body: number) => {
return body > 0 && body <= 500;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import axios from 'axios';
import { z } from 'zod';

export const QuestionShorteningRequestSchema = z.object({
token: z.string(),
sessionId: z.string(),
body: z.string().min(0),
});

export const QuestionShorteningResponseSchema = z.object({
result: z.object({
question: z.string(),
}),
});

export type QuestionShorteningRequest = z.infer<typeof QuestionShorteningRequestSchema>;

export type QuestionShorteningResponse = z.infer<typeof QuestionShorteningResponseSchema>;

export const postQuestionShortening = (body: QuestionShorteningRequest) =>
axios
.post<QuestionShorteningResponse>('/api/ai/question-shorten', QuestionShorteningRequestSchema.parse(body))
.then((res) => QuestionShorteningResponseSchema.parse(res.data));
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
import { useMutation } from '@tanstack/react-query';
import { useState } from 'react';

import {
postQuestionImprovement,
QuestionImprovementRequest,
} from '@/features/create-update-question/api/improve-question.api';
import { postQuestionImprovement } from '@/features/create-update-question/api/improve-question.api';
import { postQuestionShortening } from '@/features/create-update-question/api/shortening-question.api';

export const useQuestionWritingSupport = ({ handleAccept }: { handleAccept: (body: string) => void }) => {
const { mutate: questionImprovement, isPending: isQuestionImprovementInProgress } = useMutation({
mutationFn: (request: QuestionImprovementRequest) => {
return postQuestionImprovement(request);
mutationFn: postQuestionImprovement,
onSuccess: (data) => {
setSupportResult(data.result.question);
},
});

const { mutate: questionShortening, isPending: isQuestionShorteningInProgress } = useMutation({
mutationFn: postQuestionShortening,
onSuccess: (data) => {
setSupportResult(data.result.question);
},
Expand All @@ -29,10 +32,11 @@ export const useQuestionWritingSupport = ({ handleAccept }: { handleAccept: (bod
setSupportResult(null);
};

const requestEnable = !isQuestionImprovementInProgress;
const requestEnable = !isQuestionImprovementInProgress && !isQuestionShorteningInProgress;

return {
questionImprovement,
questionShortening,
isQuestionImprovementInProgress,
requestEnable,
supportResult,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,45 +9,55 @@ import QuestionContentView from '@/features/create-update-question/ui/QuestionCo
import { Question, useSessionStore } from '@/entities/session';
import { getContentBodyLength, isValidBodyLength } from '@/entities/session/model/qna.util';

import { useToastStore } from '@/shared/ui/toast';

interface CreateQuestionModalProps {
question?: Question;
}

function CreateQuestionModal({ question }: Readonly<CreateQuestionModalProps>) {
const addToast = useToastStore((state) => state.addToast);

const token = useSessionStore((state) => state.sessionToken);
const sessionId = useSessionStore((state) => state.sessionId);

const { body, setBody, handleSubmit, submitDisabled } = useQuestionMutation(question);
const { questionImprovement, requestEnable, supportResult, accept, reject } = useQuestionWritingSupport({
handleAccept: setBody,
});
const { questionImprovement, questionShortening, requestEnable, supportResult, accept, reject } =
useQuestionWritingSupport({
handleAccept: setBody,
});

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

const bodyLength = getContentBodyLength(supportResult ?? body);

const buttonEnabled = !submitDisabled && requestEnable && isValidBodyLength(body);
const isValidLength = isValidBodyLength(bodyLength);
const buttonEnabled = !submitDisabled && requestEnable;

const handleCreateOrUpdate = () => {
if (buttonEnabled) handleSubmit();
if (buttonEnabled && isValidLength) handleSubmit();
};

const handleQuestionImprovement = () => {
if (buttonEnabled && sessionId && token) {
if (buttonEnabled && isValidLength && sessionId && token) {
setSupportType('improve');
questionImprovement({ token, sessionId, body });
}
};

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

const handleRetry = () => {
if (sessionId && token) questionImprovement({ token, sessionId, body });
if (sessionId && token) {
if (supportType === 'improve') {
questionImprovement({ token, sessionId, body });
}
if (supportType === 'shorten') {
questionShortening({ token, sessionId, body });
}
}
};

return (
Expand All @@ -65,9 +75,10 @@ function CreateQuestionModal({ question }: Readonly<CreateQuestionModalProps>) {
<CreateQuestionModalFooter
supportResult={supportResult}
question={question}
isValidLength={isValidLength}
buttonEnabled={buttonEnabled}
handleQuestionImprovement={handleQuestionImprovement}
handleQuestionSummary={handleQuestionSummary}
handleQuestionShortening={handleQuestionShortening}
handleCreateOrUpdate={handleCreateOrUpdate}
handleRetry={handleRetry}
accept={accept}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ import { useModalContext } from '@/shared/ui/modal';
interface CreateQuestionModalFooterProps {
supportResult: string | null;
question?: Question;
isValidLength: boolean;
buttonEnabled: boolean;
handleQuestionImprovement: () => void;
handleQuestionSummary: () => void;
handleQuestionShortening: () => void;
handleCreateOrUpdate: () => void;
handleRetry: () => void;
accept: () => void;
Expand All @@ -18,9 +19,10 @@ interface CreateQuestionModalFooterProps {
export default function CreateQuestionModalFooter({
supportResult,
question,
isValidLength,
buttonEnabled,
handleQuestionImprovement,
handleQuestionSummary,
handleQuestionShortening,
handleCreateOrUpdate,
handleRetry,
accept,
Expand All @@ -34,14 +36,14 @@ export default function CreateQuestionModalFooter({
<>
<div className='flex flex-row gap-2'>
<Button
className={`${buttonEnabled ? 'bg-indigo-600' : 'cursor-not-allowed bg-indigo-300'}`}
className={`${buttonEnabled && isValidLength ? 'bg-indigo-600' : 'cursor-not-allowed bg-indigo-300'}`}
onClick={handleQuestionImprovement}
>
<div className='text-sm font-bold text-white'>질문 개선하기</div>
</Button>
<Button
className={`${buttonEnabled ? 'bg-indigo-600' : 'cursor-not-allowed bg-indigo-300'}`}
onClick={handleQuestionSummary}
onClick={handleQuestionShortening}
>
<div className='text-sm font-bold text-white'>질문 축약하기</div>
</Button>
Expand All @@ -51,7 +53,7 @@ export default function CreateQuestionModalFooter({
<div className='text-sm font-bold text-white'>취소하기</div>
</Button>
<Button
className={`${buttonEnabled ? 'bg-indigo-600' : 'cursor-not-allowed bg-indigo-300'}`}
className={`${buttonEnabled && isValidLength ? 'bg-indigo-600' : 'cursor-not-allowed bg-indigo-300'}`}
onClick={handleCreateOrUpdate}
>
<div className='text-sm font-bold text-white'>{question ? '수정하기' : '생성하기'}</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ function CreateReplyModal({ question, reply }: Readonly<CreateReplyModalProps>)

const bodyLength = getContentBodyLength(body);

const buttonEnabled = !submitDisabled && isValidBodyLength(body) && contentType !== 'question';
const buttonEnabled = !submitDisabled && isValidBodyLength(bodyLength) && contentType !== 'question';

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