Skip to content

Commit 01514ce

Browse files
mksoomksoo
authored andcommitted
feature(모집)builder apply 화면 구성
1 parent bea04a1 commit 01514ce

File tree

8 files changed

+493
-6
lines changed

8 files changed

+493
-6
lines changed

src/App.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import Board from "./modules/Community/index.tsx";
1111
import BoardView from "./modules/Community/BoardView.tsx";
1212
import { Container, CssBaseline } from "@mui/material";
1313
import { createTheme, ThemeProvider } from "@mui/material/styles";
14+
import ApplyBuilder from "./modules/Builder/ApplyBuilder.tsx";
1415

1516
function App() {
1617
const defaultTheme = createTheme();
@@ -22,8 +23,9 @@ function App() {
2223
<Container className="App">
2324
<Header />
2425
<Routes>
25-
<Route path="/" Component={Home} />
26-
<Route path="/builder" element={<IntroduceBuilder />} />
26+
<Route path="/" element={<Home />} />
27+
<Route path="/builder/intro" element={<IntroduceBuilder />} />
28+
<Route path="/builder/apply" element={<ApplyBuilder />} />
2729
<Route path="/runner" element={<Test />} />
2830
<Route path="/community/*" element={<Board />} />
2931
<Route path="/bingo" element={<Bingo />} />
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// ReusableInput.tsx
2+
import React from 'react';
3+
import { TextField, Box } from '@mui/material';
4+
5+
interface InputFieldProps {
6+
id: string;
7+
label: string;
8+
defaultValue?: string;
9+
rows?: number;
10+
fullWidth?: boolean;
11+
placeholder?: string;
12+
multiline?: boolean;
13+
}
14+
15+
const InputField: React.FC<InputFieldProps> = ({
16+
id,
17+
label,
18+
defaultValue = '',
19+
rows = 3,
20+
fullWidth = true,
21+
placeholder = '',
22+
multiline = false,
23+
}) => {
24+
return (
25+
<Box
26+
display="flex"
27+
justifyContent="center"
28+
alignItems="center"
29+
width="100%"
30+
marginY={2}
31+
>
32+
<TextField
33+
id={id}
34+
fullWidth={fullWidth}
35+
label={label}
36+
rows={rows}
37+
defaultValue={defaultValue}
38+
placeholder={placeholder}
39+
multiline={multiline}
40+
/>
41+
</Box>
42+
);
43+
};
44+
45+
export default InputField;
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
// MultipleChoiceField.tsx
2+
import React, { ChangeEvent, FC, useState } from "react";
3+
import {
4+
FormControl,
5+
FormLabel,
6+
RadioGroup,
7+
FormControlLabel,
8+
Radio,
9+
Box,
10+
FormGroup,
11+
Checkbox,
12+
TextField,
13+
} from "@mui/material";
14+
15+
interface Option {
16+
value: string;
17+
label: string;
18+
}
19+
20+
interface MultipleChoiceFieldProps {
21+
id: string;
22+
label: string;
23+
options: Option[];
24+
defaultValue?: string;
25+
fullWidth?: boolean;
26+
isMultipleOption?: boolean;
27+
isOtherOption?: boolean;
28+
}
29+
30+
const MultipleChoiceField: FC<MultipleChoiceFieldProps> = ({
31+
id,
32+
label,
33+
options,
34+
defaultValue,
35+
fullWidth = true,
36+
isMultipleOption = false,
37+
isOtherOption = false,
38+
}) => {
39+
const [selectedOptions, setSelectedOptions] = useState<string[]>(
40+
defaultValue ? [defaultValue] : []
41+
);
42+
const [selectedRadio, setSelectedRadio] = useState<string>(
43+
defaultValue || ""
44+
);
45+
46+
const handleRadioChange = (event: ChangeEvent<HTMLInputElement>) => {
47+
setSelectedRadio(event.target.value);
48+
};
49+
50+
const handleChange = (event: ChangeEvent<HTMLInputElement>) => {
51+
const value = event.target.value;
52+
setSelectedOptions((prev) =>
53+
prev.includes(value)
54+
? prev.filter((option) => option !== value)
55+
: [...prev, value]
56+
);
57+
};
58+
59+
return (
60+
<Box
61+
sx={{ border: "1px solid #ccc", padding: 2, borderRadius: 2 }}
62+
display="flex"
63+
width="100%"
64+
marginY={2}
65+
>
66+
{isMultipleOption ? (
67+
<FormControl component="fieldset" fullWidth={fullWidth}>
68+
<Box display="flex" flexDirection="column">
69+
<FormLabel
70+
component="label"
71+
style={{ alignSelf: "flex-start", marginRight: 16 }}
72+
>
73+
{label}
74+
</FormLabel>
75+
<FormGroup>
76+
{options.map((option) => (
77+
<FormControlLabel
78+
key={option.value}
79+
control={
80+
<Checkbox
81+
checked={selectedOptions.includes(option.value)}
82+
onChange={handleChange}
83+
value={option.value}
84+
/>
85+
}
86+
label={option.label}
87+
/>
88+
))}
89+
</FormGroup>
90+
</Box>
91+
</FormControl>
92+
) : (
93+
<FormControl component="fieldset" fullWidth={fullWidth}>
94+
<Box display="flex" flexDirection="column">
95+
<FormLabel
96+
component="label"
97+
style={{ alignSelf: "flex-start", marginRight: 16 }}
98+
>
99+
{label}
100+
</FormLabel>
101+
<RadioGroup
102+
aria-label={label}
103+
defaultValue={defaultValue}
104+
name={id}
105+
>
106+
{options.map((option) => (
107+
<FormControlLabel
108+
key={option.value}
109+
value={option.value}
110+
control={<Radio onChange={handleRadioChange} />}
111+
label={option.label}
112+
/>
113+
))}
114+
{isOtherOption && (
115+
<FormControlLabel
116+
value="other"
117+
control={<Radio onChange={handleRadioChange} />}
118+
label="기타"
119+
/>
120+
)}
121+
</RadioGroup>
122+
{selectedRadio === "other" && (
123+
<TextField
124+
label="기타 내용"
125+
// value={otherText}
126+
fullWidth
127+
margin="normal"
128+
/>
129+
)}
130+
</Box>
131+
</FormControl>
132+
)}
133+
</Box>
134+
);
135+
};
136+
137+
export default MultipleChoiceField;
Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
import { Box, Button } from "@mui/material";
2+
import InputField from "../../components/common/InputField";
3+
import MultipleChoiceField from "../../components/common/MultipleChoiceField";
4+
import PrivacyPolicy from "./component/PrivacyPolicy";
5+
import BuilderRules from "./component/BuilderRules";
6+
7+
const ApplyBuilder = () => {
8+
return (
9+
<>
10+
<h1>빌더 지원서</h1>
11+
<InputField id="email" label="이메일" placeholder="이메일" />
12+
<InputField id="name" label="이름" placeholder="이름" />
13+
<InputField
14+
id="phone"
15+
label="연락처(000-0000-0000)"
16+
placeholder="연락처"
17+
/>
18+
<InputField
19+
id="introduce-me"
20+
label="3줄 자기소개"
21+
placeholder="3줄 자기소개"
22+
multiline={true}
23+
rows={3}
24+
/>
25+
<MultipleChoiceField
26+
id="was-builder"
27+
label="이전에 빌더로 활동하신 적 있으신가요?"
28+
options={[
29+
{ value: "예", label: "yes" },
30+
{ value: "아니오", label: "no" },
31+
]}
32+
/>
33+
<InputField
34+
id="discordId"
35+
label="디스코드 ID"
36+
placeholder="디스코드 ID"
37+
/>
38+
<InputField
39+
id="notionId"
40+
label="노션 ID(이메일 형태; 이메일 주소가 아니면 초대가 어렵습니다."
41+
placeholder="노션 ID"
42+
/>
43+
<InputField
44+
id="portfolio"
45+
label="자신을 표현할 수 있는 링크를 하나 공유해주세요!"
46+
placeholder="e.g. linkedIn, github, blog, CV 등"
47+
/>
48+
<MultipleChoiceField
49+
id="role"
50+
label="지원하고자 하는 역할은 무엇인가요?"
51+
options={[
52+
{ value: "아카데미 빌더", label: "academy" },
53+
{ value: "펠로우십 빌더", label: "fellowship" },
54+
{ value: "커뮤니티 빌더", label: "comminity" },
55+
{ value: "데브 빌더", label: "dev" },
56+
{
57+
value: "리서치팀으로 전환(1기수 수료 후, 2기수 이상 활동 희망시",
58+
label: "research",
59+
},
60+
]}
61+
/>
62+
<InputField
63+
id="build-name"
64+
label='지원하신 역할로 진행하실 스터디/프로젝트명을 알려주세요. (리서치팀인 경우 팀명과 프로젝트 명을 각각 적어주셍. "팀명/프로젝트명" 형태)'
65+
placeholder=""
66+
/>
67+
<InputField
68+
id="build-description"
69+
label="위의 지원하신 역할에 대한 활동 계획을 간단히 적어주세요.
70+
(아카데미 빌더의 경우: 주제와 간단한 주차별 목표,
71+
커뮤니티 빌더의 경우: 기대하는 역할,
72+
데브 빌더의 경우: 개발하고 싶으신 것)"
73+
placeholder=""
74+
multiline={true}
75+
rows={3}
76+
/>
77+
<InputField
78+
id="build-reason"
79+
label="위의 지원하신 역할과 관련된 경험이 있으시다면, 얘기해주세요! 없으시다면, 지원하신 역할을 하고자하는 이유를 적어주세요."
80+
placeholder=""
81+
multiline={true}
82+
rows={3}
83+
/>
84+
<InputField
85+
id="build-gain"
86+
label="빌더 활동을 통해 얻고 싶은 것이 무엇인가요?"
87+
placeholder=""
88+
multiline={true}
89+
rows={3}
90+
/>
91+
<InputField
92+
id="build-research-member"
93+
label="(리서치팀 전환시 작성) 새로운 프로젝트에도 계속해서 참여할 사람이 누구인지 알려주세요. 그리고 추가 모집 여부도 알려주세요.
94+
(예: 김찬란 빌더, 김찬란, 김찬란 / 총 3명 / 추가 모집 0명 필요)"
95+
placeholder=""
96+
multiline={true}
97+
rows={3}
98+
/>
99+
<InputField
100+
id="expectation"
101+
label="여러분들이 가짜연구소 커뮤니티에 가장 기대하는 것은 무엇인가요?"
102+
placeholder=""
103+
multiline={true}
104+
rows={3}
105+
/>
106+
<InputField
107+
id="question"
108+
label="가짜연구소에 궁금한 점이 있으신가요?"
109+
placeholder=""
110+
multiline={true}
111+
rows={3}
112+
/>
113+
<MultipleChoiceField
114+
id=""
115+
label="가짜연구소의 대부분의 모임 및 활동들은 주 1회 이루어집니다. 2024년 상반기에 주 1회 모임을 이끄시거나 참여하시는 것이 가능하신지 생각해봐주세요!"
116+
options={[
117+
{
118+
value: "cool",
119+
label: "특별한 일정 (1-2회 정도) 외에는 가능합니다",
120+
},
121+
{
122+
value: "condition-busy",
123+
label:
124+
"취업이나 이직 등 변동사항이 생기면 그때부터는 활동이 어려울것 같습니다.",
125+
},
126+
{
127+
value: "busy",
128+
label: "너무 바쁘고, 다른 일정들이 많아 예상할 수가 없습니다.",
129+
},
130+
]}
131+
isOtherOption={true}
132+
/>
133+
<MultipleChoiceField
134+
id="is-builder"
135+
label='본 신청은 스터디나 일반 참가자가 아닌 "운영진"을 신청하는 것임을 확인하셨나요?'
136+
options={[
137+
{ value: "예", label: "yes" },
138+
{ value: "아니오", label: "no" },
139+
]}
140+
/>
141+
<Box
142+
sx={{
143+
display: "flex",
144+
flexDirection: "column",
145+
justifyContent: "center",
146+
alignItems: "flex-start",
147+
textAlign: "start",
148+
border: "1px solid #ccc",
149+
borderRadius: 2,
150+
marginBottom: 2,
151+
}}
152+
>
153+
<BuilderRules />
154+
</Box>
155+
<MultipleChoiceField
156+
id="rule-agree"
157+
label="위의 규칙에 동의하십니까?"
158+
options={[
159+
{ value: "예", label: "yes" },
160+
{ value: "아니오", label: "no" },
161+
]}
162+
/>
163+
<MultipleChoiceField
164+
id="privacy-agree"
165+
label="아래 개인정보 처리방침에 동의하십니까?"
166+
options={[
167+
{ value: "예", label: "yes" },
168+
{ value: "아니오", label: "no" },
169+
]}
170+
/>
171+
172+
<Box
173+
sx={{
174+
display: "flex",
175+
flexDirection: "column",
176+
justifyContent: "center",
177+
alignItems: "flex-start",
178+
textAlign: "start",
179+
border: "1px solid #ccc",
180+
borderRadius: 2,
181+
marginBottom: 2,
182+
}}
183+
>
184+
<PrivacyPolicy />
185+
</Box>
186+
<Button fullWidth={true} variant="contained" color="primary">
187+
제출하기
188+
</Button>
189+
</>
190+
);
191+
};
192+
193+
export default ApplyBuilder;

0 commit comments

Comments
 (0)