Skip to content

Commit

Permalink
[feat] 로그인페이지, 회원가입 페이지 완성 (예외 로직 보류) (#25)
Browse files Browse the repository at this point in the history
* feat(#22) : 회원가입 화면에서 headerstate 수정

* file(#22) : star 이미지 common 디렉터리로 이동

* file(#22) : star 이미지 common 디렉터리로 이동

* style(#22) : 헤더 height 변경

* feat(#22) : 원팀시작하기 버튼 생성

* feat(#22) : 이름, 활동지역, 전공, 희망직무 컴포넌트 완료

* feat(#22) : 입력 예외 처리 전 구현 완료

* feat(#22) : 에러 메세지 enum으로 분리

* feat(#22) : 에러 메세지 분리 및 컴포넌트 처ㅣㄹ

* feat(#22) : input값 가져오는 로직 구성

* feat(#22-1) : 로그인 로직 변경

* feat(#22) : 로그인 이동 페이지 생성

* style(#22) : 사진 수정

* feat(#22) : 로그인시 headerState 변경

* feat(#22) : 헤더에서 리스트 클릭시 경로 라우팅 설정 및 headerState 설정

* feat(#22) : 헤더 Spacer 설정

* feat(#22) : vercel 배포용 에러 제거

* fix(#22) : api 타입 수정
  • Loading branch information
j2noo authored Nov 11, 2023
1 parent 9192772 commit faf99b4
Show file tree
Hide file tree
Showing 20 changed files with 559 additions and 166 deletions.
File renamed without changes
Empty file.
Binary file added public/assets/images/join/join-bg.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/assets/images/login/login-bg.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
34 changes: 34 additions & 0 deletions public/assets/images/login/login-bg.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 16 additions & 0 deletions public/assets/images/login/login-button.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 3 additions & 2 deletions src/Router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,16 @@ import MultipleChoice from './pages/recommendation/MultipleChoice';
import Subjective from './pages/recommendation/Subjective';
import Contest from './pages/contest/Contest';
import CompetitionList from './pages/competitionList/CompetitionList';
import Login from './pages/login/Login';
import PaymentComplete from './pages/payment/PaymentComplete';

function Router() {
return (
<BrowserRouter>
<Header />
<Routes>
<Route path="/" element={<div>main</div>} />
<Route path="/login" element={<div>login</div>} />
{/* <Route path="/" element={<div>main</div>} /> */}
<Route path="/login" element={<Login />} />
<Route path="/login/oauth" element={<Oauth />} />
<Route path="/login/join" element={<Join />} />
<Route path="/recommendation" element={<Recommendation />}>
Expand Down
4 changes: 2 additions & 2 deletions src/apis/join/postJoin.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { IJoin } from '../../pages/join/Join';
import { RequestJoin } from '../../interface/Join';
import Axios from '../axios';

const postJoin = (kakaoAccessToken: string, joinData: IJoin) =>
const postJoin = (kakaoAccessToken: string, joinData: RequestJoin) =>
Axios.post(
'/api/auth/register',
{
Expand Down
104 changes: 65 additions & 39 deletions src/components/header/Header.tsx
Original file line number Diff line number Diff line change
@@ -1,69 +1,95 @@
import styled from 'styled-components';
import { useNavigate } from 'react-router-dom';
import { kakaoAuthorize } from '../login/KakaoLogin';
import { useRecoilValue } from 'recoil';
import { useRecoilState, useRecoilValue } from 'recoil';
import {
headerSelectedState,
kakaoNameState,
loginState,
} from '../../recoil/atom';

import logoSrc from '/assets/images/header/wanteam-logo.svg';
import starSrc from '/assets/images/header/header-star.svg';
import starSrc from '/assets/images/common/star.svg';
import { Headers } from '../../constants/Header';
import { useEffect } from 'react';

const Header = () => {
const kakaoName = useRecoilValue(kakaoNameState);
const isLogin = useRecoilValue(loginState);
const [isLogin, setIsLogin] = useRecoilState(loginState);
const headerSelectedIndex = useRecoilValue(headerSelectedState);
const navigate = useNavigate();
useEffect(() => {
if (localStorage.getItem('kawq;ejqwken')) setIsLogin(true);
// if (localStorage.getItem('kakaoAccessToken')) setIsLogin(true);
}, []);
return (
<HeaderLayout>
<Logo src={logoSrc} onClick={() => navigate('/')} />
<HeaderContainer>
<HeaderItem
$isSelected={headerSelectedIndex === Headers.list}
onClick={() => navigate('/list')}
>
<HeaderStar src={starSrc} />
공모전 리스트
</HeaderItem>
<HeaderItem $isSelected={headerSelectedIndex === Headers.myTeam}>
<HeaderStar src={starSrc} />내 팀
</HeaderItem>
{isLogin ? (
<>
<HeaderItem $isSelected={headerSelectedIndex === Headers.myPage}>
<>
<Spacer />
<HeaderLayout>
<HeaderContentContainer>
<Logo src={logoSrc} onClick={() => navigate('/')} />
<HeaderContainer>
<HeaderItem
$isSelected={headerSelectedIndex === Headers.list}
onClick={() => navigate('/list')}
>

<HeaderStar src={starSrc} />
{kakaoName}{' '}
공모전 리스트
</HeaderItem>
</>
) : (
<HeaderItem
$isSelected={headerSelectedIndex === Headers.login}
onClick={kakaoAuthorize}
>
<HeaderStar src={starSrc} />
로그인/회원가입
</HeaderItem>
)}
</HeaderContainer>
{/* {isLogin ? <KakaoLogout /> : <KakaoLogin />} */}
</HeaderLayout>
<HeaderItem $isSelected={headerSelectedIndex === Headers.myTeam}>
<HeaderStar src={starSrc} />내 팀
</HeaderItem>
{isLogin ? (
<>
<HeaderItem
$isSelected={headerSelectedIndex === Headers.myPage}
>
<HeaderStar src={starSrc} />
{kakaoName}{' '}
</HeaderItem>
</>
) : (
<HeaderItem
$isSelected={headerSelectedIndex === Headers.login}
onClick={() => navigate('/login')}
>
<HeaderStar src={starSrc} />
로그인/회원가입
</HeaderItem>
)}
</HeaderContainer>
</HeaderContentContainer>
</HeaderLayout>
</>
);
};
export default Header;

const Spacer = styled.div`
height: 8.2rem;
`;
const HeaderLayout = styled.header`
//width: 153.6rem;
max-width: 122.4rem;
height: 10rem;
margin: auto;
position: fixed;
top: 0;
left: 50%;
transform: translateX(-50%);
background-color: rgba(255, 255, 255, 0.8);
border-bottom: 1px solid ${(props) => props.theme.colors.gray10};
backdrop-filter: blur(8px);
width: 100%;
height: 8.2rem;
display: flex;
z-index: 999;
`;
const HeaderContentContainer = styled.div`
width: 122.4rem;
height: 100%;
/* height: 8.2rem; */
margin: auto;
display: flex;
justify-content: space-between;
align-items: center;
Expand Down
13 changes: 13 additions & 0 deletions src/components/join/ErrorMessage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import styled from 'styled-components';

const ErrorMessage = ({ errorText }: { errorText: string }) => {
return <ErrorText>{errorText}</ErrorText>;
};
const ErrorText = styled.div`
position: absolute;
bottom: -2rem;
left: 12.6rem;
color: ${(props) => props.theme.colors.error60};
${(props) => props.theme.fonts.bodyXXS};
`;
export default ErrorMessage;
51 changes: 51 additions & 0 deletions src/components/join/SelectInput.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import styled from 'styled-components';
import { REGIONS } from '../../constants/Join';

const SelectInput = ({ onChangeFunc }: { onChangeFunc: any }) => {
return (
<SelectContainer>
<Label>활동 지역</Label>
<Select onChange={onChangeFunc} name="region">
{REGIONS.map((each, idx) => (
<Option key={idx} value={each}>
{each}
</Option>
))}
</Select>
</SelectContainer>
);
};
const SelectContainer = styled.div`
width: 100%;
height: 6rem;
display: flex;
justify-content: center;
align-items: center;
border-radius: 0.5rem;
border: 1px solid ${(props) => props.theme.colors.gray20};
background-color: white;
padding: 1.4rem 2.4rem;
`;

const Label = styled.label`
width: 12rem;
color: ${(props) => props.theme.colors.gray80};
${(props) => props.theme.fonts.subtitleL};
`;
const Select = styled.select`
width: 100%;
/* flex: 1; */
color: ${(props) => props.theme.colors.gray80};
${(props) => props.theme.fonts.bodyL};
border: none;
`;
const Option = styled.option`
color: ${(props) => props.theme.colors.gray80};
${(props) => props.theme.fonts.bodyL};
`;
export default SelectInput;
76 changes: 76 additions & 0 deletions src/components/join/TextAreaInput.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import styled from 'styled-components';
import { InputProps } from '../../interface/Join';
import React, { useState } from 'react';
import ErrorMessage from './ErrorMessage';

const TextAreaInput = ({
inputProps,
onChangeFunc,
}: {
inputProps: InputProps;
onChangeFunc: any;
}) => {
const MIN_LENGTH = 10;
const MAX_LENGTH = 140;
const [text, setText] = useState('');
const handleChange = (event: React.ChangeEvent<HTMLTextAreaElement>) => {
setText(event.target.value);
onChangeFunc(event);
};
return (
<InputContainer>
<Label>{inputProps.label}</Label>
<Input
placeholder={inputProps.placeholder}
onChange={handleChange}
minLength={MIN_LENGTH}
maxLength={MAX_LENGTH}
name={inputProps.elemName}
></Input>
<LengthCount>
{text.length}/{MAX_LENGTH}
</LengthCount>
<ErrorMessage errorText={inputProps.errorText} />
</InputContainer>
);
};
const InputContainer = styled.div`
position: relative;
width: 100%;
display: flex;
justify-content: center;
/* align-items: center; */
border-radius: 0.5rem;
border: 1px solid ${(props) => props.theme.colors.gray20};
background-color: white;
padding: 1.4rem 2.4rem;
`;

const Label = styled.label`
width: 12rem;
color: ${(props) => props.theme.colors.gray80};
${(props) => props.theme.fonts.subtitleL};
`;
const Input = styled.textarea`
width: 100%;
min-height: 10rem;
color: ${(props) => props.theme.colors.gray80};
${(props) => props.theme.fonts.bodyL};
border: none;
resize: none;
`;
const LengthCount = styled.div`
position: absolute;
right: 2rem;
bottom: 2rem;
color: ${(props) => props.theme.colors.gray50};
${(props) => props.theme.fonts.buttonXXS};
`;
export default TextAreaInput;
56 changes: 56 additions & 0 deletions src/components/join/TextInput.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import styled from 'styled-components';
import { InputProps } from '../../interface/Join';
import ErrorMessage from './ErrorMessage';

const TextInput = ({
inputProps,
onChangeFunc,
}: {
inputProps: InputProps;
onChangeFunc: any;
}) => {
return (
<InputContainer>
<Label>{inputProps.label}</Label>
<Input
onChange={onChangeFunc}
type="text"
placeholder={inputProps.placeholder}
name={inputProps.elemName}
></Input>
<ErrorMessage errorText={inputProps.errorText} />
</InputContainer>
);
};
const InputContainer = styled.div`
position: relative;
width: 100%;
height: 6rem;
display: flex;
justify-content: center;
align-items: center;
border-radius: 0.5rem;
border: 1px solid ${(props) => props.theme.colors.gray20};
background-color: white;
padding: 1.4rem 2.4rem;
`;

const Label = styled.label`
width: 12rem;
color: ${(props) => props.theme.colors.gray80};
${(props) => props.theme.fonts.subtitleL};
`;
const Input = styled.input`
width: 100%;
/* flex: 1; */
color: ${(props) => props.theme.colors.gray80};
${(props) => props.theme.fonts.bodyL};
border: none;
`;
export default TextInput;
Loading

0 comments on commit faf99b4

Please sign in to comment.