Skip to content

Commit bf45d6f

Browse files
committed
implemented loading temp saves
1 parent f570c48 commit bf45d6f

File tree

11 files changed

+155
-19
lines changed

11 files changed

+155
-19
lines changed

velog-backend/src/router/posts/post/saves/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import * as savesCtrl from './saves.ctrl';
77
const saves: Router = new Router();
88

99
saves.get('/', savesCtrl.getTempSaveList);
10+
saves.get('/:saveId', savesCtrl.loadTempSave);
1011
saves.post('/', savesCtrl.tempSave);
1112

1213
export default saves;

velog-backend/src/router/posts/post/saves/saves.ctrl.js

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// @flow
22
import type { Context, Middleware } from 'koa';
33
import Joi from 'joi';
4-
import { validateSchema, extractKeys } from 'lib/common';
4+
import { validateSchema, extractKeys, isUUID } from 'lib/common';
55
import PostHistory from 'database/models/PostHistory';
66

77
export const tempSave = async (ctx: Context): Promise<*> => {
@@ -14,7 +14,9 @@ export const tempSave = async (ctx: Context): Promise<*> => {
1414
const { id } = ctx.params;
1515

1616
const schema = Joi.object().keys({
17-
title: Joi.string().min(1).max(120),
17+
title: Joi.string()
18+
.min(1)
19+
.max(120),
1820
body: Joi.string().min(1),
1921
is_release: Joi.boolean(),
2022
});
@@ -34,13 +36,39 @@ export const tempSave = async (ctx: Context): Promise<*> => {
3436
}).save();
3537

3638
ctx.body = extractKeys(postHistory, [
37-
'id', 'title', 'body', 'created_at', 'is_release',
39+
'id',
40+
'title',
41+
'body',
42+
'created_at',
43+
'is_release',
3844
]);
3945
} catch (e) {
4046
ctx.throw(500, e);
4147
}
4248
};
4349

50+
export const loadTempSave: Middleware = async (ctx) => {
51+
const { id, saveId } = ctx.params;
52+
if (!isUUID(saveId)) {
53+
ctx.body = {
54+
name: 'NOT_UUID',
55+
};
56+
ctx.status = 400;
57+
return;
58+
}
59+
try {
60+
const postHistory = await PostHistory.findOne({
61+
where: {
62+
fk_post_id: id,
63+
id: saveId,
64+
},
65+
});
66+
ctx.body = postHistory;
67+
} catch (e) {
68+
ctx.throw(500, e);
69+
}
70+
};
71+
4472
export const getTempSaveList: Middleware = async (ctx: Context) => {
4573
const { id } = ctx.params;
4674
const page = parseInt(ctx.query.page || 1, 10);
Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// @flow
22
import React, { type Node } from 'react';
3+
import { Link } from 'react-router-dom';
34
import cx from 'classnames';
45
import './Button.scss';
56

@@ -9,21 +10,42 @@ type Props = {
910
cancel?: boolean,
1011
violetFont?: boolean,
1112
className?: string,
13+
to?: ?string,
1214
children: Node,
1315
};
1416

15-
const Button = ({ theme, children, confirm, cancel, violetFont, className, ...rest }: Props) => (
16-
<button className={cx('Button', theme, className, { confirm, cancel, violetFont })} {...rest}>
17-
{children}
18-
</button>
19-
);
17+
const Button = ({
18+
theme,
19+
children,
20+
confirm,
21+
cancel,
22+
violetFont,
23+
className,
24+
to,
25+
...rest
26+
}: Props) => {
27+
const processedClassName = cx('Button', theme, className, { confirm, cancel, violetFont });
28+
if (to) {
29+
return (
30+
<Link className={processedClassName} to={to} {...rest}>
31+
{children}
32+
</Link>
33+
);
34+
}
35+
return (
36+
<button className={processedClassName} {...rest}>
37+
{children}
38+
</button>
39+
);
40+
};
2041

2142
Button.defaultProps = {
2243
theme: 'default',
2344
confirm: false,
2445
cancel: false,
2546
violetFont: false,
2647
className: '',
48+
to: null,
2749
};
2850

2951
export default Button;

velog-frontend/src/components/main/MainHead/MainHead.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ type Props = {
1414

1515
const MainHead = ({ logged, onLogin, rightArea }: Props) => (
1616
<div className="MainHead">
17-
<div className="button-area">{logged && <Button>새 포스트 작성</Button>}</div>
17+
<div className="button-area">{logged && <Button to="/write">새 포스트 작성</Button>}</div>
1818
<div className="spacer" />
1919
<div className="right-area">
2020
{rightArea || (

velog-frontend/src/components/post/PostContent/PostContent.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,11 @@ type Props = {
1313

1414
const PostContent = ({ body, onSetToc, onActivateHeading, thumbnail }: Props) => (
1515
<div className="PostContent">
16-
<div className="post-thumbnail">
17-
<img src={thumbnail} alt="" />
18-
</div>
16+
{thumbnail && (
17+
<div className="post-thumbnail">
18+
<img src={thumbnail} alt="" />
19+
</div>
20+
)}
1921
<div className="contents">
2022
<MarkdownRender body={body} onSetToc={onSetToc} onActivateHeading={onActivateHeading} />
2123
</div>

velog-frontend/src/components/write/SubmitBox/SubmitBox.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import React, { Fragment, Component, type Node } from 'react';
33
import onClickOutside from 'react-onclickoutside';
44
import SettingsIcon from 'react-icons/lib/md/settings';
55
import cx from 'classnames';
6+
import { Link } from 'react-router-dom';
67

78
import './SubmitBox.scss';
89
import SubmitBoxAdditional from '../SubmitBoxAdditional';
@@ -19,6 +20,7 @@ type Props = {
1920
onEditCategoryClick(): void,
2021
onToggleAdditionalConfig(): void,
2122
additional: Node | false,
23+
postLink: ?string,
2224
};
2325

2426
type State = {
@@ -75,6 +77,7 @@ class SubmitBox extends Component<Props, State> {
7577
configureThumbnail,
7678
onToggleAdditionalConfig,
7779
additional,
80+
postLink,
7881
} = this.props;
7982
const { animating } = this.state;
8083

@@ -84,7 +87,12 @@ class SubmitBox extends Component<Props, State> {
8487
<div className={cx('SubmitBox', visible ? 'appear' : 'disappear')}>
8588
<div className="title">
8689
<div className="text">{isEdit ? '글 수정하기' : '새 글 작성하기'}</div>
87-
{isEdit && <div className="view">글 보기</div>}
90+
{isEdit &&
91+
postLink && (
92+
<Link className="view" to={postLink}>
93+
글 보기
94+
</Link>
95+
)}
8896
</div>
8997
{additional || (
9098
<Fragment>

velog-frontend/src/containers/base/RightCorner.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ class RightCorner extends Component<Props> {
2020
if (!user) return null;
2121
return (
2222
<Fragment>
23-
<NotificationButton count={10} onClick={() => undefined} />
23+
{/* <NotificationButton count={10} onClick={() => undefined} /> */}
2424
<UserButton onClick={this.onUserButtonClick} thumbnail={user.thumbnail} />
2525
<UserMenuContainer />
2626
</Fragment>

velog-frontend/src/containers/write/SubmitBoxContainer.js

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ type Props = {
2626
thumbnail: ?string,
2727
additional: boolean,
2828
meta: Meta,
29+
username: ?string,
2930
};
3031

3132
class SubmitBoxContainer extends Component<Props> {
@@ -200,9 +201,24 @@ class SubmitBoxContainer extends Component<Props> {
200201
onCancelAdditionalConfig,
201202
onConfirmAdditionalConfig,
202203
} = this;
203-
const { body, open, categories, tags, postData, thumbnail, additional, meta } = this.props;
204+
205+
const {
206+
body,
207+
open,
208+
categories,
209+
tags,
210+
postData,
211+
thumbnail,
212+
additional,
213+
meta,
214+
username,
215+
} = this.props;
216+
217+
const postLink = username && postData && `/@${username}/${postData.url_slug}`;
218+
204219
return (
205220
<SubmitBox
221+
postLink={postLink}
206222
onEditCategoryClick={onEditCategoryClick}
207223
selectCategory={<SelectCategory categories={categories} onToggle={onToggleCategory} />}
208224
inputTags={<InputTags tags={tags} onInsert={onInsertTag} onRemove={onRemoveTag} />}
@@ -237,7 +253,7 @@ class SubmitBoxContainer extends Component<Props> {
237253
}
238254

239255
export default connect(
240-
({ write }: State) => ({
256+
({ write, user }: State) => ({
241257
open: write.submitBox.open,
242258
categories: write.submitBox.categories,
243259
tags: write.submitBox.tags,
@@ -250,6 +266,7 @@ export default connect(
250266
thumbnail: write.thumbnail,
251267
additional: write.submitBox.additional,
252268
meta: write.meta,
269+
username: user.user && user.user.username,
253270
}),
254271
() => ({}),
255272
)(SubmitBoxContainer);

velog-frontend/src/containers/write/WriteExtraContainer.js

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,28 @@ import WriteExtra from 'components/write/WriteExtra/WriteExtra';
44
import { connect } from 'react-redux';
55
import type { State } from 'store';
66
import { WriteActions } from 'store/actionCreators';
7+
import type { PostData } from 'store/modules/write';
78

89
type Props = {
910
visible: boolean,
1011
mode: string,
12+
postData: ?PostData,
1113
};
14+
1215
class WriteExtraContainer extends Component<Props> {
16+
async listTempSave() {
17+
const { postData } = this.props;
18+
if (!postData) return;
19+
WriteActions.listTempSaves(postData.id);
20+
}
21+
22+
componentDidUpdate(prevProps) {
23+
if (!prevProps.visible && this.props.visible) {
24+
// WriteExtra is now visible
25+
this.listTempSave();
26+
}
27+
}
28+
1329
onSelectLayoutMode = (mode) => {
1430
WriteActions.setLayoutMode(mode);
1531
};
@@ -33,6 +49,10 @@ class WriteExtraContainer extends Component<Props> {
3349
}
3450

3551
export default connect(
36-
({ write }: State) => ({ visible: write.writeExtra.visible, mode: write.writeExtra.layoutMode }),
52+
({ write }: State) => ({
53+
visible: write.writeExtra.visible,
54+
mode: write.writeExtra.layoutMode,
55+
postData: write.postData,
56+
}),
3757
() => ({}),
3858
)(WriteExtraContainer);
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// @flow
2+
import axios from 'lib/defaultClient';
3+
4+
export const getTempSaveList = (postId: string) => axios.get(`/posts/${postId}/saves`);
5+
6+
export type LoadTempSavePayload = {
7+
postId: string,
8+
saveId: string,
9+
};
10+
11+
export const loadTempSave = ({ postId, saveId }: LoadTempSavePayload) => {
12+
axios.get(`/posts/${postId}/saves/${saveId}`);
13+
};

0 commit comments

Comments
 (0)