Skip to content

Commit

Permalink
Merge pull request #13 from wanted-fork-fork/release/v0.1.1--proect-s…
Browse files Browse the repository at this point in the history
…etting

[Release] v0.1.1 - 프로젝트 세팅
  • Loading branch information
ooooorobo authored Nov 8, 2021
2 parents a64e87d + cfe059a commit 785139a
Show file tree
Hide file tree
Showing 15 changed files with 265 additions and 49 deletions.
6 changes: 6 additions & 0 deletions next.config.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
/** @type {import('next').NextConfig} */
module.exports = {
reactStrictMode: true,
env: {
BASE_URL:
process.env.BASE_URL ||
"https://ec2-13-124-94-121.ap-northeast-2.compute.amazonaws.com:8080",
IS_DEV: process.env.NODE_ENV === "development",
},
};
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"dev": "NODE_ENV=development next dev",
"build": "NODE_ENV=production next build",
"start": "next start",
"netlify-deploy": "next build && next export",
"lint": "next lint --ext .ts,.tsx"
"lint": "./node_modules/.bin/eslint src --ext .ts,.tsx"
},
"dependencies": {
"@netlify/plugin-nextjs": "3.9.2",
Expand Down
7 changes: 7 additions & 0 deletions src/constant/api.constant.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export const API_PREFIX = {
AUTH: "/auth",
};

export default {
API_PREFIX,
};
13 changes: 13 additions & 0 deletions src/lib/axios.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import axios from "axios";
import { Agent } from "https";

function createAxiosInstance() {
return axios.create({
httpsAgent: new Agent({
rejectUnauthorized: false,
}),
withCredentials: true,
});
}

export default { createAxiosInstance };
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ export interface APIResponse<T> {
}

export interface APIErrorResponse {
statusCode: number;
status: number;
message: string;
error?: string;
}
4 changes: 4 additions & 0 deletions src/models/dto/user.dto.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export interface LoginDto {
email: string;
pwd: string;
}
13 changes: 13 additions & 0 deletions src/models/mapper/user.mapper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { LoginDto } from "@src/models/dto/user.dto";

function buildLoginDto({
email,
password,
}: {
email: string;
password: string;
}): LoginDto {
return { email, pwd: password };
}

export default { buildLoginDto };
32 changes: 29 additions & 3 deletions src/pages/_app.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,32 @@
import Head from "next/head";
import type { AppProps } from "next/app";
import { ThemeProvider } from "styled-components";
import styled, { ThemeProvider, css } from "styled-components";

// styles
import GlobalStyle from "@src/styles/globals";
import theme from "@src/styles/theme";
import theme, { windowSize } from "@src/styles/theme";

const Container = styled.div`
${({ theme: defaultTheme }) => css`
background-color: ${defaultTheme.color.gray0};
`}
`;

const Content = styled.div`
background-color: #fff;
height: 100vh;
margin: 0 auto;
width: ${windowSize.mobile};
${({ theme: defaultTheme }) => {
const { window } = defaultTheme;
return css`
${window.mobile} {
width: 100vw;
}
`;
}}
`;

function MyApp({ Component, pageProps }: AppProps) {
return (
Expand All @@ -18,7 +40,11 @@ function MyApp({ Component, pageProps }: AppProps) {
</Head>
<ThemeProvider theme={theme}>
<GlobalStyle />
<Component {...pageProps} />
<Container>
<Content>
<Component {...pageProps} />
</Content>
</Container>
</ThemeProvider>
</>
);
Expand Down
45 changes: 34 additions & 11 deletions src/pages/index.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,47 @@
import type { NextPage } from "next";
import { FormEvent, useCallback } from "react";
import styled from "styled-components";
import { observer } from "mobx-react";

// store
// stores
import { useStores } from "@src/store/root.store";

const Container = styled.div`
//background-color: black;
`;
// templates
import LoginPageTemplate from "@src/templates/LoginPage.template";

const Container = styled.div``;

const Home: NextPage = observer(() => {
const { countStore } = useStores();
const { userStore } = useStores();

const onSubmit = useCallback(
async (e: FormEvent<HTMLFormElement>) => {
e.preventDefault();
// @ts-ignore
const email = e.target.email.value;
// @ts-ignore
const password = e.target.password.value;
await userStore.login({ email, password });
},
[userStore],
);

const onTest = useCallback(async () => {
await userStore.test();
}, [userStore]);

const onRefresh = useCallback(async () => {
await userStore.refresh();
}, [userStore]);

return (
<Container>
<p>{countStore.number}</p>
<button onClick={countStore.increase} type="button">
+
</button>
<button onClick={countStore.decrease} type="button">
-
<LoginPageTemplate onSubmit={onSubmit} />
<button type="button" onClick={onTest}>
test auth
</button>{" "}
<button type="button" onClick={onRefresh}>
test refresh
</button>
</Container>
);
Expand Down
20 changes: 17 additions & 3 deletions src/services/Auth.service.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,26 @@
import BaseHttpService from "@src/services/BaseHttp.service";
import Router from "next/router";
import { LoginDto } from "@src/models/dto/user.dto";
import { API_PREFIX } from "@src/constant/api.constant";

export default class AuthService extends BaseHttpService {
async login(): Promise<boolean> {
return Router.push(`${this.BASE_URL}/`);
prefix = API_PREFIX.AUTH;

async login(loginDto: LoginDto): Promise<string> {
return (await this.post<string>(
`${this.prefix}/login`,
loginDto,
)) as string;
}

logout() {
this.removeToken();
}

async test(): Promise<string> {
return (await this.get<string>(`/test`)) as string;
}

async refresh(): Promise<string> {
return (await this.post<string>(`${this.prefix}/refresh`)) as string;
}
}
54 changes: 36 additions & 18 deletions src/services/BaseHttp.service.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,32 @@
import axios, { AxiosError, AxiosRequestConfig, AxiosResponse } from "axios";
import { APIErrorResponse, APIResponse } from "@src/dto/api/api-response";
import {
AxiosError,
AxiosInstance,
AxiosRequestConfig,
AxiosRequestHeaders,
AxiosResponse,
} from "axios";
import { APIErrorResponse, APIResponse } from "@src/models/dto/api-response";
import Router from "next/router";
import { API_PREFIX } from "@src/constant/api.constant";

// MobX store와 함께 사용되므로 class로 생성
export default class BaseHttpService {
BASE_URL: string = process.env.BASE_URL || "http://localhost:8000";
axiosInstance: AxiosInstance;

BASE_URL: string = process.env.BASE_URL;

_accessToken: string = null;

constructor(axiosInstance: AxiosInstance) {
this.axiosInstance = axiosInstance;
}

async get<T = any>(
path: string,
options: AxiosRequestConfig = {},
): Promise<T | void> {
Object.assign(options, this._getCommonOptions());
return axios
return this.axiosInstance
.get<APIResponse<T>>(`${this.BASE_URL}${path}`, options)
.then((res: AxiosResponse<APIResponse<T>>) => res.data.data)
.catch((error: AxiosError<APIErrorResponse>) =>
Expand All @@ -26,7 +40,7 @@ export default class BaseHttpService {
options: AxiosRequestConfig = {},
): Promise<T | void> {
Object.assign(options, this._getCommonOptions());
return axios
return this.axiosInstance
.post<APIResponse<T>>(`${this.BASE_URL}${path}`, data, options)
.then((res: AxiosResponse<APIResponse<T>>) => res.data.data)
.catch((error: AxiosError<APIErrorResponse>) =>
Expand All @@ -39,7 +53,7 @@ export default class BaseHttpService {
options: AxiosRequestConfig = {},
): Promise<T | void> {
Object.assign(options, this._getCommonOptions());
return axios
return this.axiosInstance
.delete<APIResponse<T>>(`${this.BASE_URL}${path}`, options)
.then((res: AxiosResponse<APIResponse<T>>) => res.data.data)
.catch((error: AxiosError<APIErrorResponse>) =>
Expand All @@ -53,7 +67,7 @@ export default class BaseHttpService {
options: AxiosRequestConfig = {},
): Promise<T | void> {
Object.assign(options, this._getCommonOptions());
return axios
return this.axiosInstance
.patch<APIResponse<T>>(`${this.BASE_URL}${path}`, data, options)
.then((res: AxiosResponse<APIResponse<T>>) => res.data.data)
.catch((error: AxiosError<APIErrorResponse>) =>
Expand All @@ -63,10 +77,8 @@ export default class BaseHttpService {

_handleHttpError(error: AxiosError<APIErrorResponse>) {
if (error?.response?.data) {
const { statusCode } = error?.response?.data;
// const requestUrl = error.response?.config.url;

if (statusCode !== 401) {
const { status } = error?.response?.data;
if (status !== 401) {
throw error.response.data;
} else {
return this._handle401(error);
Expand All @@ -76,16 +88,22 @@ export default class BaseHttpService {
}
}

// eslint-disable-next-line class-methods-use-this
_handle401(error: AxiosError<APIErrorResponse>) {
// TODO:: refresh the token
console.log(error.message);
// this.get("/api/auth/refresh")
// .then(() => axios.request(error.config))
// .catch(() => Router.push("/login"));
// refresh token
this.post<string>(`${API_PREFIX.AUTH}/refresh`)
.then((res: string) => {
this._saveToken(res);

// request again
const { config } = error;
config.headers = this._getCommonOptions()
.headers as AxiosRequestHeaders;
return this.axiosInstance.request(config);
})
.catch(() => Router.push("/login"));
}

_getCommonOptions() {
_getCommonOptions(): AxiosRequestConfig {
const token = this.loadToken();
if (token) {
return {
Expand Down
14 changes: 14 additions & 0 deletions src/store/root.store.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,26 @@
import { createContext, useContext } from "react";

import CountStore from "@src/store/count.store";
import UserStore from "@src/store/user.store";
import AuthService from "@src/services/Auth.service";

import Axios from "@src/lib/axios";
import { AxiosInstance } from "axios";

export class RootStore {
axiosInstance: AxiosInstance;

countStore: CountStore;

userStore: UserStore;

constructor() {
this.axiosInstance = Axios.createAxiosInstance();

const authService = new AuthService(this.axiosInstance);

this.countStore = new CountStore(this);
this.userStore = new UserStore(this, authService);
}
}

Expand Down
37 changes: 37 additions & 0 deletions src/store/user.store.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { makeAutoObservable } from "mobx";

// store
import { RootStore } from "@src/store/root.store";
import AuthService from "@src/services/Auth.service";

// model
import { LoginDto } from "@src/models/dto/user.dto";
import UserMapper from "@src/models/mapper/user.mapper";

export default class UserStore {
private readonly rootStore: RootStore;

private readonly authService: AuthService;

constructor(rootStore: RootStore, authService: AuthService) {
this.authService = authService;
this.rootStore = rootStore;

makeAutoObservable(this);
}

async login({ email, password }) {
const loginDto: LoginDto = UserMapper.buildLoginDto({ email, password });
const token = await this.authService.login(loginDto);
this.authService._saveToken(token);
}

async test() {
await this.authService.test();
}

async refresh() {
const token = await this.authService.refresh();
this.authService._saveToken(token);
}
}
Loading

0 comments on commit 785139a

Please sign in to comment.