Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
b6464c1
refactor: ApplicationForm 컴포넌트 제거
oesnuj Jun 4, 2025
d75e305
style: AnswerApplicationForm 스타일 파일 추가
oesnuj Jun 4, 2025
d87f68a
feat: AnswerApplicationForm 컴포넌트 추가
oesnuj Jun 4, 2025
0d2e349
feat: AnswerItem 타입 정의 추가
oesnuj Jun 4, 2025
11290f2
feat: 지원서 답변 관리를 위한 useAnswers 커스텀 훅 추가
oesnuj Jun 4, 2025
6b0b860
feat: QuestionAnswerer 컴포넌트 추가
oesnuj Jun 4, 2025
3840fbf
style: QuestionTitle 스타일 속성 수정
oesnuj Jun 4, 2025
57a26fe
refactor: App.tsx 주석 스타일 수정
oesnuj Jun 4, 2025
3092588
style: InputField 기본 배경색 스타일 수정
oesnuj Jun 4, 2025
81c0089
feat: 지원서 타입에 answer 및 onAnswerChange 속성 추가
oesnuj Jun 4, 2025
0233673
feat: Choice 컴포넌트 다중 및 단일 선택 로직 개선
oesnuj Jun 4, 2025
18a05f4
feat: QuestionAnswerer 컴포넌트의 Choice 렌더링 로직 추가
oesnuj Jun 4, 2025
d16bee1
style: AnswerApplicationForm 스타일 개선
oesnuj Jun 4, 2025
9b60dee
style: AnswerApplicationForm 질문 목록 스타일 구조 개선
oesnuj Jun 4, 2025
42d0bac
refactor: AnswerApplicationForm의 clubId 설정 방식 수정
oesnuj Jun 4, 2025
b2bf891
refactor: AnswerApplicationForm에서 clubId 가져오는 로직 수정
oesnuj Jun 4, 2025
1d5a6da
refactor: AnswerApplicationForm 경로에 clubId 파라미터 추가
oesnuj Jun 4, 2025
513f97b
refactor: ClubApplyButton에서 useNavigate, useParams 및 useGetClubDetail 추가
oesnuj Jun 4, 2025
b4413d0
refactor: ClubApplyButton 컴포넌트 리다이렉트 로직 개선
oesnuj Jun 4, 2025
2309286
refactor: SideBar 컴포넌트의 메뉴 항목 순서 변경
oesnuj Jun 4, 2025
d36019f
feat: 지원서 작성 페이지에 제출 버튼 추가
oesnuj Jun 4, 2025
be386a1
refactor: SideBar 컴포넌트에서 불필요한 console.error 제거
oesnuj Jun 4, 2025
8224fe7
Merge branch 'develop-fe' into feature/#491-apply-mc-field-MOA-35
seongwon030 Jun 4, 2025
75805bd
refactor: AnswerApplicationForm 및 CreateApplicationForm 관련 라우팅 수정
oesnuj Jun 4, 2025
2664571
Merge remote-tracking branch 'origin/feature/#491-apply-mc-field-MOA-…
oesnuj Jun 4, 2025
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
11 changes: 2 additions & 9 deletions frontend/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -75,16 +75,9 @@ const App = () => {
</AdminClubProvider>
}
/>
{/*//todo /:clubid로 수정 필요*/}
{/*<Route*/}
{/* path='/application/:clubid'*/}
{/* element={<AnswerApplicationForm />}*/}
{/*/>*/}
<Route path='/application' element={<AnswerApplicationForm />} />
{/*TODO: CreateForm은 관리자 기능이므로 추후 /admin/* 경로 안으로 이동 필요*/}
<Route
path='create-application'
element={<CreateApplicationForm />}
path='/application/:clubId'
element={<AnswerApplicationForm />}
/>
<Route path='*' element={<Navigate to='/' replace />} />
</Routes>
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/common/InputField/InputField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ const InputField = ({
hasError={isError}
readOnly={readOnly}
style={{
background: bgColor || '#F5F5F5',
background: bgColor || '#FFF',
color: textColor,
borderColor: borderColor,
}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
font-weight: 500;
background: white;
color: #555;
margin-bottom: 200px;
margin-bottom: 60px;
cursor: pointer;
`;

Expand All @@ -41,3 +41,30 @@
border: none;
border-top: 1px solid #ddd;
`;

export const ButtonWrapper = styled.div`

Check warning on line 45 in frontend/src/pages/AdminPage/application/CreateApplicationForm.styles.ts

View check run for this annotation

Codecov / codecov/patch

frontend/src/pages/AdminPage/application/CreateApplicationForm.styles.ts#L45

Added line #L45 was not covered by tests
display: flex;
justify-content: flex-end;
`;

export const submitButton = styled.button`

Check warning on line 50 in frontend/src/pages/AdminPage/application/CreateApplicationForm.styles.ts

View check run for this annotation

Codecov / codecov/patch

frontend/src/pages/AdminPage/application/CreateApplicationForm.styles.ts#L50

Added line #L50 was not covered by tests
padding: 10px 56px;
background-color: #ff5414;
border-radius: 10px;
border: none;
color: #fff;
font-size: 1.25rem;
font-weight: 600;
letter-spacing: -0.4px;
transition: background-color 0.2s;
margin: 50px 0;

&:hover {
background-color: #ffad8e;
animation: pulse 0.4s ease-in-out;
}

&:active {
transform: scale(0.95);
}
`;
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,9 @@ const CreateApplicationForm = () => {
<Styled.AddQuestionButton onClick={addQuestion}>
질문 추가 +
</Styled.AddQuestionButton>
<Styled.ButtonWrapper>
<Styled.submitButton>제출하기</Styled.submitButton>
</Styled.ButtonWrapper>
</PageContainer>
</>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@
margin-bottom: 46px;
`;

export const QuestionsWrapper = styled.div`

Check warning on line 12 in frontend/src/pages/AdminPage/application/answer/AnswerApplicationForm.styles.ts

View check run for this annotation

Codecov / codecov/patch

frontend/src/pages/AdminPage/application/answer/AnswerApplicationForm.styles.ts#L12

Added line #L12 was not covered by tests
display: flex;
flex-direction: column;
gap: 50px;
`;

export const ButtonWrapper = styled.div`
display: flex;
justify-content: flex-end;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@
import QuestionAnswerer from '@/pages/AdminPage/application/components/QuestionAnswerer/QuestionAnswerer';

const AnswerApplicationForm = () => {
//const { clubId } = useParams<{ clubId: string }>();
const clubId = '67e54ae51cfd27718dd40bec'; // 하드코딩된 club ID
const { clubId } = useParams<{ clubId: string }>();

Check warning on line 12 in frontend/src/pages/AdminPage/application/answer/AnswerApplicationForm.tsx

View check run for this annotation

Codecov / codecov/patch

frontend/src/pages/AdminPage/application/answer/AnswerApplicationForm.tsx#L12

Added line #L12 was not covered by tests
const { data: clubDetail, error } = useGetClubDetail(clubId || '');
const { onAnswerChange, getAnswersById } = useAnswers();
if (!clubDetail) {
Expand All @@ -33,14 +32,16 @@
tags={clubDetail.tags}
/>
<Styled.FormTitle>{mockData.form_title}</Styled.FormTitle>
{mockData.questions.map((q) => (
<QuestionAnswerer
key={q.id}
question={q}
selectedAnswers={getAnswersById(q.id)}
onChange={onAnswerChange}
/>
))}
<Styled.QuestionsWrapper>
{mockData.questions.map((q) => (
<QuestionAnswerer

Check warning on line 37 in frontend/src/pages/AdminPage/application/answer/AnswerApplicationForm.tsx

View check run for this annotation

Codecov / codecov/patch

frontend/src/pages/AdminPage/application/answer/AnswerApplicationForm.tsx#L37

Added line #L37 was not covered by tests
key={q.id}
question={q}
selectedAnswers={getAnswersById(q.id)}
onChange={onAnswerChange}
/>
))}
</Styled.QuestionsWrapper>
<Styled.ButtonWrapper>
<Styled.submitButton>제출하기</Styled.submitButton>
</Styled.ButtonWrapper>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,13 @@
case 'CHOICE':
case 'MULTI_CHOICE':
return (
<></>
// <Choice
// {...baseProps}
// items={question.items}
// isMulti={question.type === 'MULTI_CHOICE'}
// answer={selectedAnswers}
// onAnswerChange={(value) => onChange(question.id, value)}
// />
<Choice
{...baseProps}
items={question.items}
isMulti={question.type === 'MULTI_CHOICE'}
answer={selectedAnswers}
onAnswerChange={(value) => onChange(question.id, value)}

Check warning on line 55 in frontend/src/pages/AdminPage/application/components/QuestionAnswerer/QuestionAnswerer.tsx

View check run for this annotation

Codecov / codecov/patch

frontend/src/pages/AdminPage/application/components/QuestionAnswerer/QuestionAnswerer.tsx#L55

Added line #L55 was not covered by tests
/>
);

default:
Expand Down
120 changes: 60 additions & 60 deletions frontend/src/pages/AdminPage/application/fields/Choice.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,10 @@
import InputField from '@/components/common/InputField/InputField';
import { APPLICATION_FORM } from '@/constants/APPLICATION_FORM';
import { ChoiceProps } from '@/types/application';
import { useState } from 'react';

const MIN_ITEMS = 2;
const MAX_ITEMS = 6;

// todo inputField clear 버튼 빼기
// todo 입력 필드안에 항목 삭제 아이콘 추가
// todo mode : answer일때 다중, 단일 조건에 따라 선택 가능하도록 UI 및 기능 추가 필요
// todo isMulti나 질문 타입을 props로 받아서 단일 / 다중 판단 하면 될듯

const Choice = ({
id,
title,
Expand All @@ -25,37 +19,47 @@
items = [],
isMulti,
onItemsChange,
answer = [],
onAnswerChange,
}: ChoiceProps) => {
const [selected, setSelected] = useState<number[]>([]);

// — 아이템 텍스트 변경(빌더 모드 전용)
const handleItemChange = (index: number, newValue: string) => {
const updated = items.map((item, i) =>
i === index ? { ...item, value: newValue } : item,
);
onItemsChange?.(updated);
};

// — 아이템 추가(빌더 모드 전용)
const handleAddItem = () => {
if (items.length >= MAX_ITEMS) return;
onItemsChange?.([...items, { value: '' }]);
};

// — 아이템 삭제(빌더 모드 전용)
const handleDeleteItem = (index: number) => {
if (items.length <= MIN_ITEMS) return;
const updated = items.filter((_, i) => i !== index);
onItemsChange?.(updated);
};

const handleSelect = (index: number) => {
const handleSelect = (idx: number) => {

Check warning on line 46 in frontend/src/pages/AdminPage/application/fields/Choice.tsx

View check run for this annotation

Codecov / codecov/patch

frontend/src/pages/AdminPage/application/fields/Choice.tsx#L46

Added line #L46 was not covered by tests
if (mode !== 'answer') return;
const value = items[idx].value;

Check warning on line 48 in frontend/src/pages/AdminPage/application/fields/Choice.tsx

View check run for this annotation

Codecov / codecov/patch

frontend/src/pages/AdminPage/application/fields/Choice.tsx#L48

Added line #L48 was not covered by tests
if (!value) return;

if (isMulti) {
setSelected((prev) =>
prev.includes(index)
? prev.filter((i) => i !== index)
: [...prev, index],
);
if (Array.isArray(answer)) {
if (answer.includes(value)) {
onAnswerChange?.(answer.filter((v) => v !== value));
} else {
onAnswerChange?.([...answer, value]);
}
}
// 다중 선택: 이미 포함되어 있으면 제거, 아니면 추가
} else {
setSelected([index]);
// 단일 선택: 클릭된 값만 넘김
onAnswerChange?.(value);
}
};

Expand All @@ -73,51 +77,47 @@
mode={mode}
onDescriptionChange={onDescriptionChange}
/>
{items.map((item, index) => (
<Styled.ItemWrapper
key={index}
onClick={() => handleSelect(index)}
data-selected={
mode === 'answer' && selected.includes(index) ? 'true' : undefined
}
>
<InputField
value={item.value}
onChange={(e) => handleItemChange(index, e.target.value)}
placeholder={APPLICATION_FORM.CHOICE.placeholder}
disabled={false}
readOnly={mode === 'answer'}
showClearButton={false}
bgColor={
mode === 'answer' && selected.includes(index)
? '#FFE4DA'
: undefined
}
textColor={
mode === 'answer'
? selected.includes(index)
? 'rgba(0,0,0,0.8)'
: 'rgba(0,0,0,0.3)'
: undefined
}
borderColor={
mode === 'answer' && selected.includes(index)
? '#FF5414'
: undefined
}
/>
{mode === 'builder' && items.length > MIN_ITEMS && (
<Styled.DeleteButton
onClick={(e) => {
e.stopPropagation();
handleDeleteItem(index);
}}
>
삭제
</Styled.DeleteButton>
)}
</Styled.ItemWrapper>
))}

{items.map((item, index) => {
// ▶ selected 대신, answer.includes(item.value)로 판별
const isSelected = mode === 'answer' && answer.includes(item.value);

return (

Check warning on line 85 in frontend/src/pages/AdminPage/application/fields/Choice.tsx

View check run for this annotation

Codecov / codecov/patch

frontend/src/pages/AdminPage/application/fields/Choice.tsx#L85

Added line #L85 was not covered by tests
<Styled.ItemWrapper
key={index}
onClick={() => handleSelect(index)}

Check warning on line 88 in frontend/src/pages/AdminPage/application/fields/Choice.tsx

View check run for this annotation

Codecov / codecov/patch

frontend/src/pages/AdminPage/application/fields/Choice.tsx#L88

Added line #L88 was not covered by tests
data-selected={isSelected ? 'true' : undefined}
>
<InputField
value={item.value}
onChange={(e) => handleItemChange(index, e.target.value)}

Check warning on line 93 in frontend/src/pages/AdminPage/application/fields/Choice.tsx

View check run for this annotation

Codecov / codecov/patch

frontend/src/pages/AdminPage/application/fields/Choice.tsx#L93

Added line #L93 was not covered by tests
placeholder={APPLICATION_FORM.CHOICE.placeholder}
readOnly={mode === 'answer'}
showClearButton={false}
bgColor={isSelected ? '#FFE4DA' : '#F5F5F5'}
textColor={
mode === 'answer'
? isSelected
? 'rgba(0,0,0,0.8)'
: 'rgba(0,0,0,0.3)'
: undefined
}
borderColor={isSelected ? '#FF5414' : undefined}
/>

{mode === 'builder' && items.length > MIN_ITEMS && (
<Styled.DeleteButton
onClick={(e) => {
e.stopPropagation();
handleDeleteItem(index);

Check warning on line 112 in frontend/src/pages/AdminPage/application/fields/Choice.tsx

View check run for this annotation

Codecov / codecov/patch

frontend/src/pages/AdminPage/application/fields/Choice.tsx#L111-L112

Added lines #L111 - L112 were not covered by tests
}}
>
삭제
</Styled.DeleteButton>
)}
</Styled.ItemWrapper>
);
})}

{mode === 'builder' && items.length < MAX_ITEMS && (
<Styled.AddItemButton onClick={handleAddItem}>
Expand Down
3 changes: 1 addition & 2 deletions frontend/src/pages/AdminPage/components/SideBar/SideBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ const tabs = [
{ label: '기본 정보 수정', path: '/admin/club-info' },
{ label: '모집 정보 수정', path: '/admin/recruit-edit' },
{ label: '활동 사진 수정', path: '/admin/photo-edit' },
{ label: '계정 관리', path: '/admin/account-edit' },
{ label: '지원서 관리', path: '/admin/application-edit' },
{ label: '계정 관리', path: '/admin/account-edit' },
];

const SideBar = ({ clubLogo, clubName }: SideBarProps) => {
Expand Down Expand Up @@ -44,7 +44,6 @@ const SideBar = ({ clubLogo, clubName }: SideBarProps) => {
localStorage.removeItem('accessToken');
navigate('/admin/login', { replace: true });
} catch (error) {
console.error(error);
alert('로그아웃에 실패했습니다.');
}
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import useMixpanelTrack from '@/hooks/useMixpanelTrack';
import styled from 'styled-components';
import { useNavigate, useParams } from 'react-router-dom';

Check warning on line 3 in frontend/src/pages/ClubDetailPage/components/ClubApplyButton/ClubApplyButton.tsx

View check run for this annotation

Codecov / codecov/patch

frontend/src/pages/ClubDetailPage/components/ClubApplyButton/ClubApplyButton.tsx#L3

Added line #L3 was not covered by tests
import { useGetClubDetail } from '@/hooks/queries/club/useGetClubDetail';

interface ButtonProps {
recruitmentForm?: string;
Expand Down Expand Up @@ -39,11 +41,16 @@
recruitmentForm,
presidentPhoneNumber,
}: ButtonProps) => {
const { clubId } = useParams<{ clubId: string }>();

Check warning on line 44 in frontend/src/pages/ClubDetailPage/components/ClubApplyButton/ClubApplyButton.tsx

View check run for this annotation

Codecov / codecov/patch

frontend/src/pages/ClubDetailPage/components/ClubApplyButton/ClubApplyButton.tsx#L44

Added line #L44 was not covered by tests
const trackEvent = useMixpanelTrack();
const navigate = useNavigate();

Check warning on line 46 in frontend/src/pages/ClubDetailPage/components/ClubApplyButton/ClubApplyButton.tsx

View check run for this annotation

Codecov / codecov/patch

frontend/src/pages/ClubDetailPage/components/ClubApplyButton/ClubApplyButton.tsx#L46

Added line #L46 was not covered by tests

const handleClick = () => {
trackEvent('Club Apply Button Clicked');

//TODO: 지원서를 작성한 동아리의 경우에만 리다이렉트
//navigate(`/application/${clubId}`);

// [x] FIXME: recruitmentForm 있을 때는 리다이렉트
if (presidentPhoneNumber) {
alert(`${presidentPhoneNumber} 으로 연락하여 지원해 주세요.`);
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/types/application.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ export interface ChoiceProps extends QuestionComponentProps {
items?: { value: string }[];
isMulti?: boolean;
onItemsChange?: (newItems: { value: string }[]) => void;
answer?: string | string[];
onAnswerChange?: (value: string[] | string) => void;
}

export interface ApplicationFormData {
Expand Down