This repository has been archived by the owner on Nov 1, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(logic): create basic logic for fetch and main UI
hack: 독립적으로 E2E 테스트를 작성하는 방법을 아직 못 찾음.. TODO: 테스트 전/후로백엔드의 DB를 비우자
- Loading branch information
Showing
10 changed files
with
273 additions
and
39 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
export type TypeLoginRes = { mailid: string } | ||
|
||
export interface TypeUserNoPw { | ||
student_no: number | ||
student_pw: string | ||
} | ||
|
||
export type TypeSemester = { | ||
averagePoint: number // Float | ||
totalCredit: number | ||
isOutside: boolean | ||
semester: 'FIRST' | 'SUMMER' | 'SECOND' | 'WINTER' | ||
year: number | ||
} | ||
|
||
export type TypeUser = { | ||
name: string | ||
mailid: string | ||
averagePoint: number // Float | ||
semesters: TypeSemester[] | ||
} | ||
|
||
export enum enumSemester { | ||
'1학기' = 'FIRST', | ||
'하기계절' = 'SUMMER', | ||
'2학기' = 'SECOND', | ||
'동기계절' = 'WINTER', | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import { TypeUser } from './models' | ||
|
||
export type TypeRes = { | ||
status: number | ||
} | ||
|
||
export interface TypeLoad extends TypeRes { | ||
data: TypeUser | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,38 +1,40 @@ | ||
import React, { FormEvent, useState, Fragment } from 'react' | ||
import React from 'react' | ||
|
||
import logo from './logo.svg' | ||
import './App.css' | ||
|
||
import { Input } from './view/Input' | ||
import { submitID } from './control' | ||
import Login from './routes/Login' | ||
import Main from './routes/Main' | ||
import Fetch from './routes/Fetch' | ||
import { | ||
BrowserRouter as Router, | ||
Switch, | ||
Route, | ||
Redirect, | ||
} from 'react-router-dom' | ||
|
||
const App: React.FC = () => { | ||
const [flag, setFlag] = useState<boolean>() | ||
const onSubmit = async (e: FormEvent) => { | ||
e.preventDefault() | ||
// @ts-ignore | ||
const { value }: { value: string } = e.target[0] | ||
setFlag(await submitID(value)) | ||
} | ||
return ( | ||
<div className="App"> | ||
<header className="App-header"> | ||
<img src={logo} className="App-logo" alt="logo" /> | ||
{typeof flag === 'undefined' ? ( | ||
<Fragment> | ||
<p>제주대학교 메일 ID를 입력해주세요!</p> | ||
<form onSubmit={onSubmit}> | ||
<Input name="mailid" /> | ||
</form> | ||
</Fragment> | ||
) : flag ? ( | ||
<p id="result">mail was send</p> | ||
) : ( | ||
<p id="result">not found username from mail server</p> | ||
)} | ||
</header> | ||
</div> | ||
) | ||
} | ||
const App: React.FC = () => ( | ||
<div className="App"> | ||
<header className="App-header"> | ||
<img src={logo} className="App-logo" alt="logo" /> | ||
<Router> | ||
<Switch> | ||
<Route exact path="/"> | ||
<Redirect to="login" /> | ||
</Route> | ||
<Route path="/login"> | ||
<Login /> | ||
</Route> | ||
<Route path="/main"> | ||
<Main /> | ||
</Route> | ||
<Route path="/fetch"> | ||
<Fetch /> | ||
</Route> | ||
</Switch> | ||
</Router> | ||
</header> | ||
</div> | ||
) | ||
|
||
export default App |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,36 @@ | ||
import axios, { AxiosResponse } from 'axios' | ||
import { TypeUser, TypeUserNoPw } from './@types/models' | ||
import { getToken } from './utils' | ||
|
||
const baseURL = 'http://localhost:4000/' | ||
|
||
const request = axios.create({ | ||
baseURL, | ||
}) | ||
|
||
export const sendID = (id: string): Promise<AxiosResponse<string>> => | ||
request.post('login', id, { | ||
headers: { 'Content-Type': 'text/plain' }, | ||
export const sendID = ( | ||
mailid: string | ||
): Promise<AxiosResponse<string | undefined>> => | ||
request.post( | ||
'login', | ||
{ mailid }, | ||
{ | ||
headers: { 'Content-Type': 'application/json' }, | ||
} | ||
) | ||
|
||
export const fetchData = ( | ||
data: TypeUserNoPw | ||
): Promise<AxiosResponse<TypeUser>> => | ||
request.post('fetch', data, { | ||
headers: { | ||
Authorization: `Bearer ${getToken()}`, | ||
}, | ||
}) | ||
|
||
export const loadData = (): Promise<AxiosResponse<TypeUser>> => | ||
request.get('load', { | ||
headers: { | ||
Authorization: `Bearer ${getToken()}`, | ||
}, | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,32 @@ | ||
import { sendID } from './api' | ||
import { sendID, loadData } from './api' | ||
import { TypeLoad } from './@types/state' | ||
import { fetchData } from './api' | ||
import { TypeUserNoPw } from './@types/models' | ||
|
||
export const submitID = async (id: string) => { | ||
export const submitID = async (mailid: string) => { | ||
try { | ||
return (await sendID(id)).status === 201 | ||
return (await sendID(mailid)).status === 201 | ||
} catch (e) { | ||
return false | ||
if (e.message.includes('401')) return false | ||
throw e | ||
} | ||
} | ||
|
||
export const resData = async (): Promise<TypeLoad> => { | ||
const { status, data } = await loadData() | ||
return { | ||
status, | ||
data, | ||
} | ||
} | ||
|
||
export const fetchAndSet = async (data: TypeUserNoPw): Promise<number> => { | ||
const { status } = await fetchData(data) | ||
return status | ||
} | ||
|
||
type OptionalNumber = number | undefined | ||
|
||
// FF: High Order Function | ||
export const isCodeFF = (status: OptionalNumber) => (code: OptionalNumber) => | ||
status === code |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
import React, { useState, FormEvent, useEffect, Fragment } from 'react' | ||
|
||
import { fetchAndSet, isCodeFF } from '../control' | ||
import { Input } from '../view/Input' | ||
import { saveToken } from '../utils' | ||
import { Redirect } from 'react-router-dom' | ||
|
||
interface FormElements extends HTMLFormElement { | ||
student_no: HTMLInputElement | ||
student_pw: HTMLInputElement | ||
} | ||
|
||
interface FormTarget extends FormEvent<HTMLFormElement> { | ||
target: FormElements | ||
} | ||
|
||
const App = () => { | ||
useEffect(saveToken, []) | ||
|
||
const [status, setStatus] = useState<number>() | ||
const isCode = isCodeFF(status) | ||
|
||
const onSubmit = async (event: FormTarget) => { | ||
event.preventDefault() | ||
setStatus( | ||
await fetchAndSet({ | ||
student_no: parseInt(event.target.student_no.value), | ||
student_pw: event.target.student_pw.value, | ||
}) | ||
) | ||
} | ||
|
||
const Form = () => ( | ||
<div id="form"> | ||
<p>학번 및 비밀번호를 입력해주세요!</p> | ||
<form onSubmit={onSubmit}> | ||
<Input name="student_no" type="username" /> | ||
<Input name="student_pw" type="password" /> | ||
<button type="submit">Submit</button> | ||
</form> | ||
</div> | ||
) | ||
|
||
if (isCode(undefined)) return <Form /> | ||
return ( | ||
<Fragment> | ||
~~ | ||
{isCode(201) && <Redirect to="/main" />} | ||
{isCode(401) && ( | ||
<div id="invalid"> | ||
<p>입력한 정보가 유효하지 않습니다</p> | ||
<Form /> | ||
</div> | ||
)} | ||
{isCode(500) && <p id="error">500 오류</p>} | ||
</Fragment> | ||
) | ||
} | ||
|
||
export default App |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import React, { FormEvent, useState, Fragment } from 'react' | ||
|
||
import { Input } from '../view/Input' | ||
import { submitID } from '../control' | ||
|
||
const App: React.FC = () => { | ||
const [flag, setFlag] = useState<boolean>() | ||
const onSubmit = async (event: FormEvent) => { | ||
event.preventDefault() | ||
// @ts-ignore | ||
const { value }: { value: string } = event.target[0] | ||
setFlag(await submitID(value)) | ||
} | ||
return ( | ||
<Fragment> | ||
{typeof flag === 'undefined' ? ( | ||
<Fragment> | ||
<p>제주대학교 메일 ID를 입력해주세요!</p> | ||
<form onSubmit={onSubmit}> | ||
<Input name="mailid" /> | ||
</form> | ||
</Fragment> | ||
) : flag ? ( | ||
<p id="result">mail was send</p> | ||
) : ( | ||
<p id="result">not found username from mail server</p> | ||
)} | ||
</Fragment> | ||
) | ||
} | ||
|
||
export default App |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import React, { useState, Fragment } from 'react' | ||
import useAsyncEffect from 'use-async-effect' | ||
|
||
import { resData, isCodeFF } from '../control' | ||
import { Redirect, Link } from 'react-router-dom' | ||
import { TypeUser } from '../@types/models' | ||
|
||
const App = () => { | ||
const [status, setStatus] = useState<number>() | ||
const [userData, setUserData] = useState<TypeUser>() | ||
|
||
useAsyncEffect(async () => { | ||
const { status: resStatus, data } = await resData() | ||
setStatus(resStatus) | ||
setUserData(data) | ||
}, []) | ||
|
||
const isCode = isCodeFF(status) | ||
|
||
const Go2Login = () => ( | ||
<div id="error"> | ||
{isCode(401) && <p>서버에서 사용자 정보를 찾을 수 없어요 :/</p>} | ||
{isCode(500) && <p>500 오류 :/</p>} | ||
<Link to="/login">다시 로그인하러 가기</Link> | ||
</div> | ||
) | ||
|
||
if (isCode(undefined)) return <p id="loading">불러오는 중..</p> | ||
return ( | ||
<Fragment> | ||
{isCode(200) && ( | ||
<p> | ||
<span id="result">캐싱 된 데이터:</span> {console.log(userData)} | ||
</p> | ||
)} | ||
{isCode(204) && <Redirect to="/fetch" />} | ||
{(isCode(401) || isCode(500)) && <Go2Login />} | ||
</Fragment> | ||
) | ||
} | ||
|
||
export default App |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import qs from 'querystring' | ||
|
||
export const saveToken = () => { | ||
localStorage.setItem('token', qs.parse(window.location.search)[ | ||
'?token' | ||
] as string) | ||
} | ||
|
||
export const getToken = () => localStorage.getItem('token') |