Skip to content

Commit

Permalink
Merge pull request #199 from boostcampwm-2024/feature/fe/#197-doLogin
Browse files Browse the repository at this point in the history
[FE][Feat] 로그인 api 연동
  • Loading branch information
happyhyep authored Nov 19, 2024
2 parents e961153 + 189e7ff commit 3d77902
Show file tree
Hide file tree
Showing 11 changed files with 218 additions and 37 deletions.
69 changes: 35 additions & 34 deletions backend/package.json
Original file line number Diff line number Diff line change
@@ -1,34 +1,35 @@
{
"name": "ddara-backend",
"private": true,
"workspaces": [
"frontend",
"backend"
],
"version": "0.0.0",
"type": "module",
"description": "따라따라의 선따라길따라 BackEnd 코드",
"main": "index.js",
"scripts": {
"dev": "node src/index.js",
"test": "vitest",
"test:watch": "vitest --watch",
"test:coverage": "vitest run --coverage",
"lint": "pnpm lint-staged"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"bcrypt": "^5.1.1",
"dotenv": "^16.4.5",
"express": "^4.21.1",
"express-validator": "^7.2.0",
"jsonwebtoken": "^9.0.2",
"pg": "^8.13.1",
"swagger-jsdoc": "^6.2.8",
"swagger-ui-express": "^5.0.1",
"uuid": "^11.0.3",
"ws": "^8.11.0"
}
}
{
"name": "ddara-backend",
"private": true,
"workspaces": [
"frontend",
"backend"
],
"version": "0.0.0",
"type": "module",
"description": "따라따라의 선따라길따라 BackEnd 코드",
"main": "index.js",
"scripts": {
"dev": "node src/index.js",
"test": "vitest",
"test:watch": "vitest --watch",
"test:coverage": "vitest run --coverage",
"lint": "pnpm lint-staged"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"bcrypt": "^5.1.1",
"cors": "^2.8.5",
"dotenv": "^16.4.5",
"express": "^4.21.1",
"express-validator": "^7.2.0",
"jsonwebtoken": "^9.0.2",
"pg": "^8.13.1",
"swagger-jsdoc": "^6.2.8",
"swagger-ui-express": "^5.0.1",
"uuid": "^11.0.3",
"ws": "^8.11.0"
}
}
10 changes: 10 additions & 0 deletions backend/src/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import express from 'express';
import swaggerUi from 'swagger-ui-express';
import http from 'http';
import cors from 'cors';
import { specs } from '../swaggerConfig.js';
import { PORT } from './constants/constants.js';
import { initializeWebSocketServer } from './websocketServer.js';
Expand All @@ -10,6 +11,15 @@ import { channelRouter } from './routes/channelRouter.js';
const app = express();
app.use(express.json());

// TODO: 프론트 배포 후 origin url 변경
app.use(
cors({
origin: ['http://localhost:5173', 'http://223.130.151.43'],
methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
credentials: true,
}),
);

app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(specs));

app.use('/api/auth', authRouter);
Expand Down
27 changes: 27 additions & 0 deletions frontend/src/api/auth.api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { getApiClient } from '@/api/client.api.ts';
import { ResponseDto } from '@/api/dto/response.dto.ts';
import { LoginResEntity } from '@/api/dto/auth.dto.ts';

export const doLogin = (id: string, password: string): Promise<ResponseDto<LoginResEntity>> => {
const promiseFn = (
fnResolve: (value: ResponseDto<LoginResEntity>) => void,
fnReject: (reason?: any) => void,
) => {
const apiClient = getApiClient();
apiClient
.post('/auth/login', { id, password })
.then(res => {
if (!res.data.success) {
console.error(res);
fnReject(`msg.${res.data.resultMsg}`);
} else {
fnResolve(new ResponseDto<LoginResEntity>(res.data));
}
})
.catch(err => {
console.error(err);
fnReject('msg.RESULT_FAILED');
});
};
return new Promise(promiseFn);
};
31 changes: 31 additions & 0 deletions frontend/src/api/client.api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { AppConfig } from '@/constants';
import { loadLocalData } from '@/utils/common/manageLocalData.ts';
import axios from 'axios';

let apiClient = axios.create({
baseURL: AppConfig.API_SERVER,
headers: {
'Content-type': 'application/json',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Credentials': true,
},
});

export function setApiToken(token: string): void {
if (apiClient) apiClient.defaults.headers.common.Authorization = `Bearer ${token}`;
}

export const getApiClient = () => {
const token = loadLocalData(AppConfig.KEYS.LOGIN_TOKEN);
if (token) setApiToken(token);
if (!apiClient) {
apiClient = axios.create({
baseURL: AppConfig.API_SERVER,
headers: {
'Content-type': 'application/json',
'Access-Control-Allow-Origin': '*',
},
});
}
return apiClient;
};
5 changes: 5 additions & 0 deletions frontend/src/api/dto/auth.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export class LoginResEntity {
token: string | undefined;

userId: string | undefined;
}
16 changes: 16 additions & 0 deletions frontend/src/api/dto/response.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
export class ResponseDto<T> {
resultCode = 0;

resultMsg = '';

data?: T;

totalCount = 0;

constructor(data?: any) {
if (data.resultCode) this.resultCode = data.resultCode;
if (data.resultMsg) this.resultMsg = data.resultMsg;
if (data.data) this.data = data.data;
if (data.totalCount) this.totalCount = data.totalCount;
}
}
13 changes: 11 additions & 2 deletions frontend/src/component/authmodal/AuthModal.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import React, { useState } from 'react';
import { Modal } from '@/component/common/modal/Modal';
import { doLogin } from '@/api/auth.api.ts';
import { saveLocalData } from '@/utils/common/manageLocalData.ts';
import { AppConfig } from '@/constants.ts';

interface IAuthModalProps {
/** 모달이 열려 있는지 여부를 나타냅니다. */
Expand Down Expand Up @@ -43,7 +46,13 @@ export const AuthModal = (props: IAuthModalProps) => {
};

const handleLoginClick = () => {
console.log('로그인 데이터:', loginData);
doLogin(loginData.id, loginData.pw).then(el => {
if (el.data?.token && el.data?.userId) {
saveLocalData(AppConfig.KEYS.LOGIN_TOKEN, el.data.token);
saveLocalData(AppConfig.KEYS.LOGIN_USER, el.data.userId);
}
window.location.reload();
});
};

const handleSignUpClick = () => {
Expand All @@ -63,7 +72,7 @@ export const AuthModal = (props: IAuthModalProps) => {
};

return (
<Modal isOpen={props.isOpen} onClose={props.onClose}>
<Modal isOpen={props.isOpen}>
{modalType === 'login' ? (
<>
<Modal.Header content="Log In" onClose={props.onClose} />
Expand Down
17 changes: 17 additions & 0 deletions frontend/src/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
export const KEYS = {
LOGIN_USER: 'LUT',
LOGIN_TOKEN: 'LUT_TK',
};

export const AppConfig = {
/**
* API SERVER
*/
API_SERVER: 'http://223.130.151.43:3001/api',
// API_SERVER: 'http://localhost:3001/api',

/**
* ETC
*/
KEYS,
};
2 changes: 1 addition & 1 deletion frontend/src/pages/Main.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { Fragment } from 'react';
import { Fragment } from 'react';
import { getUserLocation } from '@/hooks/getUserLocation';
import { Map } from '@/component/maps/Map';
import { BottomSheet } from '@/component/bottomSheet/BottomSheet';
Expand Down
53 changes: 53 additions & 0 deletions frontend/src/utils/common/manageLocalData.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/* eslint-disable */
import lzString from 'lz-string'

export function saveLocalData(key: string, val: string): void {
if (typeof window !== 'undefined') {
const storage = window.localStorage;

if (storage) {
try {
storage.setItem(key, lzString.compressToUTF16(val));
} catch (e) {
console.error('Storage Full ... clean old data...');
for (const k in storage) {
if (k.indexOf('DATA_MESSAGE_DETAIL_') > -1) {
storage.removeItem(k);
}
}
storage.setItem(key, lzString.compressToUTF16(val));
}
}
}
}

export function loadLocalData(key: string): string | null {
if (typeof window !== undefined) {
const storage = window.localStorage;

if (storage) {
const keyValue = storage.getItem(key);
if (keyValue) return lzString.decompressFromUTF16(keyValue);
}
}
return null;
}

export function clearLocalData() {
if (typeof window !== undefined) {
const storage = window.localStorage;

if (storage) {
storage.clear();
}
}
}

export function removeLocalData(key: string): void {
if (typeof window !== undefined) {
const storage = window.localStorage;
if (storage) {
storage.removeItem(key);
}
}
}
12 changes: 12 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 3d77902

Please sign in to comment.