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
2 changes: 1 addition & 1 deletion src/api/api.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import axios from 'axios';

export const apiClient = axios.create({
baseURL: import.meta.env.VITE_API_BASE_URL || 'https://backendbase.site',
baseURL: 'https://backendbase.site',
headers: {
'Content-Type': 'multipart/form-data',
},
Expand Down
5 changes: 3 additions & 2 deletions src/components/chat/FileSendButton.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { useRef, useState } from 'react';
import { apiClient } from '../../api/api';
import axios from 'axios';

interface UploadResponse {
Expand Down Expand Up @@ -32,9 +31,11 @@ const FileSendButton = ({ onUploadSuccess }: FileSendButtonProps) => {
const formData = new FormData();
formData.append('file', file);

const uploadUrl = import.meta.env.VITE_UPLOAD_URL;
console.log('Uploading to:', uploadUrl);
console.log('Uploading file:', file.name);

const response = await apiClient.post<UploadResponse>('/chat/upload', formData, {
const response = await axios.post<UploadResponse>(uploadUrl, formData, {
headers: {
'Content-Type': 'multipart/form-data',
},
Expand Down
2 changes: 1 addition & 1 deletion src/components/onboarding/FormButton.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const FormButton = ({ type, onClick }: { type: string; onClick: () => void }) => {
const buttonStyle =
'bg-[#1d4ed8] w-full text-white py-3 rounded-lg text-center font-medium cursor-pointer';
'bg-[#0D2D84] w-full text-white py-3 rounded-lg text-center font-medium cursor-pointer';

const grayButtonStyle =
'bg-gray-300 w-full text-gray-700 py-3 rounded-lg text-center font-medium cursor-pointer';
Expand Down
38 changes: 35 additions & 3 deletions src/components/onboarding/MultiSelect.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,42 @@
const MultiSelect = ({ title }: { title: string }) => {
import { useState } from 'react';

interface MultiSelectProps {
title: string;
options?: string[];
}

const MultiSelect = ({
title,
options = ['10대 이하', '20대', '30대', '40대', '50대', '60대 이상'],
}: MultiSelectProps) => {
const [selectedOptions, setSelectedOptions] = useState<string[]>([]);

const toggleOption = (option: string) => {
setSelectedOptions((prev) =>
prev.includes(option) ? prev.filter((item) => item !== option) : [...prev, option],
);
};
Comment on lines +3 to +18
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

선택된 값을 부모 컴포넌트로 전달하는 방법이 없습니다.

selectedOptions 상태가 컴포넌트 내부에만 존재하고 부모로 노출되지 않아, Onboarding.tsx에서 사용자가 선택한 타겟층 데이터를 수집할 수 없습니다. 이는 폼 제출 시 필수 데이터가 누락되는 치명적인 문제입니다.

다음과 같이 onChange 콜백을 추가하세요:

 interface MultiSelectProps {
   title: string;
   options?: string[];
+  value?: string[];
+  onChange?: (selected: string[]) => void;
 }

 const MultiSelect = ({
   title,
   options = ['10대 이하', '20대', '30대', '40대', '50대', '60대 이상'],
+  value = [],
+  onChange,
 }: MultiSelectProps) => {
-  const [selectedOptions, setSelectedOptions] = useState<string[]>([]);
+  const selectedOptions = value;

   const toggleOption = (option: string) => {
-    setSelectedOptions((prev) =>
-      prev.includes(option) ? prev.filter((item) => item !== option) : [...prev, option],
-    );
+    const newSelection = selectedOptions.includes(option)
+      ? selectedOptions.filter((item) => item !== option)
+      : [...selectedOptions, option];
+    onChange?.(newSelection);
   };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
interface MultiSelectProps {
title: string;
options?: string[];
}
const MultiSelect = ({
title,
options = ['10대 이하', '20대', '30대', '40대', '50대', '60대 이상'],
}: MultiSelectProps) => {
const [selectedOptions, setSelectedOptions] = useState<string[]>([]);
const toggleOption = (option: string) => {
setSelectedOptions((prev) =>
prev.includes(option) ? prev.filter((item) => item !== option) : [...prev, option],
);
};
interface MultiSelectProps {
title: string;
options?: string[];
value?: string[];
onChange?: (selected: string[]) => void;
}
const MultiSelect = ({
title,
options = ['10대 이하', '20대', '30대', '40대', '50대', '60대 이상'],
value = [],
onChange,
}: MultiSelectProps) => {
const selectedOptions = value;
const toggleOption = (option: string) => {
const newSelection = selectedOptions.includes(option)
? selectedOptions.filter((item) => item !== option)
: [...selectedOptions, option];
onChange?.(newSelection);
};
🤖 Prompt for AI Agents
In src/components/onboarding/MultiSelect.tsx around lines 3 to 18, the component
keeps selectedOptions internal and never exposes changes to the parent; add an
onChange prop to MultiSelectProps (e.g., onChange?: (selected: string[]) =>
void), accept it in the component signature, and invoke it whenever selection
changes (either call onChange(updatedSelected) inside toggleOption after
updating state or use a useEffect watching selectedOptions to call onChange).
Ensure the prop is properly typed and has no-op fallback if undefined.


return (
<div className="flex flex-col gap-6">
{/* 제목 */}
<p className="text-[24px] font-semibold">{title}을 선택하세요</p>
{/* 입력칸 */}
<input type="text" className="rounded-xl border border-gray-200 px-2 py-4 text-[20px]" />
{/* 6개 그리드 버튼 */}
<div className="grid grid-cols-2 gap-4 md:grid-cols-3">
{options.map((option, index) => (
<button
key={index}
onClick={() => toggleOption(option)}
className={`rounded-xl border-2 px-4 py-8 text-[18px] font-medium duration-200 ${
selectedOptions.includes(option)
? 'border-[#0D2D84] bg-[#0D2D84] text-white'
: 'border-gray-200 bg-white text-gray-700 hover:bg-gray-50'
}`}
>
{option}
</button>
))}
</div>
Comment on lines +24 to +39
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

접근성 개선을 위해 버튼 상태 속성을 추가하세요.

선택 가능한 버튼들에 aria-pressed 속성이 없어 스크린 리더 사용자가 현재 선택 상태를 파악하기 어렵습니다.

다음과 같이 접근성 속성을 추가하세요:

         <button
           key={index}
           onClick={() => toggleOption(option)}
+          aria-pressed={selectedOptions.includes(option)}
           className={`rounded-xl border-2 px-4 py-8 text-[18px] font-medium duration-200 ${
             selectedOptions.includes(option)
               ? 'border-[#0D2D84] bg-[#0D2D84] text-white'
               : 'border-gray-200 bg-white text-gray-700 hover:bg-gray-50'
           }`}
         >
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
{/* 6개 그리드 버튼 */}
<div className="grid grid-cols-2 gap-4 md:grid-cols-3">
{options.map((option, index) => (
<button
key={index}
onClick={() => toggleOption(option)}
className={`rounded-xl border-2 px-4 py-8 text-[18px] font-medium duration-200 ${
selectedOptions.includes(option)
? 'border-[#0D2D84] bg-[#0D2D84] text-white'
: 'border-gray-200 bg-white text-gray-700 hover:bg-gray-50'
}`}
>
{option}
</button>
))}
</div>
{/* 6개 그리드 버튼 */}
<div className="grid grid-cols-2 gap-4 md:grid-cols-3">
{options.map((option, index) => (
<button
key={index}
onClick={() => toggleOption(option)}
aria-pressed={selectedOptions.includes(option)}
className={`rounded-xl border-2 px-4 py-8 text-[18px] font-medium duration-200 ${
selectedOptions.includes(option)
? 'border-[#0D2D84] bg-[#0D2D84] text-white'
: 'border-gray-200 bg-white text-gray-700 hover:bg-gray-50'
}`}
>
{option}
</button>
))}
</div>
🤖 Prompt for AI Agents
In src/components/onboarding/MultiSelect.tsx around lines 24 to 39, the
selectable buttons are missing ARIA state which makes it hard for screen reader
users to know which options are selected; add an aria-pressed attribute to each
button bound to the selection state (e.g.,
aria-pressed={selectedOptions.includes(option)}) so the button exposes its
pressed/selected state, and also ensure the element is a proper button
(type="button") to avoid form submission side-effects.

</div>
);
};
Expand Down
14 changes: 7 additions & 7 deletions src/components/onboarding/SingleSelect.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
const defaultOptions = [
{ id: 1, name: 'option1' },
{ id: 2, name: 'option2' },
{ id: 3, name: 'option3' },
{ id: 4, name: 'option4' },
{ id: 5, name: 'option5' },
{ id: 6, name: 'option6' },
{ id: 7, name: 'option7' },
{ id: 1, name: '식품 소분업' },
{ id: 2, name: '기타식품판매업' },
{ id: 3, name: '일반음식점' },
{ id: 4, name: '휴게음식점' },
{ id: 5, name: '제과점' },
{ id: 6, name: '단란주점/유흥주점' },
{ id: 7, name: '즉석판매제조·가공업' },
];

const SingleSelect = ({ title }: { title: string }) => {
Expand Down
2 changes: 1 addition & 1 deletion src/pages/chat/ChatPageTest.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@
return () => {
socket.close();
};
}, []);

Check warning on line 104 in src/pages/chat/ChatPageTest.tsx

View workflow job for this annotation

GitHub Actions / checks

React Hook useEffect has a missing dependency: 'sessionId'. Either include it or remove the dependency array

// 자동 스크롤
useEffect(() => {
Expand All @@ -123,7 +123,7 @@
{
id: Date.now().toString(),
role: 'assistant',
content: '업로드 완료되었습니다. 재고 관리 채팅을 시작하세요',
content: '재고 파일이 업로드 완료되었습니다. \n 채팅을 시작해보세요 !',
},
]);
};
Expand Down
4 changes: 2 additions & 2 deletions src/pages/onboarding/Onboarding.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import MultiSelect from '../../components/onboarding/MultiSelect';
const Onboarding = () => {
const navigate = useNavigate();
const [currentStep, setCurrentStep] = useState(1);
const totalSteps = 5;
const totalSteps = 6;

const handlePrev = () => {
if (currentStep > 1) {
Expand Down Expand Up @@ -58,7 +58,7 @@ const Onboarding = () => {
</div>
<div className="h-2 w-full rounded-full bg-gray-200">
<div
className="h-2 rounded-full bg-blue-500 transition-all duration-300"
className="h-2 rounded-full bg-[#0D2D84] transition-all duration-300"
style={{ width: `${(currentStep / totalSteps) * 100}%` }}
/>
</div>
Expand Down