From 01514ce76ddd624b7171c0a0ef06ae7bc33ea300 Mon Sep 17 00:00:00 2001
From: mksoo <>
Date: Sun, 2 Jun 2024 16:33:19 +0900
Subject: [PATCH 1/5] =?UTF-8?q?feature(=EB=AA=A8=EC=A7=91)builder=20apply?=
=?UTF-8?q?=20=ED=99=94=EB=A9=B4=20=EA=B5=AC=EC=84=B1?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/App.tsx | 6 +-
src/components/common/InputField.tsx | 45 ++++
src/components/common/MultipleChoiceField.tsx | 137 +++++++++++++
src/modules/Builder/ApplyBuilder.tsx | 193 ++++++++++++++++++
src/modules/Builder/IntroduceBuilder.tsx | 4 +-
.../Builder/component/BuilderRules.tsx | 43 ++++
.../Builder/component/PrivacyPolicy.tsx | 66 ++++++
src/modules/Header/Header.tsx | 5 +-
8 files changed, 493 insertions(+), 6 deletions(-)
create mode 100644 src/components/common/InputField.tsx
create mode 100644 src/components/common/MultipleChoiceField.tsx
create mode 100644 src/modules/Builder/component/BuilderRules.tsx
create mode 100644 src/modules/Builder/component/PrivacyPolicy.tsx
diff --git a/src/App.tsx b/src/App.tsx
index 9f7de79..1adac04 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -11,6 +11,7 @@ import Board from "./modules/Community/index.tsx";
import BoardView from "./modules/Community/BoardView.tsx";
import { Container, CssBaseline } from "@mui/material";
import { createTheme, ThemeProvider } from "@mui/material/styles";
+import ApplyBuilder from "./modules/Builder/ApplyBuilder.tsx";
function App() {
const defaultTheme = createTheme();
@@ -22,8 +23,9 @@ function App() {
-
- } />
+ } />
+ } />
+ } />
} />
} />
} />
diff --git a/src/components/common/InputField.tsx b/src/components/common/InputField.tsx
new file mode 100644
index 0000000..885ce54
--- /dev/null
+++ b/src/components/common/InputField.tsx
@@ -0,0 +1,45 @@
+// ReusableInput.tsx
+import React from 'react';
+import { TextField, Box } from '@mui/material';
+
+interface InputFieldProps {
+ id: string;
+ label: string;
+ defaultValue?: string;
+ rows?: number;
+ fullWidth?: boolean;
+ placeholder?: string;
+ multiline?: boolean;
+}
+
+const InputField: React.FC = ({
+ id,
+ label,
+ defaultValue = '',
+ rows = 3,
+ fullWidth = true,
+ placeholder = '',
+ multiline = false,
+}) => {
+ return (
+
+
+
+ );
+};
+
+export default InputField;
diff --git a/src/components/common/MultipleChoiceField.tsx b/src/components/common/MultipleChoiceField.tsx
new file mode 100644
index 0000000..baf3a36
--- /dev/null
+++ b/src/components/common/MultipleChoiceField.tsx
@@ -0,0 +1,137 @@
+// MultipleChoiceField.tsx
+import React, { ChangeEvent, FC, useState } from "react";
+import {
+ FormControl,
+ FormLabel,
+ RadioGroup,
+ FormControlLabel,
+ Radio,
+ Box,
+ FormGroup,
+ Checkbox,
+ TextField,
+} from "@mui/material";
+
+interface Option {
+ value: string;
+ label: string;
+}
+
+interface MultipleChoiceFieldProps {
+ id: string;
+ label: string;
+ options: Option[];
+ defaultValue?: string;
+ fullWidth?: boolean;
+ isMultipleOption?: boolean;
+ isOtherOption?: boolean;
+}
+
+const MultipleChoiceField: FC = ({
+ id,
+ label,
+ options,
+ defaultValue,
+ fullWidth = true,
+ isMultipleOption = false,
+ isOtherOption = false,
+}) => {
+ const [selectedOptions, setSelectedOptions] = useState(
+ defaultValue ? [defaultValue] : []
+ );
+ const [selectedRadio, setSelectedRadio] = useState(
+ defaultValue || ""
+ );
+
+ const handleRadioChange = (event: ChangeEvent) => {
+ setSelectedRadio(event.target.value);
+ };
+
+ const handleChange = (event: ChangeEvent) => {
+ const value = event.target.value;
+ setSelectedOptions((prev) =>
+ prev.includes(value)
+ ? prev.filter((option) => option !== value)
+ : [...prev, value]
+ );
+ };
+
+ return (
+
+ {isMultipleOption ? (
+
+
+
+ {label}
+
+
+ {options.map((option) => (
+
+ }
+ label={option.label}
+ />
+ ))}
+
+
+
+ ) : (
+
+
+
+ {label}
+
+
+ {options.map((option) => (
+ }
+ label={option.label}
+ />
+ ))}
+ {isOtherOption && (
+ }
+ label="기타"
+ />
+ )}
+
+ {selectedRadio === "other" && (
+
+ )}
+
+
+ )}
+
+ );
+};
+
+export default MultipleChoiceField;
diff --git a/src/modules/Builder/ApplyBuilder.tsx b/src/modules/Builder/ApplyBuilder.tsx
index e69de29..636b459 100644
--- a/src/modules/Builder/ApplyBuilder.tsx
+++ b/src/modules/Builder/ApplyBuilder.tsx
@@ -0,0 +1,193 @@
+import { Box, Button } from "@mui/material";
+import InputField from "../../components/common/InputField";
+import MultipleChoiceField from "../../components/common/MultipleChoiceField";
+import PrivacyPolicy from "./component/PrivacyPolicy";
+import BuilderRules from "./component/BuilderRules";
+
+const ApplyBuilder = () => {
+ return (
+ <>
+ 빌더 지원서
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ >
+ );
+};
+
+export default ApplyBuilder;
diff --git a/src/modules/Builder/IntroduceBuilder.tsx b/src/modules/Builder/IntroduceBuilder.tsx
index d2e5188..6fda291 100644
--- a/src/modules/Builder/IntroduceBuilder.tsx
+++ b/src/modules/Builder/IntroduceBuilder.tsx
@@ -103,16 +103,18 @@ const IntroduceBuilder = () => {
diff --git a/src/modules/Builder/component/BuilderRules.tsx b/src/modules/Builder/component/BuilderRules.tsx
new file mode 100644
index 0000000..bdf09c1
--- /dev/null
+++ b/src/modules/Builder/component/BuilderRules.tsx
@@ -0,0 +1,43 @@
+// BuilderRules.tsx
+import React from 'react';
+import { Container, Typography, Box, List, ListItem, ListItemText } from '@mui/material';
+
+const BuilderRules: React.FC = () => {
+ return (
+
+
+
+ 가짜연구소 빌더(운영진) 활동 규칙
+
+
+ 가짜연구소에서는 빌더(운영진)이 프로젝트를 원활히 진행할 수 있도록 규칙과 도구, 그리고 도우미가 있습니다. 가짜연구소 커뮤니티와 빌더, 그리고 참여하는 러너까지 귀중한 시간을 낸 만큼! 원하는 바 모두 이루실 수 있기를 바라며 규칙을 만들었습니다. 물론 언제나 예외상황은 존재하겠지만, 가짜연구소 방식의 성장에 동참해주시면 감사드리겠습니다!
+
+
+
+
+ 1. 운영진 활동 규칙 (필수)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export default BuilderRules;
diff --git a/src/modules/Builder/component/PrivacyPolicy.tsx b/src/modules/Builder/component/PrivacyPolicy.tsx
new file mode 100644
index 0000000..afe5b7c
--- /dev/null
+++ b/src/modules/Builder/component/PrivacyPolicy.tsx
@@ -0,0 +1,66 @@
+// PrivacyPolicy.tsx
+import React from 'react';
+import { Container, Typography, Box, List, ListItem, ListItemText, FormControlLabel, Checkbox } from '@mui/material';
+
+const PrivacyPolicy: React.FC = () => {
+ return (
+
+
+
+ 개인정보 처리방침
+
+
+ 가짜연구소는 「개인정보 보호법」에 따라 여러분의 개인정보를 아래와 같이 수집 및 이용하고자 하며, 법에 따라 수집한 개인정보를 안전하게 보호하겠습니다. 아래의 사항에 대해 충분히 읽어보신 후 동의 여부를 체크해 주시기 바랍니다.
+
+
+
+
+ ▶ 개인정보의 수집·이용 목적
+
+
+
+
+
+
+
+
+
+
+ ▶ 수집하는 개인정보의 항목
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ▶ 개인정보의 보유·이용 기간
+
+
+ 가짜연구소 커뮤니티에서는 정보주체의 회원 가입일로부터 서비스를 제공하는 기간 동안에 한하여 가짜연구소 서비스를 이용하기 위한 최소한의 개인정보를 보유 및 이용 하게 됩니다. 회원가입/구글 폼 등을 통해 개인정보의 수집·이용, 제공 등에 대해 동의하신 내용은 언제든지 철회하실 수 있습니다. 회원 탈퇴를 요청하거나 수집/이용목적을 달성하거나 보유/이용기간이 종료한 경우, 사업 폐지 등의 사유발생시 개인 정보를 지체 없이 파기합니다.
+
+
+
+
+
+ ▶ 동의를 거부할 권리 및 동의 거부에 따른 불이익
+
+
+ 지원자는 개인정보의 수집, 이용 등과 관련한 위 사항에 대하여 원하지 않는 경우 동의를 거부할 수 있습니다.
+
+
+ 다만, 수집하는 개인정보의 항목에서 필수정보에 대한 수집 및 이용에 대하여 동의하지 않는 경우는 지원전형에 제한이 있을 수 있습니다.
+
+
+
+
+ );
+};
+
+export default PrivacyPolicy;
diff --git a/src/modules/Header/Header.tsx b/src/modules/Header/Header.tsx
index 01c9b8c..400ef4d 100644
--- a/src/modules/Header/Header.tsx
+++ b/src/modules/Header/Header.tsx
@@ -11,7 +11,6 @@ import {
Button,
Drawer,
IconButton,
- Typography,
} from "@mui/material";
import { Menu, Close } from "@mui/icons-material";
import PseudoLabLogo from "../../components/common/PseudoLabLogo";
@@ -28,8 +27,8 @@ interface Props {
const drawerWidth = window.innerWidth * 0.7;
const navItems = [
- { name: "커뮤니티", path: "/community", permission: "" },
- { name: "빌더", path: "/builder", permission: "" },
+ { name: "커뮤니티", path: "/comunity", permission: "" },
+ { name: "빌더", path: "/builder/intro", permission: "" },
{ name: "러너", path: "/runner", permission: "" },
{ name: "빙고", path: "/bingo", permission: "" },
];
From 94d7d2755881683cf77342822526b47ef77aa222 Mon Sep 17 00:00:00 2001
From: mksoo <>
Date: Sun, 2 Jun 2024 17:46:33 +0900
Subject: [PATCH 2/5] =?UTF-8?q?form=20=EC=9E=85=EB=A0=A5=20=EB=B0=9B?=
=?UTF-8?q?=EC=9D=80=EA=B1=B0=20state=EC=97=90=20=EB=84=A3=EB=8A=94?=
=?UTF-8?q?=EA=B1=B0=EA=B9=8C=EC=A7=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/components/common/InputField.tsx | 3 +
src/components/common/MultipleChoiceField.tsx | 8 +-
src/modules/Builder/ApplyBuilder.tsx | 134 +++++++++++++++---
3 files changed, 122 insertions(+), 23 deletions(-)
diff --git a/src/components/common/InputField.tsx b/src/components/common/InputField.tsx
index 885ce54..f77a3b4 100644
--- a/src/components/common/InputField.tsx
+++ b/src/components/common/InputField.tsx
@@ -10,6 +10,7 @@ interface InputFieldProps {
fullWidth?: boolean;
placeholder?: string;
multiline?: boolean;
+ onChange: (e: any) => void;
}
const InputField: React.FC = ({
@@ -20,6 +21,7 @@ const InputField: React.FC = ({
fullWidth = true,
placeholder = '',
multiline = false,
+ onChange,
}) => {
return (
= ({
defaultValue={defaultValue}
placeholder={placeholder}
multiline={multiline}
+ onChange={onChange}
/>
);
diff --git a/src/components/common/MultipleChoiceField.tsx b/src/components/common/MultipleChoiceField.tsx
index baf3a36..cd61e5f 100644
--- a/src/components/common/MultipleChoiceField.tsx
+++ b/src/components/common/MultipleChoiceField.tsx
@@ -25,6 +25,7 @@ interface MultipleChoiceFieldProps {
fullWidth?: boolean;
isMultipleOption?: boolean;
isOtherOption?: boolean;
+ onChange?: (e: any) => void;
}
const MultipleChoiceField: FC = ({
@@ -35,6 +36,7 @@ const MultipleChoiceField: FC = ({
fullWidth = true,
isMultipleOption = false,
isOtherOption = false,
+ onChange,
}) => {
const [selectedOptions, setSelectedOptions] = useState(
defaultValue ? [defaultValue] : []
@@ -79,7 +81,7 @@ const MultipleChoiceField: FC = ({
control={
}
@@ -107,14 +109,14 @@ const MultipleChoiceField: FC = ({
}
+ control={}
label={option.label}
/>
))}
{isOtherOption && (
}
+ control={}
label="기타"
/>
)}
diff --git a/src/modules/Builder/ApplyBuilder.tsx b/src/modules/Builder/ApplyBuilder.tsx
index 636b459..680fb70 100644
--- a/src/modules/Builder/ApplyBuilder.tsx
+++ b/src/modules/Builder/ApplyBuilder.tsx
@@ -3,17 +3,63 @@ import InputField from "../../components/common/InputField";
import MultipleChoiceField from "../../components/common/MultipleChoiceField";
import PrivacyPolicy from "./component/PrivacyPolicy";
import BuilderRules from "./component/BuilderRules";
+import { useState } from "react";
const ApplyBuilder = () => {
+ const [formData, setFormData] = useState({
+ email: "",
+ name: "",
+ phone: "",
+ introduceMe: "",
+ wasBuilder: false,
+ discordId: "",
+ notionId: "",
+ portfolio: "",
+ role: "",
+ buildName: "",
+ buildDescription: "",
+ buildReason: "",
+ buildGain: "",
+ buildResearchMember: "",
+ expectation: "",
+ question: "",
+ availability: "",
+ isBuilder: true,
+ ruleAgree: true,
+ privacyAgree: true,
+ });
+
+ const handleChange = (id: string, value: any) => {
+ setFormData((prevData) => ({
+ ...prevData,
+ [id]: value,
+ }));
+ };
+
+ const handleSubmit = () => {
+ console.log(formData);
+ };
+
return (
<>
빌더 지원서
-
-
+ handleChange("email", e.target.value)}
+ />
+ handleChange("name", e.target.value)}
+ />
handleChange("phone", e.target.value)}
/>
{
placeholder="3줄 자기소개"
multiline={true}
rows={3}
+ onChange={(e) => handleChange("introduceMe", e.target.value)}
/>
{
+ handleChange("wasBuilder", (e.target.value === "y" ? true : false));
+ }}
/>
handleChange("discordId", e.target.value)}
/>
handleChange("notionId", e.target.value)}
/>
handleChange("portfolio", e.target.value)}
/>
{
+ handleChange("role", e.target.value);
+ }}
/>
{
+ handleChange("buildName", e.target.value);
+ }}
/>
{
placeholder=""
multiline={true}
rows={3}
+ onChange={(e) => {
+ handleChange("buildDescription", e.target.value);
+ }}
/>
{
placeholder=""
multiline={true}
rows={3}
+ onChange={(e) => {
+ handleChange("buildReason", e.target.value);
+ }}
/>
{
placeholder=""
multiline={true}
rows={3}
+ onChange={(e) => {
+ handleChange("buildGain", e.target.value);
+ }}
/>
{
placeholder=""
multiline={true}
rows={3}
+ onChange={(e) => {
+ handleChange("buildResearchMember", e.target.value);
+ }}
/>
{
placeholder=""
multiline={true}
rows={3}
+ onChange={(e) => {
+ handleChange("expectation", e.target.value);
+ }}
/>
{
placeholder=""
multiline={true}
rows={3}
+ onChange={(e) => {
+ handleChange("question", e.target.value);
+ }}
/>
{
},
]}
isOtherOption={true}
+ onChange={(e) => {
+ handleChange("availability", e.target.value);
+ }}
/>
{
+ handleChange("wasBuilder", (e.target.value === "y" ? true : false));
+ }}
/>
{
id="rule-agree"
label="위의 규칙에 동의하십니까?"
options={[
- { value: "예", label: "yes" },
- { value: "아니오", label: "no" },
+ { value: "y", label: "예" },
+ { value: "n", label: "아니오" },
]}
+ onChange={(e) => {
+ handleChange("wasBuilder", (e.target.value === "y" ? true : false));
+ }}
/>
{
+ handleChange("wasBuilder", (e.target.value === "y" ? true : false));
+ }}
/>
{
>
-