Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

모임 개설 대상 파트 Chip 으로 변경 #914

Merged
merged 8 commits into from
Oct 9, 2024
Merged
Show file tree
Hide file tree
Changes from 6 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: 0 additions & 2 deletions pages/post/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -135,8 +135,6 @@ export default function PostPage() {
!!comment
);

console.log({ comments });

Copy link
Contributor

Choose a reason for hiding this comment

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

콘솔 제거 고마워~!

const handleClickComment = () => {
const refCurrent = commentRef.current;
if (refCurrent) {
Expand Down
73 changes: 73 additions & 0 deletions src/components/form/Presentation/JoinablePartsField/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { Option } from '@components/form/Select/OptionItem';
import { parts } from '@data/options';
import { Chip } from '@sopt-makers/ui';
import { useState, useEffect } from 'react';

interface JoinablePartsFieldProps {
value: Option[];
onChange: (newSelectedParts: Option[]) => void;
}

const JoinablePartsField = ({ value, onChange }: JoinablePartsFieldProps) => {
const [selectedParts, setSelectedParts] = useState<Option[]>([]);

useEffect(() => {
if (Array.isArray(value)) {
setSelectedParts(value); // value prop이 변경되면 상태 동기화
}
}, [value]);

const handleClick = (selectedOption: Option) => {
let updatedParts = [...selectedParts];

// 'all' 옵션을 클릭했을 때 처리
if (selectedOption.value === 'all') {
if (selectedParts.some(part => part.value === 'all')) {
// 전체 옵션이 이미 선택되어 있으면 해제
updatedParts = [];
} else {
// 전체 옵션을 선택하면 모든 부분을 선택
updatedParts = parts;
}
} else {
// 개별 옵션을 선택할 때
if (selectedParts.some(part => part.value === selectedOption.value)) {
// 이미 선택된 항목이면 해제
updatedParts = updatedParts.filter(part => part.value !== selectedOption.value);
} else {
// 선택되지 않은 항목이면 추가
updatedParts.push(selectedOption);
}

// 개별 옵션 해제 시 전체 옵션도 해제
if (updatedParts.some(part => part.value === 'all') && updatedParts.length < parts.length) {
updatedParts = updatedParts.filter(part => part.value !== 'all');
}

// 모든 개별 파트가 선택되었으면 'all' 옵션도 활성화
if (updatedParts.length === parts.length - 1) {
updatedParts.push(parts[0]);
}
}

setSelectedParts(updatedParts);
onChange(updatedParts); // 선택된 파트의 value만 전달
};
Copy link
Contributor

Choose a reason for hiding this comment

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

코드가 조금 verbose 한 면이 있어서, 리팩토링을 해보면 좋을 것 같아! 지금 진이는, value 라는 사용자 입력 값을 useEffect 를 이용해서 지켜보면서, setState 를 해주고 있는데, 관점을 바꿔서 사용자 이벤트를 기반으로 리팩토링해보면 좋지 않을까 하는 생각이야~

Copy link
Member Author

Choose a reason for hiding this comment

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

좋은 피드백 고마오 !! 코드리뷰 반영했는데 한 번 확인해줄 수 있어 ?

Copy link
Contributor

Choose a reason for hiding this comment

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

훨씬 깔끔해진 거 같애! 충돌만 잡고 머지해보자~!


return (
<>
{parts.map(part => (
<Chip
active={selectedParts.some(selected => selected.value === part.value)}
onClick={() => handleClick(part)}
key={part.value}
style={{ width: '80px' }}
>
{part.label}
</Chip>
))}
</>
);
};

export default JoinablePartsField;
47 changes: 23 additions & 24 deletions src/components/form/Presentation/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { ChangeEvent, useState } from 'react';
import React, { ChangeEvent } from 'react';
import CancelIcon from '@assets/svg/x.svg';
import { FieldError, FieldErrors } from 'react-hook-form';
import { categories } from '@data/categories';
Expand All @@ -13,7 +13,6 @@ import TextInput from '../TextInput';
import ImagePreview from './ImagePreview';
import { MAX_FILE_SIZE } from '@type/form';
import NeedMentor from '../CheckBox/NeedMentor';
import { parts } from '@data/options';
import { useRouter } from 'next/router';
import { getPresignedUrl, uploadImage } from '@api/API_LEGACY/meeting';
import { imageS3Bucket } from '@constants/url';
Expand All @@ -22,6 +21,7 @@ import { fontsObject } from '@sopt-makers/fonts';
import { colors } from '@sopt-makers/colors';
import CheckSelectedIcon from '@assets/svg/checkBox/form_selected.svg';
import CheckUnselectedIcon from '@assets/svg/checkBox/form_unselected.svg';
import JoinablePartsField from '@components/form/Presentation/JoinablePartsField';

interface PresentationProps {
submitButtonLabel: React.ReactNode;
Expand Down Expand Up @@ -330,23 +330,23 @@ function Presentation({
};
return (
<STargetFieldWrapper>
<FormController
name="detail.joinableParts"
defaultValue={[parts[0]]}
render={({ field: { value, onChange, onBlur } }) => (
<Select options={parts} value={value} onChange={onChange} onBlur={onBlur} multiple />
)}
></FormController>

<STargetChipContainer>
<FormController
name="detail.joinableParts"
render={({ field: { value, onChange } }) => (
<JoinablePartsField value={value} onChange={onChange} />
)}
></FormController>
</STargetChipContainer>
{/* 모집 인원 */}
<div style={{ display: 'flex' }}>
<div style={{ display: 'flex', alignItems: 'center' }}>
<SMemberCountWrapper>
<FormController
name="capacity"
render={({ field, fieldState: { error } }) => (
<TextInput
type="number"
placeholder="인원"
placeholder="총 인원 수"
right={<span style={{ marginLeft: '10px', color: '#a9a9a9' }}>명</span>}
required
{...field}
Expand Down Expand Up @@ -492,19 +492,18 @@ const SNeedMentorFieldWrapper = styled('div', {
});
const STargetFieldWrapper = styled('div', {
display: 'flex',
alignItems: 'center',
gap: '10px',
flexDirection: 'column',
gap: '$16',
marginBottom: '16px',
height: '52px',
'@tablet': {
height: '48px',
},
});

'@media(max-width: 525px)': {
flexDirection: 'column',
alignItems: 'flex-start',
const STargetChipContainer = styled('div', {
display: 'flex',
gap: '$10',
flexWrap: 'wrap',

marginBottom: '52px',
'@media(max-width: 430px)': {
maxWidth: '320px',
},
});

Expand Down Expand Up @@ -575,8 +574,8 @@ const SSectionCountBox = styled('div', {
});

const SMemberCountWrapper = styled('div', {
width: '94px',
height: '52px',
width: '119px',
height: '48px',
});

const SFormCheckBox = styled('div', {
Expand Down
3 changes: 0 additions & 3 deletions src/components/form/TableOfContents/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,8 @@ function TableOfContents({ label }: TableOfContentsProps) {
const isTitleValid = form.title && !errors.title;

const isCategoryValid = form.category?.value && !errors.category;
// console.log('카테고리', '' + form.category?.value, isCategoryValid);
const isImageValid = form.files && form.files.length > 0;
console.log('이미지', isImageValid);
const isDescriptionValid = form.detail && form.detail.desc && !errors.detail;
console.log('모임소개', isImageValid);
const isApplicationDateValid = form.startDate && form.endDate && !errors.startDate && !errors.endDate;
const isTargetValid =
form.detail &&
Expand Down
2 changes: 1 addition & 1 deletion src/components/form/TextInput/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ const SInputWrapper = styled('div', {
});
const SInput = styled('input', {
width: '100%',
padding: '18px 20px',
padding: '11px 16px',
display: 'flex',
alignItems: 'center',
fontAg: '16_medium_100',
Expand Down
9 changes: 4 additions & 5 deletions src/data/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,11 @@ export const generationOptions = [
];

export const parts = [
Copy link
Contributor

Choose a reason for hiding this comment

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

요 options 의 part 는 여기에서만 쓰이는 아이일까? 다른 곳에서도 쓰인다면 그곳에서도 잘 동작하는지 확인이 필요할 거 같애~!

Copy link
Member Author

Choose a reason for hiding this comment

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

edit 이랑 presentation 쪽에서만 쓰여!
edit 쪽 실행시켜봤는데 모임 수정 잘 되는 거 확인했오요!

{ label: '대상 파트', value: null },
{ label: '전체', value: 'all', order: 1 },
{ label: '전체파트', value: 'all', order: 1 },
{ label: '기획', value: 'PM', order: 2 },
{ label: '디자인', value: 'DESIGN', order: 3 },
{ label: '웹', value: 'WEB', order: 4 },
{ label: '안드로이드', value: 'ANDROID', order: 5 },
{ label: 'iOS', value: 'IOS', order: 6 },
{ label: '서버', value: 'SERVER', order: 7 },
{ label: 'iOS', value: 'IOS', order: 6 },
{ label: 'Android', value: 'ANDROID', order: 5 },
{ label: '웹', value: 'WEB', order: 4 },
];
Loading