Skip to content

Commit

Permalink
Feat: 모집글 페이지 드랍다운 관련 기능 수정 (#137)
Browse files Browse the repository at this point in the history
* Feat:드랍관련 변경내용 적용

* Feat:link 추가 입력창 기능구현

* Feat:드랍다운 유효성 hook-form기능 추가

* Feat:링크 인풋 유효성 검사 기능 추가
  • Loading branch information
JIS0098 authored Mar 23, 2024
1 parent 74a22aa commit b14e96d
Show file tree
Hide file tree
Showing 7 changed files with 255 additions and 83 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import styled from "styled-components";
import DESIGN_TOKEN from "@/styles/tokens";
import { DROPDOWN_INFO } from "@/constants/dropDown";

interface LinkInputProps {
selectedOption: string;
onChange: (value: string) => void;
}

export default function LinkInput({ selectedOption, onChange }: LinkInputProps) {
const { recruitment } = DROPDOWN_INFO;
const optionIndex = recruitment.contactWay.options?.indexOf(selectedOption);
const value = recruitment.contactWay.placeholder[optionIndex];

return (
<Container>
{selectedOption !== "기타" ? <Input placeholder={value} onChange={(e) => onChange(e.target.value)} /> : null}
</Container>
);
}

const { color } = DESIGN_TOKEN;

const Container = styled.div`
width: 100%;
height: 4.8rem;
`;

const Input = styled.input`
width: 100%;
height: 4.8rem;
border-radius: 0.5rem;
border: 0.1rem solid ${color.gray[2]};
padding: 1.858rem;
&:focus {
outline: none;
}
`;
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,18 @@ export const Container = styled.form`
`;

export const GirdContainer = styled.div`
& h3 {
display: flex;
& span {
color: ${color.red};
}
}
& p {
color: ${color.red};
}
display: grid;
gap: 4rem;
grid-template-areas:
Expand Down Expand Up @@ -62,6 +74,10 @@ export const RadioButtonBox = styled.div`
display: flex;
gap: 3rem;
}
& p {
margin-top: -1.2rem;
}
`;

export const RadioButtonWarper = styled.div`
Expand Down Expand Up @@ -93,11 +109,21 @@ export const SelectChipBox = styled.div`
flex-direction: column;
gap: 2rem;
& h3 {
& span {
color: ${color.red};
}
}
& > div {
display: flex;
flex-wrap: wrap;
gap: 0.8rem;
}
& p {
margin-top: -0.95rem;
}
`;

export const QuillBox = styled.div`
Expand All @@ -109,3 +135,34 @@ export const QuillBox = styled.div`
border-bottom: none;
}
`;

export const SubmitButtonBox = styled.div`
display: grid;
grid-template-columns: repeat(2, 15.6rem);
gap: 1.2rem;
justify-content: end;
`;

export const SelectContainer = styled.form`
display: flex;
flex-direction: column;
width: 77.4rem;
gap: 4rem;
& p {
color: ${color.red};
}
& h1 {
border-bottom: 0.1rem solid ${color.gray[2]};
padding-bottom: 2rem;
}
${mediaQueries.tablet} {
width: 46.2rem;
}
${mediaQueries.mobile} {
width: 32rem;
}
`;
192 changes: 150 additions & 42 deletions co-kkiri/src/components/commons/RecruitmentRequestLayout/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,21 @@ import SelectPositionChipList from "@/components/commons/SelectPositionChipList"
import * as S from "./RecruitLayout.styled";
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";

import LinkInput from "./LinkInput";
import Button from "../Button";
import { useForm, Controller, SubmitHandler, FieldValues } from "react-hook-form";
import DESIGN_TOKEN from "@/styles/tokens";
export default function RecruitmentRequestLayout() {
const {
recruitment: { capacity, progressPeriod, progressWay, contactWay },
} = DROPDOWN_INFO;

const [selectedOption, setSelectedOption] = useState<RecruitmentRequest>({
type: "",
recruitEndAt: "",
progressPeriod: "",
capacity: 0,
capacity: undefined,
contactWay: "",
progressWay: "",
stacks: [],
Expand Down Expand Up @@ -59,35 +59,81 @@ export default function RecruitmentRequestLayout() {
}));
};


const {
handleSubmit,
control,
formState: { errors },
} = useForm();

const onSubmit: SubmitHandler<FieldValues> = (data) => {
console.log(data);
};

return (
<>
<S.SelectContainer>
<h1>스터디/프로젝트 정보 입력</h1>
<S.GirdContainer>
<S.RadioButtonBox>
<h3>모집 구분</h3>
<h3>
모집 구분 <span>*</span>
</h3>
<span>
<S.RadioButtonWarper>
<RadioButton value="PROJECT" onClick={() => handleSelectType("PROJECT")} />
<span>프로젝트</span>
</S.RadioButtonWarper>
<S.RadioButtonWarper>
<RadioButton value="STUDY" onClick={() => handleSelectType("STUDY")} />
<span>스터디</span>
</S.RadioButtonWarper>
<Controller
name="type"
control={control}
rules={{ required: true }}
render={({ field }) => (
<>
<S.RadioButtonWarper>
<RadioButton
value="STUDY"
onClick={() => {
handleSelectType("STUDY");
field.onChange("STUDY");
}}
/>
<span>스터디</span>
</S.RadioButtonWarper>
<S.RadioButtonWarper>
<RadioButton
value="PROJECT"
onClick={() => {
handleSelectType("PROJECT");
field.onChange("PROJECT");
}}
/>
<span>프로젝트</span>
</S.RadioButtonWarper>
</>
)}
/>
</span>
{errors.type && <p>모집 구분을 선택해주세요.</p>}
</S.RadioButtonBox>
<S.SelectBox>
<h3>마감기간</h3>
<DeadlineDropdown
placeholder="마감 기간"
selectedOption={selectedOption.recruitEndAt}
onSelect={(option) => {
setSelectedOption((prevOptions) => ({
...prevOptions,
recruitEndAt: format(option, "yyyy.MM.dd"),
}));
}}
<h3>
모집 마감 기간 <span>*</span>
</h3>
<Controller
name="recruitEndAt"
control={control}
rules={{ required: true }}
render={({ field }) => (
<>
<DeadlineDropdown
placeholder="모집 마감 기간"
selectedOption={selectedOption.recruitEndAt}
onSelect={(option) => {
setSelectedOption((prevOptions) => ({
...prevOptions,
recruitEndAt: format(option, "yyyy.MM.dd"),
}));
field.onChange(format(option, "yyyy.MM.dd"));
}}
/>
{errors.recruitEndAt && <p>모집 마감 기간을 선택해주세요.</p>}
</>
)}
/>
</S.SelectBox>
<S.SelectBox>
Expand Down Expand Up @@ -115,17 +161,28 @@ export default function RecruitmentRequestLayout() {
/>
</S.SelectBox>
<S.SelectBox>
<h3>진행 방식</h3>
<S.DropdownWrapper>
<Dropdown
placeholder={progressWay.defaultValue}
options={progressWay.options}
selectedOption={selectedOption?.progressWay}
onSelect={(option) => {
setSelectedOption((prevOption) => ({ ...prevOption, progressWay: option }));
}}
/>
</S.DropdownWrapper>
<h3>
진행 방식 <span>*</span>
</h3>
<Controller
name="progressWay"
control={control}
rules={{ required: true }}
render={({ field }) => (
<S.DropdownWrapper>
<Dropdown
placeholder={progressWay.defaultValue}
options={progressWay.options}
selectedOption={selectedOption?.progressWay}
onSelect={(option) => {
setSelectedOption((prevOption) => ({ ...prevOption, progressWay: option }));
field.onChange(option);
}}
/>
</S.DropdownWrapper>
)}
/>
{errors.progressWay && <p>진행방식을 선택해주세요.</p>}
</S.SelectBox>
<S.SelectBox>
<h3>연락 방법</h3>
Expand All @@ -137,6 +194,36 @@ export default function RecruitmentRequestLayout() {
setSelectedOption((prevOption) => ({ ...prevOption, contactWay: option }));
}}
/>
{selectedOption.contactWay !== "기타" && (
<>
<Controller
name={selectedOption.contactWay}
control={control}
rules={{
pattern: {
value:
selectedOption.contactWay === "이메일"
? /^[0-9a-zA-Z]([-_.]?[0-9a-zA-Z])*@[0-9a-zA-Z]([-_.]?[0-9a-zA-Z])*\.[a-zA-Z]{2,3}$/i
: /^(https?:\/\/)?([\da-z.-]+)\.([a-z.]{2,})\/?([\w/#.-]*)*(\?[\w=&.-]*)?(#[\w-]*)?$/,
message:
selectedOption.contactWay === "이메일"
? "올바른 이메일 형식이 아닙니다."
: "올바른 url 형식이 아닙니다",
},
}}
render={({ field }) => (
<LinkInput
selectedOption={selectedOption.contactWay}
onChange={(link) => {
setSelectedOption((prevOption) => ({ ...prevOption, link: link }));
field.onChange(link);
}}
/>
)}
/>
{errors[selectedOption.contactWay] && <p>{String(errors[selectedOption.contactWay]?.message)}</p>}
</>
)}
</S.SelectBox>
</S.GirdContainer>
<S.SelectChipBox>
Expand All @@ -147,16 +234,37 @@ export default function RecruitmentRequestLayout() {
/>
</S.SelectChipBox>
<S.SelectChipBox>
<h3>모집 포지션</h3>
<SelectPositionChipList
selectedPositions={selectedOption.positions}
onChipClick={(position) => handleSelectPosition(position)}
<h3>
모집 포지션<span>*</span>
</h3>
<Controller
name="positions"
control={control}
rules={{ required: true }}
render={({ field }) => (
<>
<SelectPositionChipList
selectedPositions={selectedOption.positions}
onChipClick={(position) => {
handleSelectPosition(position);
field.onChange(position);
}}
/>
</>
)}
/>
{errors.positions && <p>모집 포지션을 선택해주세요.</p>}
</S.SelectChipBox>
<S.QuillBox>
<h1>스터디/프로젝트 소개</h1>
<QuillEditor setSelectedOption={setSelectedOption} />
</S.QuillBox>
</>
<S.SubmitButtonBox>
<Button variant="primaryLight">취소하기</Button>
<Button variant="primary" onClick={handleSubmit(onSubmit)}>
글 등록하기
</Button>
</S.SubmitButtonBox>
</S.SelectContainer>
);
}
Loading

0 comments on commit b14e96d

Please sign in to comment.