Skip to content

Commit

Permalink
Merge pull request #226 from boostcamp-2020/develop
Browse files Browse the repository at this point in the history
nginx μ„€μ •ν•œ 배포
  • Loading branch information
rolled-potatoes authored Dec 14, 2020
2 parents 1176651 + 6cb6977 commit 6494f5d
Show file tree
Hide file tree
Showing 28 changed files with 250 additions and 157 deletions.
141 changes: 125 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,24 +1,135 @@
## N석봉
## N석봉 - 가계뢀 μ„œλΉ„μŠ€
<p align='center'>
<img width='50%' src='https://i.imgur.com/c283ZvJ.png'>
</p>

> Project16-A-Account-Book
<p align='center'>
<img src="https://img.shields.io/badge/React-v17.0.1-blue?logo=React"/>
<img src="https://img.shields.io/badge/node.js-v14.15.1-green?logo=Node.js"/>
<img src="https://img.shields.io/badge/storybook-v6.0.28-ff69b4?logo=storybook"/>
<img src="https://img.shields.io/badge/koa-v2.13.0-aaa?logo=Kaggle"/>
<img src="https://img.shields.io/badge/mongodb-v4.0.10-critical?logo=mongodb"/>
<img src="https://img.shields.io/badge/mongoose-v5.10.15-critical?logo=mongodb"/>
<img src="https://img.shields.io/badge/Typescript-v4.0.5-blue?logo=typescript"/>
<img src="https://img.shields.io/badge/jest-v26.6.3-orange?logo=jest"/>
<img src="https://img.shields.io/badge/MobX-v6.0.4-orange?logo=Monster">
<img src="https://img.shields.io/badge/prettier-^2.2.0-yellow?logo=prettier" />
<img src="https://img.shields.io/badge/eslint-^7.11.0-yellow?logo=eslint">
<img src="https://img.shields.io/badge/yarn-^1.22.5-yellow?logo=yarn">
</p>

<div>
<img src="https://img.shields.io/badge/React-v17.0.1-blue)"/>
<img src="https://img.shields.io/badge/node-v14.15.1-green"/>
<img src="https://img.shields.io/badge/storybook-v6.0.28-ff69b4"/>
<img src="https://img.shields.io/badge/koa-v2.13.0-aaa"/>
<img src="https://img.shields.io/badge/mongoose-v5.10.15-critical"/>
</div>
## 🏠 [HOME PAGE](http://xn--n-b22fl8h.kro.kr)

## πŸ’Έ [HOME PAGE](http://xn--n-b22fl8h.kro.kr/login)
λˆμ€ λ„ˆκ°€ 쓰거라 πŸ€‘, κ΄€λ¦¬λŠ” λ‚΄κ°€ ν• ν…Œλ‹ˆ 😎

λˆμ€ λ„ˆκ°€ 쓰거라, κ΄€λ¦¬λŠ” λ‚΄κ°€ ν• ν…Œλ‹ˆ
## πŸ“Œ 가계뢀 μ„œλΉ„μŠ€ μ†Œκ°œ
### πŸ‘©β€πŸ‘©β€πŸ‘§β€πŸ‘¦ 개인 λ˜λŠ” 곡용으둜 관리할 수 μžˆλŠ” μžμ‚°κ΄€λ¦¬ 가계뢀 μ„œλΉ„μŠ€
> - 혼자만의 가계뢀λ₯Ό 관리할 수 μžˆμŠ΅λ‹ˆλ‹€.
> - 친ꡬλ₯Ό μ΄ˆλŒ€ν•˜μ—¬ ν•¨κ»˜ 가계뢀λ₯Ό 관리할 수 μžˆμŠ΅λ‹ˆλ‹€.
### πŸ“ˆ μ§€μΆœκ³Ό μˆ˜μž…μ— λŒ€ν•œ 톡계 제곡
> - κ·Έλ™μ•ˆμ˜ μ§€μΆœλ‚΄μ—­κ³Ό μˆ˜μž…μ„ **뢄석**ν•˜μ—¬ μž…μΆœκΈˆ ν˜„ν™©μ„ νŒŒμ•…ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
### βœ”οΈ λ‚΄κ°€ 보고 싢은 κ²ƒλ“€λ§Œ 필터링
> - μ›ν•˜λŠ” λ‚΄μ—­λ§Œ **필터링**ν•΄μ„œ λ³Ό 수 μžˆλŠ” κΈ°λŠ₯을 μ œκ³΅ν•©λ‹ˆλ‹€.
### πŸ“† 달λ ₯을 ν†΅ν•œ κ±°λž˜λ‚΄μ—­ 확인
> - 달 λ³„λ‘œ 돈의 μ‚¬μš© 내역을 확인할 수 μžˆμŠ΅λ‹ˆλ‹€!
### πŸ“© MMSλ₯Ό μž…λ ₯ν•˜μ—¬ λ°”λ‘œ κ±°λž˜λ‚΄μ—­μ— μΆ”κ°€
> - 문자둜 온 κ±°λž˜λ‚΄μ—­μ„ 치기만 ν•˜λ©΄, λ°”λ‘œ κ±°λž˜λ‚΄μ—­μ— μΆ”κ°€ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
## πŸ“Œ μ†Œκ°œ
<!-- ## πŸ“Œ 기획 λ°°κ²½
- 슀마트폰 기기에 맞좘 μ›Ή μ„œλΉ„μŠ€
-
λ°”μœ 일상을 μ‚΄μ•„κ°€λŠ” ν˜„λŒ€μ‚¬νšŒμΈλ“€μ€ μžκΈˆμ„ 관리해쀄 μ„œλΉ„μŠ€κ°€ ν•„μš”ν•˜μ§€λ§Œ μ‹œκ°„μ„ νˆ¬μžν•˜κΈ°λŠ” 쉽지 μ•ŠμŠ΅λ‹ˆλ‹€. 가계뢀 μ„œλΉ„μŠ€μΈ N석봉은 μ΄λΆ€λΆ„μ—μ„œ ν”„λ‘œμ νŠΈ μ˜λ„λ₯Ό κΈ°νšν–ˆμŠ΅λ‹ˆλ‹€. μ–΄μ©Œκ΅¬ μ €μ©Œκ΅¬
-->
## πŸ“Œ [기술 및 λ…Όμ˜ 정리 - WIKI](https://github.com/boostcamp-2020/Project16-A-Account-Book/wiki)

πŸ’° 개인 λ˜λŠ” 곡용으둜 이용 ν•  수 μžˆλŠ” μžμ‚°κ΄€λ¦¬ μ„œλΉ„μŠ€ μž…λ‹ˆλ‹€.
## πŸ“Œ μ£Όμš” κΈ°λŠ₯

πŸ“ˆ μž…λ ₯된 데이터λ₯Ό μ‹œμž‘ν™”ν•˜μ—¬ 뢄석 및 νŒŒμ•… ν•  수 μžˆλŠ” κΈ°λŠ₯을 μ œκ³΅ν•©λ‹ˆλ‹€.
|[πŸ”— 둜그인](https://github.com/boostcamp-2020/Project16-A-Account-Book/wiki/%EC%A3%BC%EC%9A%94-%EA%B8%B0%EB%8A%A5-%EC%86%8C%EA%B0%9C#-%EB%A1%9C%EA%B7%B8%EC%9D%B8-%ED%8E%98%EC%9D%B4%EC%A7%80%EA%B8%B0%EB%8A%A5-%EC%86%8C%EA%B0%9C)|[πŸ”— κ°€κ³„λΆ€λ¦¬μŠ€νŠΈ](https://github.com/boostcamp-2020/Project16-A-Account-Book/wiki/%EC%A3%BC%EC%9A%94-%EA%B8%B0%EB%8A%A5-%EC%86%8C%EA%B0%9C#-%EA%B3%B5%EC%9C%A0-%EA%B0%80%EA%B3%84%EB%B6%80-%ED%8E%98%EC%9D%B4%EC%A7%80)|[πŸ”— λ©”μΈνŽ˜μ΄μ§€](https://github.com/boostcamp-2020/Project16-A-Account-Book/wiki/%EC%A3%BC%EC%9A%94-%EA%B8%B0%EB%8A%A5-%EC%86%8C%EA%B0%9C#-%EB%A9%94%EC%9D%B8-%ED%8E%98%EC%9D%B4%EC%A7%80-%EC%86%8C%EA%B0%9C)|[πŸ”— 달λ ₯νŽ˜μ΄μ§€](https://github.com/boostcamp-2020/Project16-A-Account-Book/wiki/%EC%A3%BC%EC%9A%94-%EA%B8%B0%EB%8A%A5-%EC%86%8C%EA%B0%9C#-%EB%8B%AC%EB%A0%A5-%ED%8E%98%EC%9D%B4%EC%A7%80-%EC%86%8C%EA%B0%9C)|
|:--:|:--:|:--:|:--:|
|![](https://i.imgur.com/Vh06k4p.png)|![](https://i.imgur.com/lfBYG9C.png)|![](https://i.imgur.com/fp18GM8.png)|![](https://i.imgur.com/QqL7sad.png)|

|[πŸ”— ν†΅κ³„νŽ˜μ΄μ§€](https://github.com/boostcamp-2020/Project16-A-Account-Book/wiki/%EC%A3%BC%EC%9A%94-%EA%B8%B0%EB%8A%A5-%EC%86%8C%EA%B0%9C#-%ED%86%B5%EA%B3%84-%ED%8E%98%EC%9D%B4%EC%A7%80-%EC%86%8C%EA%B0%9C)|[πŸ”— μ±„νŒ…νŽ˜μ΄μ§€](https://github.com/boostcamp-2020/Project16-A-Account-Book/wiki/%EC%A3%BC%EC%9A%94-%EA%B8%B0%EB%8A%A5-%EC%86%8C%EA%B0%9C#-%EC%B1%84%ED%8C%85-%ED%8E%98%EC%9D%B4%EC%A7%80%EA%B8%B0%EB%8A%A5-%EC%86%8C%EA%B0%9C)|[πŸ”— νƒœκ·ΈνŽ˜μ΄μ§€](https://github.com/boostcamp-2020/Project16-A-Account-Book/wiki/%EC%A3%BC%EC%9A%94-%EA%B8%B0%EB%8A%A5-%EC%86%8C%EA%B0%9C#-%ED%83%9C%EA%B7%B8-%ED%8E%98%EC%9D%B4%EC%A7%80)|[πŸ”— μ•ŒλžŒ λͺ¨λ‹¬](https://github.com/boostcamp-2020/Project16-A-Account-Book/wiki/%EC%A3%BC%EC%9A%94-%EA%B8%B0%EB%8A%A5-%EC%86%8C%EA%B0%9C#-%EC%95%8C%EB%9E%8C-%EB%AA%A8%EB%8B%AC)|
|:--:|:--:|:--:|:--:|
|![](https://i.imgur.com/RDIQb3Q.png)|![](https://i.imgur.com/rhwIsA1.png)|![](https://i.imgur.com/36NIY7b.png)|<img width='500' src='https://i.imgur.com/3N5mWKB.png'>|

## πŸ“Œμ„œλΉ„μŠ€ 흐름
![](https://i.imgur.com/w2UftIk.png)


## βš™οΈ ν”„λ‘œμ νŠΈ ꡬ동 방법

μš°μ„  Repository cloneν•œ ν›„, Project16-A-Account-Book 폴더에 λ“€μ–΄κ°„λ‹€.

**1. λͺ½κ³ λ””λΉ„ μ„€μΉ˜ ν›„ λ°μ΄ν„°λ² μ΄μŠ€ 생성**
**2. λ°±μ—”λ“œ**
- λ°±μ—”λ“œ ν™˜κ²½ λ³€μˆ˜ μ„€μ •
- be 폴더 λ°”λ‘œ 밑에 .env 파일 생성
- .env-template μ•ˆμ— μžˆλŠ” λ‚΄μš© μž‘μ„±
- .env μ˜ˆμ‹œ
- mongodb cloud의 경우 DB_PORTλŠ” μž‘μ„±ν•˜μ§€ μ•ŠκΈ°
```
DB_USER=[λ°μ΄ν„°λ² μ΄μŠ€ μœ μ € 이름 (ex. test)]
DB_PASSWORD=[λ°μ΄ν„°λ² μ΄μŠ€ password (ex. 123123)]
DB_HOST=[λ°μ΄ν„°λ² μ΄μŠ€ 호슀트 이름 (ex. cluster0.3v1lt.mongodb.net)]
DB_DATABASE=[λ°μ΄ν„°λ² μ΄μŠ€ 이름 (ex. account?retryWrites=true&w=majority)]
DB_PORT=[λ°μ΄ν„°λ² μ΄μŠ€ 포트 (ex. 27017)]
JWT_SECRET=[JWT secret key (ex. ajsdFAG430tu04qkn) ]
GITHUB_ID=[GitHub_OAuth_Client_Id (ex. 6df23f10bc0622c89804)]
GITHUB_SECRET=[GitHub_OAuth_Client_Secret]
HOST=[μ„œλ²„ μ£Όμ†Œ (ex. http://localhost)]
BE_PORT=[λ°±μ—”λ“œμ—”λ“œ μ„œλ²„ 포트 (ex. 4000)]
FE_PORT=[ν”„λ‘ νŠΈμ—”λ“œ μ„œλ²„ 포트 (ex. 3000)]
EXPIRES_IN=[JWT 토큰 만료 μ‹œκ°„ (ex. 24h)]
```

- μ‹€ν–‰

```jsx
cd be
yarn
yarn dev
```
or
```jsx
cd be
npm install
npm run dev
```

**3. ν”„λ‘ νŠΈμ—”λ“œ**
- ν”„λ‘ νŠΈμ—”λ“œ ν™˜κ²½ λ³€μˆ˜ μ„€μ •
- fe 폴더 λ°”λ‘œ 밑에 .env.development 파일 생성
- .env_sample에 μžˆλŠ” λ‚΄μš© μž‘μ„±
- .env μ˜ˆμ‹œ
```
REACT_APP_API_URL=[μ„œλ²„ μ£Όμ†Œ (ex. http://localhost)]

REACT_APP_API_PORT=[ν”„λ‘ νŠΈμ—”λ“œ μ„œλ²„ 포트 (ex. 4000)]
```
- μ‹€ν–‰
```jsx
cd fe
yarn
yarn start
```
or
```jsx
cd fe
npm install
npm run start
```
## πŸ“Œ νŒ€μ›μ†Œκ°œ
Expand All @@ -27,6 +138,4 @@
| <img src="https://ca.slack-edge.com/T019JFET9H7-U019R14MZQA-3fc3f52ba025-512" alt="img" height="150px" width="150px" /> | <img src="https://avatars1.githubusercontent.com/u/43772082?s=400&u=7b56e9b176e2f44faa90309d6b2e2820ea679a1c&v=4" alt="img" height="150px" width="150px" /> | <img src="https://ca.slack-edge.com/T019JFET9H7-U0198M695JT-ebc94d8fd643-512" alt="img" height="150px" width="150px" /> | <img src="https://ca.slack-edge.com/T019JFET9H7-U019L3LK929-3a96d76029a8-512" alt="img" height="150px" width="150px" /> |
| [dbstjrwnekd](https://github.com/dbstjrwnekd) | [yejineee](https://github.com/yejineee) | [pkiop](https://github.com/pkiop) | [rolled-potatoes](https://github.com/rolled-potatoes) |
## πŸ“Œ 기술 μŠ€νƒ
<center><img src="https://user-images.githubusercontent.com/44409642/99674728-c9ecfc80-2ab9-11eb-8039-06b9ebdc5e38.png"/></center>
2 changes: 1 addition & 1 deletion be/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"scripts": {
"dev": "cd src && nodemon --exec ts-node -r tsconfig-paths/register app.ts",
"dev": "cd src && NODE_ENV=development nodemon --exec ts-node -r tsconfig-paths/register app.ts",
"seed": "cd src && NODE_ENV=SEED ts-node -r tsconfig-paths/register seed.ts",
"unseed": "cd src && NODE_ENV=UNSEED ts-node -r tsconfig-paths/register seed.ts",
"seed-dev": "npm run seed && npm run dev",
Expand Down
1 change: 0 additions & 1 deletion be/src/.env-template
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,4 @@ GITHUB_ID=
GITHUB_SECRET=
HOST=
BE_PORT=
FE_PORT=
EXPIRES_IN=
2 changes: 1 addition & 1 deletion be/src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ app.use(async (ctx, next) => {
ctx.body = err;
}
});
app.use(cors(corsOptions));

app.use(cors(corsOptions));
app.use(bodyParser());
app.use(Router.routes());
app.use(Router.allowedMethods());
Expand Down
7 changes: 2 additions & 5 deletions be/src/config/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,9 @@ export const getDbUri = () => {
return dbConfig.port ? localUri : srvUri;
};

export const getHostUrl = () => {
return `${hostConfig.url}:${hostConfig.backPort}`;
};

export const getFrontUrl = () => {
return `${hostConfig.url}:${hostConfig.frontPort}`;
const port = process.env.NODE_ENV === 'development' ? ':3000' : '';
return `${hostConfig.url}${port}`;
};

export const corsOptions = {
Expand Down
9 changes: 9 additions & 0 deletions be/src/controllers/user/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export const getUserByAccessToken = async (ctx: Context) => {
ctx.status = 200;
ctx.body = ctx.request.body.user;
};

export const getInvitation = async (ctx: Context) => {
const { user } = ctx.request.body;
const accounts = await userService.getInvitation(user);
Expand All @@ -26,8 +27,16 @@ export const getInvitation = async (ctx: Context) => {
title: account.title,
ownerName: account.ownerName,
host: user.invitations[idx].host,
imageUrl: account.imageUrl,
}));
ctx.body = invitations;
};

export const deleteInvitation = async (ctx: Context) => {
const { user } = ctx.request.body;
const { accountObjId } = ctx.params;
await userService.denyInvitation(user, accountObjId);
ctx.status = 204;
ctx.res.end();
};
export default titleByAccountId;
4 changes: 3 additions & 1 deletion be/src/routers/api/user/account.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import Router from 'koa-router';
import { getInvitation } from 'controllers/user';
import { getInvitation, deleteInvitation } from 'controllers/user';

const router = new Router();

router.get('/', getInvitation);
router.delete('/:accountObjId', deleteInvitation);

export default router;
18 changes: 16 additions & 2 deletions be/src/services/user/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { UserModel, IUserDocument } from 'models/user';
import { AccountModel, IAccountDocument } from 'models/account';
import { AccountModel } from 'models/account';

export const titleByAccountId = async (accountId: String) => {
const account = await AccountModel.findOne(
Expand All @@ -14,14 +14,28 @@ export const getUserList = async () => {
const allUserList = await UserModel.find({}).exec();
return allUserList;
};

export const getInvitation = async (user: IUserDocument) => {
const account: any = user.invitations?.map((invitation) =>
AccountModel.findById(invitation.accounts).select(
'title _id ownerName accountProfile',
'title _id ownerName imageUrl',
),
);
const results = await Promise.all(account);
return results;
};

export const denyInvitation = async (
user: IUserDocument,
accountObjId: string,
) => {
const prevInvitaionLength = user.invitations?.length;
// eslint-disable-next-line no-param-reassign
user.invitations = user.invitations?.filter(
(invitation) => String(invitation.accounts) !== accountObjId,
);
if (user.invitations?.length === prevInvitaionLength)
return Promise.resolve();
return user.save();
};
export default titleByAccountId;
1 change: 1 addition & 0 deletions fe/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
"last 1 safari version"
]
},
"proxy":"http://localhost:4000",
"devDependencies": {
"@babel/core": "^7.12.3",
"@storybook/addon-actions": "^6.0.28",
Expand Down
Binary file added fe/public/favicon.ico
Binary file not shown.
1 change: 1 addition & 0 deletions fe/public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico"/>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
</head>
Expand Down
1 change: 0 additions & 1 deletion fe/src/apis/axios.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import axios from 'axios';

const instance = axios.create({
withCredentials: true,
baseURL: `${process.env.REACT_APP_API_URL}:${process.env.REACT_APP_API_PORT}`,
});

instance.interceptors.response.use(
Expand Down
21 changes: 21 additions & 0 deletions fe/src/components/atoms/DatePicker/index.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import React, { useState } from 'react';

import GlobalThemeProvider from 'styles/GlobalThemeProvider';
import DatePicker from '.';

export default {
title: 'atoms/DatePicker',
component: DatePicker,
};

export const datePicker = () => {
const [date, setDates] = useState<Date | null>(null);
const onChnage = (d: Date) => {
setDates(d);
};
return (
<GlobalThemeProvider>
<DatePicker date={date} onChange={onChnage} disabled={false} />
</GlobalThemeProvider>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -5,35 +5,39 @@ import ReactDatePicker, {
} from 'react-datepicker';
import 'react-datepicker/dist/react-datepicker.css';
import ko from 'date-fns/locale/ko';
import DateRange from '../DateRange';
import * as S from './style';

registerLocale('ko', ko);
setDefaultLocale('ko');
export interface IDatePicker {
dates: {
startDate: Date | null;
endDate: Date | null;
};
date: Date | null;
name?: string;
onChange: any;
disabled: boolean;
}
export interface IButton {
onClick?: any;
}
export interface ICustomInput {
value?: any;
onClick?: any;
}

const DatePicker = ({ dates, onChange }: IDatePicker) => {
const DatePicker = ({
date,
onChange,
name = 'startDate',
disabled,
}: IDatePicker) => {
return (
<S.Container id="date-picker">
<DateRange dates={dates} />
<ReactDatePicker
selected={dates.startDate}
onChange={onChange}
startDate={dates.startDate}
endDate={dates.endDate}
selectsRange
inline
selected={date}
onChange={(d: Date) => onChange(d, name)}
className="my-react-picker"
locale={ko}
disabled={disabled}
dateFormat="yy.MM.dd"
popperPlacement="auto"
popperModifiers={{ preventOverflow: { enabled: true } }}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ export const Container = styled.div`
.react-datepicker__month-container {
font-family: 'Bmeuljiro';
}
.my-react-picker {
background-color: ${({ theme }) => theme.color.white};
border: none;
outline: none;
}
`;

export const DecsContainer = styled.div`
Expand Down
Loading

0 comments on commit 6494f5d

Please sign in to comment.