diff --git a/src/App.tsx b/src/App.tsx
index 9f7de79..cb4ff53 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -11,6 +11,9 @@ 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";
+import IntroduceRunner from "./modules/Runner/IntroduceRunner.tsx";
+import ApplyRunner from "./modules/Runner/ApplyRunner.tsx";
function App() {
const defaultTheme = createTheme();
@@ -22,9 +25,11 @@ function App() {
-
- } />
- } />
+ } />
+ } />
+ } />
+ } />
+ } />
} />
} />
} />
diff --git a/src/components/common/InputField.tsx b/src/components/common/InputField.tsx
new file mode 100644
index 0000000..f77a3b4
--- /dev/null
+++ b/src/components/common/InputField.tsx
@@ -0,0 +1,48 @@
+// 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;
+ onChange: (e: any) => void;
+}
+
+const InputField: React.FC = ({
+ id,
+ label,
+ defaultValue = '',
+ rows = 3,
+ fullWidth = true,
+ placeholder = '',
+ multiline = false,
+ onChange,
+}) => {
+ return (
+
+
+
+ );
+};
+
+export default InputField;
diff --git a/src/components/common/MultipleChoiceField.tsx b/src/components/common/MultipleChoiceField.tsx
new file mode 100644
index 0000000..cd61e5f
--- /dev/null
+++ b/src/components/common/MultipleChoiceField.tsx
@@ -0,0 +1,139 @@
+// 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;
+ onChange?: (e: any) => void;
+}
+
+const MultipleChoiceField: FC = ({
+ id,
+ label,
+ options,
+ defaultValue,
+ fullWidth = true,
+ isMultipleOption = false,
+ isOtherOption = false,
+ onChange,
+}) => {
+ 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/components/common/PrivacyPolicy.tsx b/src/components/common/PrivacyPolicy.tsx
new file mode 100644
index 0000000..afe5b7c
--- /dev/null
+++ b/src/components/common/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/Builder/ApplyBuilder.tsx b/src/modules/Builder/ApplyBuilder.tsx
index e69de29..708895d 100644
--- a/src/modules/Builder/ApplyBuilder.tsx
+++ b/src/modules/Builder/ApplyBuilder.tsx
@@ -0,0 +1,287 @@
+import { Box, Button } from "@mui/material";
+import InputField from "../../components/common/InputField";
+import MultipleChoiceField from "../../components/common/MultipleChoiceField";
+import PrivacyPolicy from "../../components/common/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)}
+ />
+ 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);
+ }}
+ />
+ {
+ handleChange("buildDescription", e.target.value);
+ }}
+ />
+ {
+ handleChange("buildReason", e.target.value);
+ }}
+ />
+ {
+ handleChange("buildGain", e.target.value);
+ }}
+ />
+ {
+ handleChange("buildResearchMember", e.target.value);
+ }}
+ />
+ {
+ handleChange("expectation", e.target.value);
+ }}
+ />
+ {
+ handleChange("question", e.target.value);
+ }}
+ />
+ {
+ handleChange("availability", e.target.value);
+ }}
+ />
+ {
+ handleChange("isBuilder", e.target.value === "y" ? true : false);
+ }}
+ />
+
+
+
+ {
+ handleChange("ruleAgree", e.target.value === "y" ? true : false);
+ }}
+ />
+ {
+ handleChange("privacyAgree", e.target.value === "y" ? true : false);
+ }}
+ />
+
+
+
+
+
+ 제출하기
+
+ >
+ );
+};
+
+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/Header/Header.tsx b/src/modules/Header/Header.tsx
index 01c9b8c..c326035 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";
@@ -29,8 +28,8 @@ interface Props {
const drawerWidth = window.innerWidth * 0.7;
const navItems = [
{ name: "커뮤니티", path: "/community", permission: "" },
- { name: "빌더", path: "/builder", permission: "" },
- { name: "러너", path: "/runner", permission: "" },
+ { name: "빌더", path: "/builder/intro", permission: "" },
+ { name: "러너", path: "/runner/intro", permission: "" },
{ name: "빙고", path: "/bingo", permission: "" },
];
diff --git a/src/modules/Runner/ApplyRunner.tsx b/src/modules/Runner/ApplyRunner.tsx
index e69de29..12cf449 100644
--- a/src/modules/Runner/ApplyRunner.tsx
+++ b/src/modules/Runner/ApplyRunner.tsx
@@ -0,0 +1,273 @@
+import { Box, Button } from "@mui/material";
+import InputField from "../../components/common/InputField";
+import MultipleChoiceField from "../../components/common/MultipleChoiceField";
+import PrivacyPolicy from "../../components/common/PrivacyPolicy";
+import AgreeDatasetUsage from "./component/AgreeDatasetUsage";
+import { useState } from "react";
+
+const ApplyRunner = () => {
+ const [formData, setFormData] = useState({
+ email: "",
+ name: "",
+ phone: "",
+ introduceMe: "",
+ discordId: "",
+ notionId: "",
+ credentialLink: "",
+ portfolio: "",
+ applyFirst: "",
+ applySecond: "",
+ applyThird: "",
+ motivation: "",
+ myFuture: "",
+ myLevel: "",
+ etc: "",
+ question: "",
+ availability: "",
+ privacyAgree: true,
+ agreeDatasetUsage: 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)}
+ />
+ handleChange("introduceMe", e.target.value)}
+ />
+ handleChange("discordId", e.target.value)}
+ />
+ handleChange("notionId", e.target.value)}
+ />
+ handleChange("credentialLink", e.target.value)}
+ />
+ handleChange("portfolio", e.target.value)}
+ />
+ {/* 이 부분 DB랑 연동시켜야함 */}
+ {
+ handleChange("applyFirst", e.target.value);
+ }}
+ />
+ {
+ handleChange("applySecond", e.target.value);
+ }}
+ />
+ {
+ handleChange("applyThird", e.target.value);
+ }}
+ />
+ {
+ handleChange("motivation", e.target.value);
+ }}
+ />
+ {
+ handleChange("myFuture", e.target.value);
+ }}
+ />
+ {
+ handleChange("myLevel", e.target.value);
+ }}
+ />
+ {
+ handleChange("etc", e.target.value);
+ }}
+ />
+ {
+ handleChange("question", e.target.value);
+ }}
+ />
+ {
+ handleChange("availability", e.target.value);
+ }}
+ />
+ {
+ handleChange("privacyAgree", e.target.value === "y" ? true : false);
+ }}
+ />
+
+
+
+
+
+
+ {
+ handleChange(
+ "agreeDatasetUsage",
+ e.target.value === "y" ? true : false
+ );
+ }}
+ />
+
+ 제출하기
+
+ >
+ );
+};
+
+export default ApplyRunner;
diff --git a/src/modules/Runner/IntroduceRunner.tsx b/src/modules/Runner/IntroduceRunner.tsx
new file mode 100644
index 0000000..d6a6730
--- /dev/null
+++ b/src/modules/Runner/IntroduceRunner.tsx
@@ -0,0 +1,95 @@
+import { Container, Typography, Theme, Button } from "@mui/material";
+import IntroduceBanner from "./component/IntroduceBanner";
+import { styled } from "@mui/system";
+
+const ImageContainer = styled(Container)({
+ display: "flex",
+ width: "100%",
+ justifyContent: "center",
+ alignItems: "center",
+});
+
+const MainContainer = styled(Container)({
+ textAlign: "center",
+ padding: (theme: Theme) => theme.spacing(4),
+ margin: (theme: Theme) => theme.spacing(4),
+});
+
+const Title = styled(Typography)({
+ fontSize: "2.5rem",
+ fontWeight: "bold",
+ marginBottom: (theme: Theme) => theme.spacing(2),
+ color: (theme: Theme) => theme.palette.primary.main,
+});
+
+const Description = styled(Typography)({
+ fontSize: "1.2rem",
+ marginBottom: (theme: Theme) => theme.spacing(4),
+});
+
+const IntroduceRunner = () => {
+ return (
+
+
+
+
+ 가짜연구소 러너 8기 모집
+
+ [안내]
+
+ 가짜연구소의 아카데미에서는 이론적 지식을 습득하고, 다양한 실험 및
+ 연구도 진행하며, 리뷰와 토론을 통해 학문적, 경험적 성장을 이루는
+ 아카데미를 운영하고 있습니다. 아카데미는 스터디, 펠로우쉽, 오픈랩,
+ 리서치로 구성되어 있습니다. 청강이 가능한 스터디는 누구나 참여하실 수
+ 있으니, 하반기 동안 지속적으로는 참여하기 어려운 상황이시라면
+ 가짜연구소 디스코드의 #가짜연-청강 채널을 눈여겨봐주세요!
+
+
+ 실력이 출중한 분이 필요하기 보다는, 팀원들과 함께 시너지를 내며
+ 목표까지 완주하는 것이 중요합니다! 그간의 경험을 살펴보면, 다양한
+ 사람들이 팀원으로 함께하며 서로 부족한 부분을 채워주더라구요! 따라서,
+ 함께 성장할 의지만 있다면, 가짜연구소의 공유, 동기부여, 함꼐하는
+ 즐거움과 함께 고속 성장을 하실 수 있습니다!
+
+
+ *모집 기간: 12월 12일(화)~27일(수)
+ *모집 부문:
+ 1) 스터디: 단순한 스터디 그룹을 넘어, 공유와 기여를 통해 한층 더
+ 성장할 기회가 있는 가짜연구소의 스터디 그룹입니다!
+ *지원 자격: - 머신러닝에 관심이 있고, 책임감 있게 팀과 공동체를
+ 이끌며 함께 성장하고 싶은 누구나
+ *활동 기간: 8기, 2023년 상반기 (팀별로 상이함으로 팀별 계획표를 참조)
+
+ *선정 결과 발표: 12월 29일(금), 메일을 통해 안내 (스팸 메일함 확인
+ 필요)
+
+ *조정 기간: 12월 29일(금)~ 1월 6일(토)
+
+ 가짜연구소 소개: https://pseudo-lab.com/
+
+ 팀별 계획표: https://pseudo-lab.com/d16a59aa6f3847a092f8d55b89279b0a
+
+ 가짜연구소 디스코드: https://discord.gg/EPurkHVtp2
+
+
+
+
+ 러너 지원하러 가기
+
+
+ );
+};
+
+export default IntroduceRunner;
diff --git a/src/modules/Runner/SelectionRunnder.tsx b/src/modules/Runner/SelectionRunnder.tsx
deleted file mode 100644
index e69de29..0000000
diff --git a/src/modules/Runner/IntroduceRunnder.tsx b/src/modules/Runner/SelectionRunner.tsx
similarity index 100%
rename from src/modules/Runner/IntroduceRunnder.tsx
rename to src/modules/Runner/SelectionRunner.tsx
diff --git a/src/modules/Runner/component/AgreeDatasetUsage.tsx b/src/modules/Runner/component/AgreeDatasetUsage.tsx
new file mode 100644
index 0000000..6f055cf
--- /dev/null
+++ b/src/modules/Runner/component/AgreeDatasetUsage.tsx
@@ -0,0 +1,43 @@
+// BuilderRules.tsx
+import React from "react";
+import {
+ Container,
+ Typography,
+ Box,
+ List,
+ ListItem,
+ ListItemText,
+} from "@mui/material";
+
+const AgreeDatasetUsage: React.FC = () => {
+ return (
+
+
+
+ 데이터셋 활용 동의
+
+
+ Kaggle에서는 2018년부터 매년 DS & ML Survey를 진행하고, 이를
+ 데이터셋으로 구축하여 공개하고 있습니다. 학계/업계에 대한 의미 있는
+ 통찰력을 가질 수 있는 기회로, 가짜연구소에서도 유사하게 진행하고자
+ 합니다. 여러분들이 입력해주신 정보와 출결 정보에서 개인정보를
+ 제거하고, 데이터셋으로 만들어 비영리적으로 공개하고자 합니다. 혹시
+ 동의하시나요?
+
+
+
+ 활용가치 예시: 타이타닉 생존자 예측 문제에서 아이디어를 얻어,
+ 가짜연구소 생존자(=완주자) 예측
+
+
+
+ ※ 동의하지 않으시면 사용 및 공개하지 않을 예정이며, 동의 여부 정보가
+ 선정과정에서 빌더에게 전달되지 않기에 러너 선정에 어떠한 영향도 미치지
+ 않습니다
+
+
+
+ );
+};
+
+export default AgreeDatasetUsage;
diff --git a/src/modules/Runner/component/IntroduceBanner.tsx b/src/modules/Runner/component/IntroduceBanner.tsx
new file mode 100644
index 0000000..d165499
--- /dev/null
+++ b/src/modules/Runner/component/IntroduceBanner.tsx
@@ -0,0 +1,27 @@
+import { styled } from "@mui/system";
+import pseudoLabLogo from "../../assets/pseudo_lab_logo.png";
+import { Link } from "react-router-dom";
+
+type LogoImageProps = {
+ maxWidth: string;
+ width: string;
+ height: string;
+ marginRight?: string;
+};
+
+const IntroduceBanner = (props: LogoImageProps) => {
+ const LogoImageStyle = styled("img")({
+ width: props.width,
+ height: props.height,
+ marginRight: props.marginRight, // 이미지와 텍스트 사이에 간격을 조절
+ });
+
+ return (
+
+ );
+};
+
+export default IntroduceBanner;