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

Feat: 변경된 Dropdown으로 recruit페이지 리팩토링 #134

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
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { useState } from "react";
import { format } from "date-fns";

import "@/styles/globals.css";
Expand All @@ -8,34 +7,31 @@ import DESIGN_TOKEN from "@/styles/tokens";
import useOpenToggle from "@/hooks/useOpenToggle";
import SquareDropButton from "../commons/SquareDropButton";
import { Calendar } from "./ui/calendar";

import { RecruitmentRequest } from "@/types/recruitmentRequestTypes";

interface DeadlineDropdownProps {
setSelectedOptions: React.Dispatch<React.SetStateAction<RecruitmentRequest>>;
placeholder: string;
selectedOption: string;
onSelect: (option: string) => void;
}

export default function DeadlineDropdown({ setSelectedOptions }: DeadlineDropdownProps) {
const [selectOption, setSelectOption] = useState<Date | undefined>();
const [isSelected, setIsSelected] = useState(false);
export default function DeadlineDropdown({ placeholder, selectedOption, onSelect }: DeadlineDropdownProps) {
const { isOpen, openToggle: toggleDropdown, ref } = useOpenToggle();
const date = selectOption ? format(selectOption, "yyyy.MM.dd") : "마감 기간";

const handleSelectDate = (date: Date | undefined) => {
setSelectOption(date);
setSelectedOptions((prevOptions) => ({
...prevOptions,
recruitEndAt: date ? format(date, "yyyy.MM.dd") : "",
}));
setIsSelected(true);
date ? onSelect(format(date, "yyyy.MM.dd")) : onSelect("");
toggleDropdown();
};

return (
<Container ref={ref}>
<SquareDropButton $iconType="date" onClick={toggleDropdown} selectOption={date} $isSelected={isSelected} />
<SquareDropButton
$iconType="date"
onClick={toggleDropdown}
selectOption={selectedOption || placeholder || ""}
$isSelected={!!selectedOption}
/>
{isOpen && (
<CalendarWrapper>
<Calendar mode="single" selected={selectOption} onSelect={handleSelectDate} initialFocus />
<Calendar mode="single" onSelect={handleSelectDate} initialFocus />
</CalendarWrapper>
)}
</Container>
Expand Down
8 changes: 4 additions & 4 deletions co-kkiri/src/components/commons/ReactQuill/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ const formats = [
];

export default function QuillEditor({
setSelectedOptions,
setSelectedOption,
}: {
setSelectedOptions: React.Dispatch<React.SetStateAction<RecruitmentRequest>>;
setSelectedOption: React.Dispatch<React.SetStateAction<RecruitmentRequest>>;
}) {
const modules = useMemo(() => {
return {
Expand All @@ -34,14 +34,14 @@ export default function QuillEditor({
}, []);

const handleTitleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setSelectedOptions((prevOptions) => ({
setSelectedOption((prevOptions) => ({
...prevOptions,
title: e.target.value,
}));
};

const handleContentChange = (content: string) => {
setSelectedOptions((prevOptions) => ({
setSelectedOption((prevOptions) => ({
...prevOptions,
content: content,
}));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import DESIGN_TOKEN from "@/styles/tokens";
import { useState } from "react";
import styled from "styled-components";

const { typography, color, mediaQueries } = DESIGN_TOKEN;
Expand Down Expand Up @@ -71,6 +70,18 @@ export const RadioButtonWarper = styled.div`
gap: 0.8rem;
`;

export const DropdownWrapper = styled.div`
width: 36.7rem;

${mediaQueries.tablet} {
width: 46.2rem;
}

${mediaQueries.mobile} {
width: 32rem;
}
`;

export const SelectBox = styled.div`
display: flex;
flex-direction: column;
Expand Down
137 changes: 99 additions & 38 deletions co-kkiri/src/components/commons/RecruitmentRequestLayout/index.tsx
Original file line number Diff line number Diff line change
@@ -1,32 +1,65 @@
import DeadlineDropdown from "@/components/commons/DropDowns/DeadlineDropdown/DeadlineDropdown";
import RecruitDropdown from "@/components/commons/DropDowns/RecruitDropdown";
import Dropdown from "@/components/commons/DropDowns/Dropdown";
import MultiselectDropdown from "@/components/commons/DropDowns/StackMultiselectDropdown";
import RadioButton from "@/components/commons/RadioButton";
import QuillEditor from "@/components/commons/ReactQuill";
import SelectPositionChipList from "@/components/commons/SelectPositionChipList";
import * as S from "./RecruitLayout.styled";
import { Dispatch, SetStateAction } from "react";
import { DROPDOWN_INFO } from "@/constants/dropDown";
import { useState } from "react";
import styled from "styled-components";
import DESIGN_TOKEN from "@/styles/tokens";
import { RecruitmentRequest } from "@/types/recruitmentRequestTypes";
import { format } from "date-fns";

interface RecruitLayoutProps {
handleSelectType: (type: string) => void;
handleSelectOption: ({ optionType, option }: { optionType: string; option: string | number }) => void;
handleChangeLink: (link: string) => void;
handleSelectStack: (stacks: string[]) => void;
handleSelectPosition: (position: string) => void;
selectedOptions: RecruitmentRequest;
setSelectedOptions: Dispatch<SetStateAction<RecruitmentRequest>>;
}
export default function RecruitmentRequestLayout() {
const {
recruitment: { capacity, progressPeriod, progressWay, contactWay },
} = DROPDOWN_INFO;

const [selectedOption, setSelectedOption] = useState<RecruitmentRequest>({
type: "",
recruitEndAt: "",
progressPeriod: "",
capacity: 0,
contactWay: "",
progressWay: "",
stacks: [],
positions: [],
title: "",
content: "",
link: "",
});

const findOptionByValue = <ValueType, OptionType>(values: ValueType[], options: OptionType[], value: ValueType) => {
const index = values.indexOf(value);
return options[index];
};

const handleSelectType = (type: string): void => {
setSelectedOption((prevOptions) => ({
...prevOptions,
type: type,
}));
};

export default function RecruitmentRequestLayout({
handleSelectType,
handleSelectOption,
handleSelectStack,
handleChangeLink,
handleSelectPosition,
selectedOptions,
setSelectedOptions,
}: RecruitLayoutProps) {
const handleSelectStack = (stacks: string[]): void => {
setSelectedOption((prevOptions) => ({
...prevOptions,
stacks: stacks,
}));
};

const handleSelectPosition = (position: string): void => {
setSelectedOption((prevOptions) => ({
...prevOptions,
positions: prevOptions.positions.includes(position)
? prevOptions.positions.filter((prevPosition) => prevPosition !== position)
: [...prevOptions.positions, position],
}));
};


return (
<>
<h1>스터디/프로젝트 정보 입력</h1>
Expand All @@ -46,55 +79,83 @@ export default function RecruitmentRequestLayout({
</S.RadioButtonBox>
<S.SelectBox>
<h3>마감기간</h3>
<DeadlineDropdown setSelectedOptions={setSelectedOptions} />
<DeadlineDropdown
placeholder="마감 기간"
selectedOption={selectedOption.recruitEndAt}
onSelect={(option) => {
setSelectedOption((prevOptions) => ({
...prevOptions,
recruitEndAt: format(option, "yyyy.MM.dd"),
}));
}}
/>
</S.SelectBox>
<S.SelectBox>
<h3>진행 기간</h3>
<RecruitDropdown
menuInfoType="progressPeriod"
onClick={(option) => handleSelectOption({ optionType: "progressPeriod", option })}
<Dropdown
placeholder={progressPeriod.defaultValue}
options={progressPeriod.options}
selectedOption={selectedOption.progressPeriod}
onSelect={(option) => {
setSelectedOption((prevOption) => ({ ...prevOption, progressPeriod: option }));
}}
/>
</S.SelectBox>
<S.SelectBox>
<h3>모집 인원</h3>
<RecruitDropdown
menuInfoType="capacity"
onClick={(option) => handleSelectOption({ optionType: "capacity", option })}
<Dropdown
placeholder={capacity.defaultValue}
options={capacity.options}
selectedOption={findOptionByValue(capacity.values, capacity.options, selectedOption.capacity)}
onSelect={(option) => {
const optionIndex = capacity.options.indexOf(option);
const value = capacity.values[optionIndex];
setSelectedOption((prevOption) => ({ ...prevOption, capacity: value }));
}}
/>
</S.SelectBox>
<S.SelectBox>
<h3>진행 방식</h3>
<RecruitDropdown
menuInfoType="progressWay"
onClick={(option) => handleSelectOption({ optionType: "progressWay", option })}
/>
<S.DropdownWrapper>
<Dropdown
placeholder={progressWay.defaultValue}
options={progressWay.options}
selectedOption={selectedOption?.progressWay}
onSelect={(option) => {
setSelectedOption((prevOption) => ({ ...prevOption, progressWay: option }));
}}
/>
</S.DropdownWrapper>
</S.SelectBox>
<S.SelectBox>
<h3>연락 방법</h3>
<RecruitDropdown
menuInfoType="contactWay"
onClick={(option) => handleSelectOption({ optionType: "contactWay", option })}
onChange={(link) => handleChangeLink(link)}
<Dropdown
placeholder={contactWay.defaultValue}
options={contactWay.options}
selectedOption={selectedOption?.contactWay}
onSelect={(option) => {
setSelectedOption((prevOption) => ({ ...prevOption, contactWay: option }));
}}
/>
</S.SelectBox>
</S.GirdContainer>
<S.SelectChipBox>
<h3>기술 스택</h3>
<MultiselectDropdown
selectedOptions={selectedOptions.stacks}
selectedOptions={selectedOption.stacks}
onSelectChange={(stack) => handleSelectStack(stack)}
/>
</S.SelectChipBox>
<S.SelectChipBox>
<h3>모집 포지션</h3>
<SelectPositionChipList
selectedPositions={selectedOptions.positions}
selectedPositions={selectedOption.positions}
onChipClick={(position) => handleSelectPosition(position)}
/>
</S.SelectChipBox>
<S.QuillBox>
<h1>스터디/프로젝트 소개</h1>
<QuillEditor setSelectedOptions={setSelectedOptions} />
<QuillEditor setSelectedOption={setSelectedOption} />
</S.QuillBox>
</>
);
Expand Down
47 changes: 1 addition & 46 deletions co-kkiri/src/pages/Recruit/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,55 +19,10 @@ export default function Recruit() {
link: "",
});

const handleSelectType = (type: string): void => {
setSelectedOptions((prevOptions) => ({
...prevOptions,
type: type,
}));
};

const handleSelectOption = ({ optionType, option }: { optionType: string; option: string | number }): void => {
setSelectedOptions((prevOptions) => ({
...prevOptions,
[optionType]: option,
}));
};

const handleChangeLink = (link: string): void => {
setSelectedOptions((prevOptions) => ({
...prevOptions,
link: link,
}));
};

const handleSelectStack = (stacks: string[]): void => {
setSelectedOptions((prevOptions) => ({
...prevOptions,
stacks: stacks,
}));
};

const handleSelectPosition = (position: string): void => {
setSelectedOptions((prevOptions) => ({
...prevOptions,
positions: prevOptions.positions.includes(position)
? prevOptions.positions.filter((prevPosition) => prevPosition !== position)
: [...prevOptions.positions, position],
}));
};
console.log(selectedOptions);
return (
<S.Container>
<S.SelectContainer>
<RecruitmentRequestLayout
handleSelectType={handleSelectType}
handleSelectOption={handleSelectOption}
handleSelectStack={handleSelectStack}
handleChangeLink={handleChangeLink}
handleSelectPosition={handleSelectPosition}
selectedOptions={selectedOptions}
setSelectedOptions={setSelectedOptions}
/>
<RecruitmentRequestLayout />
<S.SubmitButtonBox>
<Button variant="primaryLight">취소하기</Button>
<Button variant="primary">글 등록하기</Button>
Expand Down
Loading