Skip to content

Commit a586997

Browse files
committed
Updating data model
1 parent 36f76cd commit a586997

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

78 files changed

+1387
-896
lines changed

.eslintrc.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ module.exports = {
2828
'import/prefer-default-export': 'off',
2929
'react/prop-types': 'off',
3030
'react/state-in-constructor': 'off',
31+
'react/static-property-placement': ['error', 'static public field'],
32+
'react/destructuring-assignment': ['warn', 'always', { ignoreClassFields: true }],
33+
'no-nested-ternary': 'off',
3134
// '@typescript-eslint/adjacent-overload-signatures': 'warn',
3235
// '@typescript-eslint/array-type': 'warn',
3336
// '@typescript-eslint/ban-types': 'warn',
@@ -50,7 +53,7 @@ module.exports = {
5053
// '@typescript-eslint/member-ordering': 'off',
5154
// '@typescript-eslint/no-empty-function': 'warn',
5255
// '@typescript-eslint/no-empty-interface': 'warn',
53-
// '@typescript-eslint/no-explicit-any': 'off',
56+
'@typescript-eslint/no-explicit-any': 'off',
5457
// '@typescript-eslint/no-misused-new': 'warn',
5558
// '@typescript-eslint/no-namespace': 'warn',
5659
// '@typescript-eslint/no-parameter-properties': 'off',

README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,9 @@ This project is a clone of hacker news rewritten with universal JavaScript, usin
7474
<img alt="Hacker News Clone Architecture Overview" width="auto" height="400px" src="docs/HN-Clone-Architecture-overview.png">
7575
</p>
7676

77-
_Server.js_ is the entry point. It uses Express and passes requests to Next. Next SSR renders the pages using `getInitialProps()` hook from Apollo helper. Therefore the app makes GraphQL requests on the client or server.
77+
_server.ts_ is the entry point. It uses Express and passes requests to Next. Next SSR renders the pages using `getServerSideProps()` hook from Apollo helper. Therefore the app makes GraphQL requests on the client or server.
7878

79-
When the client receives the page it preloads next page JS designated with `<Link prefetch href="/">`. When the client navigates to the linked page it only needs to make a GraphQL query to render. _Great!_
79+
When the client loads the page it preloads next pages code from any `<Link href="/">`. When the client navigates to the next page it only needs to make one GraphQL query to render. _Great!_
8080

8181
See more: <a href="https://github.com/zeit/next.js/">Next.js</a>,
8282
<a href="http://dev.apollodata.com/react/">Apollo GraphQL Client</a>

package-lock.json

+80
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+4-3
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
"build:docker": "docker build --tag 'clintonwoo/hackernews-react-graphql:latest' --rm . && docker run -p 80:3000 --name hackernews-react-graphql clintonwoo/hackernews-react-graphql",
1212
"build:static-website": "NODE_ENV=production rm -rf build/static && npm install --only=dev && next build && next export -o build/static",
1313
"debug": "DEBUG=app:* npm start",
14-
"debug:inspect": "node --inspect -r ts-node/register src/server.ts",
14+
"debug:inspect": "cross-env TS_NODE_COMPILER_OPTIONS={\\\"module\\\":\\\"commonjs\\\"} node --inspect -r ts-node/register src/server.ts",
1515
"debug:inspect-production": "NODE_ENV=production node --inspect dist/server.js",
1616
"debug:inspectr": "NODE_ENV=production DEBUG=app* ts-node --inspect dist/server.js",
1717
"debug:all": "DEBUG=* npm start",
@@ -21,7 +21,7 @@
2121
"prettier:format": "prettier --write .",
2222
"test": "jest --config jest.config.js",
2323
"tsc:check": "tsc --noEmit",
24-
"start": "ts-node --compiler-options=\"{\"\"module\"\":\"\"commonjs\"\"}\" src/server.ts",
24+
"start": "cross-env TS_NODE_COMPILER_OPTIONS={\\\"module\\\":\\\"commonjs\\\"} ts-node src/server.ts",
2525
"start:prod": "NODE_ENV=production node dist/server.js"
2626
},
2727
"author": "Clinton D'Annolfo",
@@ -49,7 +49,7 @@
4949
"graphql": "14.6.0",
5050
"graphql-tag": "2.10.3",
5151
"graphql-tools": "4.0.7",
52-
"isomorphic-fetch": "2.2.1",
52+
"isomorphic-unfetch": "3.0.0",
5353
"lru-cache": "5.1.1",
5454
"next": "9.3.1",
5555
"passport": "0.4.1",
@@ -83,6 +83,7 @@
8383
"@zeit/next-css": "1.0.1",
8484
"babel-loader": "8.1.0",
8585
"babel-plugin-transform-define": "2.0.0",
86+
"cross-env": "7.0.2",
8687
"enzyme": "3.11.0",
8788
"enzyme-adapter-react-16": "1.15.2",
8889
"enzyme-to-json": "3.4.4",

prettier.config.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,5 @@ module.exports = {
33
tabWidth: 2,
44
semi: true,
55
singleQuote: true,
6-
printWidth: 120,
6+
printWidth: 100,
77
};

src/README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
_src_ - Source code
44

5-
- _\_\_tests\_\__: Jest tests colocated in each folder.
5+
- \_\_\_tests\_\_\_: Jest tests colocated in each folder.
66
- _.next_: Next build files containing code-split modules and assets.
77
- _components_: React components with GraphQL fragments colocated in-file.
88
- _data_: GraphQL Schema, HN Web APIs, cache, sample data.

src/components/comment.tsx

+3-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,9 @@ export class Comment extends React.Component<ICommentProps> {
5050
alt=""
5151
src="/static/s.gif"
5252
height="1"
53-
width={`${indentationLevel * 40}px`} /* Width varies depending on comment level */
53+
width={`${
54+
indentationLevel * 40
55+
}px`} /* Width varies depending on comment level */
5456
/>
5557
</td>
5658
<td style={{ verticalAlign: 'top' }} className="votelinks">

src/components/comments.tsx

+6-4
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import * as React from 'react';
22

3-
import { NewsItem } from '../data/models/news-item';
3+
import { NewsItemModel } from '../data/models';
44
import { Comment, commentFragment } from './comment';
55

66
export interface ICommentsProps {
7-
newsItem: NewsItem;
7+
newsItem: NewsItemModel;
88
}
99

1010
export const commentsFragment = `
@@ -32,8 +32,10 @@ export const commentsFragment = `
3232
`;
3333

3434
export class Comments extends React.Component<ICommentsProps> {
35-
renderComment = (comment, indent): JSX.Element => {
36-
return <Comment key={comment.id} parentId={comment.parent} indentationLevel={indent} {...comment} />;
35+
renderComment = (comment, indent: number): JSX.Element => {
36+
return (
37+
<Comment key={comment.id} parentId={comment.parent} indentationLevel={indent} {...comment} />
38+
);
3739
};
3840

3941
render(): JSX.Element {

src/components/header.tsx

+5-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,11 @@ export function Header(props: IHeaderProps): JSX.Element {
4545
<a>{me.id}</a>
4646
</Link>
4747
{` (${me.karma}) | `}
48-
<a href={`/logout?auth=d78ccc2c6120ffe08f32451519c2ff46d34c51ab&amp;goto=${currentUrl}`}>logout</a>
48+
<a
49+
href={`/logout?auth=d78ccc2c6120ffe08f32451519c2ff46d34c51ab&amp;goto=${currentUrl}`}
50+
>
51+
logout
52+
</a>
4953
</span>
5054
) : (
5155
<span className="pagetop">

src/components/news-detail.spec.tsx

+3-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ MockDate.set(1506022129802);
1313
describe('NewsFeed component', () => {
1414
it('renders news items passed in as props', () => {
1515
const hideNewsItem = () => console.log('1');
16-
const wrapper = shallow(<NewsDetail {...newsItem} hideNewsItem={hideNewsItem} isFavoriteVisible={false} />);
16+
const wrapper = shallow(
17+
<NewsDetail {...newsItem} hideNewsItem={hideNewsItem} isFavoriteVisible={false} />
18+
);
1719
expect(wrapper).toMatchSnapshot();
1820
});
1921
});

src/components/news-detail.tsx

+31-18
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import Router from 'next/router';
44
import * as React from 'react';
55
import { graphql } from 'react-apollo';
66

7-
import { hideNewsItemMutation } from '../data/mutations/hide-news-item';
7+
import { hideNewsItemMutation } from '../data/mutations/hide-news-item-mutation';
88
import { convertNumberToTimeAgo } from '../helpers/convert-number-to-time-ago';
99

1010
interface INewsDetailProps extends INewsDetailOwnProps {
@@ -76,7 +76,11 @@ export function NewsDetailView(props: INewsDetailProps): JSX.Element {
7676
</Link>
7777
</span>
7878
{' | '}
79-
{hidden ? <a onClick={() => hideNewsItem(id)}>hide</a> : <a onClick={() => unhideNewsItem(id)}>hide</a>}
79+
{hidden ? (
80+
<a onClick={() => hideNewsItem(id)}>hide</a>
81+
) : (
82+
<a onClick={() => unhideNewsItem(id)}>hide</a>
83+
)}
8084
{isPostScrutinyVisible && (
8185
<span>
8286
{' | '}
@@ -89,7 +93,13 @@ export function NewsDetailView(props: INewsDetailProps): JSX.Element {
8993
)}
9094
{' | '}
9195
<Link href={`/item?id=${id}`}>
92-
<a>{commentCount === 0 ? 'discuss' : commentCount === 1 ? '1 comment' : `${commentCount} comments`}</a>
96+
<a>
97+
{commentCount === 0
98+
? 'discuss'
99+
: commentCount === 1
100+
? '1 comment'
101+
: `${commentCount} comments`}
102+
</a>
93103
</Link>
94104
{isFavoriteVisible && ' | favorite'}
95105
</td>
@@ -103,18 +113,21 @@ NewsDetailView.defaultProps = {
103113
isPostScrutinyVisible: false,
104114
};
105115

106-
export const NewsDetail = graphql<INewsDetailOwnProps, {}, {}, INewsDetailProps>(gql(hideNewsItemMutation), {
107-
props({ ownProps, mutate }) {
108-
return {
109-
...ownProps,
110-
hideNewsItem: (id: number): Promise<any> =>
111-
mutate!({ variables: { id } }).catch(() => {
112-
Router.push('/login', `/hide?id=${id}&how=up&goto=news`);
113-
}),
114-
unhideNewsItem: (id: number): Promise<any> =>
115-
mutate!({ variables: { id } }).catch(() => {
116-
Router.push('/login', `/unhide?id=${id}&how=up&goto=news`);
117-
}),
118-
};
119-
},
120-
})(NewsDetailView);
116+
export const NewsDetail = graphql<INewsDetailOwnProps, {}, {}, INewsDetailProps>(
117+
gql(hideNewsItemMutation),
118+
{
119+
props({ ownProps, mutate }) {
120+
return {
121+
...ownProps,
122+
hideNewsItem: (id: number): Promise<any> =>
123+
mutate!({ variables: { id } }).catch(() => {
124+
Router.push('/login', `/hide?id=${id}&how=up&goto=news`);
125+
}),
126+
unhideNewsItem: (id: number): Promise<any> =>
127+
mutate!({ variables: { id } }).catch(() => {
128+
Router.push('/login', `/unhide?id=${id}&how=up&goto=news`);
129+
}),
130+
};
131+
},
132+
}
133+
)(NewsDetailView);

src/components/news-feed.spec.tsx

+3-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ MockDate.set(1506022129802);
99

1010
describe('NewsFeed component', () => {
1111
it('renders news items passed in as props', () => {
12-
const wrapper = shallow(<NewsFeed newsItems={sampleData.newsItems} currentUrl="/" first={30} skip={0} />);
12+
const wrapper = shallow(
13+
<NewsFeed newsItems={sampleData.newsItems} currentUrl="/" first={30} skip={0} />
14+
);
1315
expect(wrapper).toMatchSnapshot();
1416
});
1517
});

src/components/news-feed.tsx

+12-4
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
import * as React from 'react';
22
import { DataValue } from 'react-apollo';
33

4-
import { NewsItem } from '../data/models';
4+
import { NewsItemModel } from '../data/models';
55
import { LoadingSpinner } from './loading-spinner';
66
import { NewsDetail, newsDetailNewsItemFragment } from './news-detail';
77
import { NewsTitle, newsTitleFragment } from './news-title';
88

99
export interface INewsFeedProps {
1010
isPostScrutinyVisible?: boolean;
1111
first: number;
12-
newsItems: NewsItem[];
12+
newsItems: NewsItemModel[];
1313
notice?: JSX.Element;
1414
skip: number;
1515
isJobListing?: boolean;
@@ -84,7 +84,12 @@ export function NewsFeedView(props: INewsFeedProps): JSX.Element {
8484
<tr>
8585
<td style={{ padding: '0px' }}>
8686
<table
87-
style={{ border: '0px', padding: '0px', borderCollapse: 'collapse', borderSpacing: '0px' }}
87+
style={{
88+
border: '0px',
89+
padding: '0px',
90+
borderCollapse: 'collapse',
91+
borderSpacing: '0px',
92+
}}
8893
className="itemlist"
8994
>
9095
<tbody>
@@ -115,7 +120,10 @@ export interface INewsFeedContainerProps {
115120
options;
116121
}
117122

118-
export const NewsFeed: React.SFC<INewsFeedContainerProps> = ({ data: { error, feed }, options }) => {
123+
export const NewsFeed: React.SFC<INewsFeedContainerProps> = ({
124+
data: { error, feed },
125+
options,
126+
}) => {
119127
if (error) {
120128
return (
121129
<tr>

0 commit comments

Comments
 (0)