Skip to content

Commit c1b6786

Browse files
committed
Creates plannings for series viewer page
1 parent a6392d0 commit c1b6786

File tree

31 files changed

+387
-160
lines changed

31 files changed

+387
-160
lines changed
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// @flow
2+
import Sequelize from 'sequelize';
3+
import db from 'database/db';
4+
5+
type SeriesPostCountRow = {
6+
id: string,
7+
count: number,
8+
};
9+
10+
export const getSeriesPostCountList = async (
11+
seriesIds: string[],
12+
): Promise<SeriesPostCountRow[]> => {
13+
const matches = `(${seriesIds.map(seriesId => `'${seriesId}'`).join(', ')})`;
14+
const query = `
15+
select series.id, COUNT(series_posts.fk_post_id) FROM series
16+
left join series_posts on series.id = series_posts.fk_series_id
17+
where series.id IN ${matches}
18+
group by series.id
19+
`;
20+
try {
21+
const rows = await db.query(query, {
22+
type: Sequelize.QueryTypes.SELECT,
23+
});
24+
return rows;
25+
} catch (e) {
26+
throw e;
27+
}
28+
};

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,6 @@ export const writePost = async (ctx: Context): Promise<*> => {
187187
userId: ctx.user.id,
188188
urlSlug: url_slug,
189189
});
190-
console.log(exists);
191190
if (exists > 0) {
192191
processedSlug = uniqueUrlSlug;
193192
}
@@ -265,6 +264,8 @@ export const writePost = async (ctx: Context): Promise<*> => {
265264
ctx.status = 403;
266265
return;
267266
}
267+
series.changed('updated_at', true);
268+
await series.save();
268269
await SeriesPosts.append(series_id, post.id, ctx.user.id);
269270
}
270271

@@ -385,7 +386,6 @@ export const readPost = async (ctx: Context): Promise<*> => {
385386
liked,
386387
});
387388

388-
console.log(seriesPost);
389389
ctx.body = {
390390
...serialized,
391391
series: seriesPost

velog-backend/src/router/series/series.ctrl.js

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ import Joi from 'joi';
44
import { checkEmpty, validateSchema, isUUID } from 'lib/common';
55
import { UserProfile, User, Post } from 'database/models';
66
import pick from 'lodash/pick';
7+
import {
8+
getSeriesPostCountList,
9+
} from 'database/rawQuery/series';
710
import SeriesPosts from '../../database/models/SeriesPosts';
811
import Series, { serializeSeries } from '../../database/models/Series';
912

@@ -171,18 +174,35 @@ export const createSeries = async (ctx: Context) => {
171174
}
172175
};
173176
export const listSeries = async (ctx: Context) => {
177+
const { username } = ctx.params;
174178
try {
175179
const seriesList = await Series.findAll({
176-
limit: 20,
180+
// limit: 20,
177181
include: [
178182
{
179183
model: User,
180184
include: [UserProfile],
185+
...(username
186+
? {
187+
where: {
188+
username,
189+
},
190+
}
191+
: {}),
181192
},
182193
],
183194
order: [['updated_at', 'DESC']],
184195
});
185-
ctx.body = seriesList.map(serializeSeries);
196+
const counts = await getSeriesPostCountList(seriesList.map(series => series.id));
197+
const flatData = {};
198+
counts.forEach((c) => {
199+
flatData[c.id] = c.count;
200+
});
201+
const serialized = seriesList.map(serializeSeries);
202+
serialized.forEach((s) => {
203+
s.posts_count = flatData[s.id];
204+
});
205+
ctx.body = serialized;
186206
} catch (e) {
187207
ctx.throw(500, e);
188208
}
126 KB
Binary file not shown.

velog-frontend/src/components/App.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,17 @@
11
import React from 'react';
22
import { Route, Switch } from 'react-router-dom';
3-
import { Home, Register, Write, Post, User, Saves, Settings, Policy, NotFound } from 'pages';
3+
import {
4+
Home,
5+
Register,
6+
Write,
7+
Post,
8+
User,
9+
Saves,
10+
Settings,
11+
Policy,
12+
Series,
13+
NotFound,
14+
} from 'pages';
415
import EmailLogin from 'containers/etc/EmailLogin';
516
import Core from 'containers/base/Core';
617
import { Helmet } from 'react-helmet';
@@ -32,6 +43,7 @@ const App = () => (
3243
<Route exact path="/@:username/" component={User} />
3344
<Route exact path="/@:username/tags/:tag" component={User} />
3445
<Route exact path="/@:username/:tab(history|about|series)" component={User} />
46+
<Route path="/@:username/series/:urlSlug" component={Series} />
3547
<Route path="/@:username/:urlSlug" component={Post} />
3648
<Route path="/posts/preview/:id" component={Post} />
3749
<Route path="/saves" component={Saves} />

velog-frontend/src/components/base/ViewerHead/ViewerHead.js

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,19 @@
11
// @flow
22
import React, { type Node } from 'react';
33
import { Link } from 'react-router-dom';
4+
import RightCorner from 'containers/base/RightCorner';
45
import './ViewerHead.scss';
56

6-
type Props = {
7-
rightCorner: Node,
8-
};
7+
type Props = {};
98

10-
const ViewerHead = ({ rightCorner }: Props) => (
9+
const ViewerHead = (props: Props) => (
1110
<div className="ViewerHead">
1211
<Link to="/" className="logo-area">
1312
velog
1413
</Link>
15-
<div className="right-corner">{rightCorner}</div>
14+
<div className="right-corner">
15+
<RightCorner />
16+
</div>
1617
</div>
1718
);
1819

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// @flow
2+
import React from 'react';
3+
import { Link } from 'react-router-dom';
4+
import { resizeImage } from 'lib/common';
5+
import defaultThumbnail from 'static/images/default_thumbnail.png';
6+
7+
import './HorizontalUserInfo.scss';
8+
9+
type Props = {
10+
user: {
11+
username: string,
12+
id: string,
13+
thumbnail: ?string,
14+
short_bio: ?string,
15+
},
16+
};
17+
const HorizontalUserInfo = ({ user }: Props) => {
18+
const userLink = `/@${user.username}`;
19+
return (
20+
<div className="HorizontalUserInfo">
21+
<Link to={userLink} className="user-thumbnail">
22+
<img src={resizeImage(user.thumbnail || defaultThumbnail, 128)} alt="user-thumbnail" />
23+
</Link>
24+
<div className="info">
25+
<Link to={userLink} className="username">
26+
@{user.username}
27+
</Link>
28+
<div className="description">{user.short_bio}</div>
29+
</div>
30+
</div>
31+
);
32+
};
33+
34+
HorizontalUserInfo.Placeholder = () => {
35+
return (
36+
<div className="HorizontalUserInfo placeholder">
37+
<div className="user-thumbnail">
38+
<div className="fake-img" />
39+
</div>
40+
<div className="info">
41+
<div className="username">
42+
<div className="gray-block _username" />
43+
</div>
44+
<div className="description">
45+
<div className="gray-block _description" />
46+
</div>
47+
</div>
48+
</div>
49+
);
50+
};
51+
52+
export default HorizontalUserInfo;
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
@import 'utils';
2+
3+
.HorizontalUserInfo {
4+
@include media('<medium') {
5+
background: $oc-gray-0;
6+
margin-top: -0.25rem;
7+
border-top: 1px solid $oc-gray-2;
8+
border-bottom: 1px solid $oc-gray-2;
9+
padding: 1rem;
10+
padding-top: 1rem;
11+
padding-bottom: 1rem;
12+
margin-left: -1rem;
13+
margin-right: -1rem;
14+
}
15+
display: flex;
16+
margin-top: 1em;
17+
margin-bottom: 2rem;
18+
align-items: center;
19+
.user-thumbnail {
20+
flex-shrink: 0;
21+
width: 4em;
22+
height: 4em;
23+
position: relative;
24+
img {
25+
border-radius: 50%;
26+
object-fit: cover;
27+
width: 100%;
28+
height: 100%;
29+
}
30+
}
31+
.info {
32+
margin-left: 1em;
33+
font-size: 0.875em;
34+
line-height: 1.5em;
35+
.username {
36+
font-weight: 500;
37+
color: $oc-gray-9;
38+
}
39+
.description {
40+
word-break: break-word;
41+
color: $oc-gray-6;
42+
}
43+
}
44+
45+
// for placeholder
46+
.fake-img {
47+
background: $oc-gray-1;
48+
border-radius: 50%;
49+
width: 100%;
50+
height: 100%;
51+
animation: Blink 0.5s ease-in-out;
52+
animation-iteration-count: infinite;
53+
animation-direction: alternate;
54+
}
55+
.gray-block {
56+
background: $oc-gray-1;
57+
border-radius: 2px;
58+
height: 1em;
59+
animation: Blink 0.5s ease-in-out;
60+
animation-iteration-count: infinite;
61+
animation-direction: alternate;
62+
&._username {
63+
width: 7rem;
64+
}
65+
&._description {
66+
margin-top: 0.5rem;
67+
width: 11rem;
68+
}
69+
}
70+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
// @flow
2+
export { default } from './HorizontalUserInfo';
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// @flow
2+
import React, { type Node } from 'react';
3+
import './PlainTemplate.scss';
4+
5+
type Props = {
6+
header: Node,
7+
children: Node,
8+
};
9+
10+
const PlainTemplate = ({ children, header }: Props) => (
11+
<div className="PlainTemplate">
12+
<div className="header-area">{header}</div>
13+
<div className="content-area">{children}</div>
14+
</div>
15+
);
16+
17+
export default PlainTemplate;
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
@import 'utils';
2+
.PlainTemplate {
3+
& > .content-area {
4+
margin: 0 auto;
5+
width: 768px;
6+
position: relative;
7+
@include media('<large') {
8+
padding-left: 2rem;
9+
padding-right: 2rem;
10+
width: 100%;
11+
}
12+
@include media('<medium') {
13+
padding-left: 1rem;
14+
padding-right: 1rem;
15+
}
16+
}
17+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
// @flow
2+
export { default } from './PlainTemplate';

0 commit comments

Comments
 (0)