Skip to content
This repository has been archived by the owner on Sep 8, 2021. It is now read-only.

Modernize the application & Performance tweaks #135

Open
wants to merge 136 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
136 commits
Select commit Hold shift + click to select a range
9294c1a
update dependencies, migrate from willMount to didMount, migrate from…
khaledosman Apr 8, 2019
d1345f9
update react-redux to v7
khaledosman Apr 9, 2019
7775e28
lazy-loading & codeplitting
khaledosman Apr 9, 2019
3564731
bump dependencies
khaledosman Apr 15, 2019
af89125
update to create-react-app/react-scripts v3
khaledosman Apr 23, 2019
f777409
package-lock
khaledosman Apr 23, 2019
6b9d534
get rid of unnecessary componentWillReceiveProps in Settings component
khaledosman Apr 23, 2019
eafbb1f
migrate away from deprecated componentWillReceiveProps
khaledosman Apr 23, 2019
271ea9f
update deprecated import
khaledosman Apr 23, 2019
0dfe95b
bump dependencies
khaledosman May 7, 2019
83cb191
bump dependencies
khaledosman May 15, 2019
5a824e9
upgrade to react-router to v5.0.1
khaledosman Jun 6, 2019
c971ca1
update react-redux to v7.1.0
khaledosman Jun 18, 2019
83a4212
bump dependencies
khaledosman Jul 3, 2019
ea6d874
fix error on logout
khaledosman Jul 8, 2019
814ce01
update marked to v0.7.0
khaledosman Jul 8, 2019
cf6fa2e
fix change between uncontrolled to controlled component warnings
khaledosman Jul 8, 2019
0024f84
update to react v16.9.0
khaledosman Aug 16, 2019
b2524da
fix warnings
khaledosman Aug 16, 2019
f71672a
use fontdisplay:swap for google fonts
khaledosman Aug 27, 2019
0ec1b33
bump dependencies
khaledosman Sep 16, 2019
0f3c489
fix: set default user image
khaledosman Sep 16, 2019
30e3016
fix: ARTICLE_SUBMITTED action causes error when article is null
khaledosman Sep 18, 2019
fe5015b
chore: bump dependencies
khaledosman Jan 2, 2020
7501c69
fix: bump dependencies
khaledosman Jan 2, 2020
414e54d
Merge branch 'master' of https://github.com/khaledosman/react-redux-r…
khaledosman Jan 2, 2020
a7f5992
chore: bump dependencies
khaledosman Jan 17, 2020
a6f5edb
chore: bump dependencies
khaledosman Feb 7, 2020
395553a
chore: bump dependencies
khaledosman Feb 28, 2020
eed6f7f
bump dependencies
khaledosman Aug 10, 2020
299d4cb
dont break the app if the api request fails
khaledosman Aug 28, 2020
3a4f62f
downgrade history to v4.10
khaledosman Aug 28, 2020
13e6b57
add backend URL environment parameter
sashee Dec 29, 2020
8aad14f
Add documentation for the REACT_APP_BACKEND_URL
sashee Dec 29, 2020
02b6511
Merge pull request #1 from sashee/master
khaledosman Dec 30, 2020
cd7d12e
update to react17 and cra v4
khaledosman Jan 27, 2021
f30415b
Fix missing image in Header
sashee Feb 13, 2021
e9e398f
Merge pull request #2 from sashee/patch-1
khaledosman Feb 13, 2021
4bc0c04
bump dependencies
khaledosman Apr 15, 2021
d63d1d8
Configure the store with Redux Toolkit
leosuncin Jun 12, 2021
3e8e7de
remove superagent dependency
leosuncin Jun 12, 2021
f131052
replace marked with snarkdown
leosuncin Jun 12, 2021
d0974df
convert article reducer to slice
leosuncin Jun 12, 2021
14b693c
convert auth reducer to slice
leosuncin Jun 13, 2021
6157cf9
Fix ListError component
leosuncin Jun 13, 2021
e5fc376
convert settings reducer to slice
leosuncin Jun 14, 2021
7fc69d9
convert profile reducer to slice
leosuncin Jun 14, 2021
5128756
install and setup Cypress
leosuncin Jun 14, 2021
52a677c
add e2e test for home page
leosuncin Jun 17, 2021
1c320b7
add e2e test for app navigation
leosuncin Jun 17, 2021
da11ef6
add e2e test for register page
leosuncin Jun 17, 2021
d068f09
add e2e test for login page
leosuncin Jun 17, 2021
ef7c858
add e2e test for editor page
leosuncin Jun 17, 2021
caa71f8
add more e2e test for editor page
leosuncin Jun 18, 2021
130e2b2
add e2e test for settings page
leosuncin Jun 18, 2021
7538550
add e2e test for article page
leosuncin Jun 18, 2021
d4c5e21
generate a markdown with faker
leosuncin Jun 18, 2021
e6880e3
add e2e test for profile page
leosuncin Jun 19, 2021
5723b0e
add more e2e test for app navigation
leosuncin Jun 19, 2021
26988be
add more e2e test for home page
leosuncin Jun 19, 2021
2d3d759
fix generated markdown
leosuncin Jun 19, 2021
e2880b7
stop using markdown because causes issues with compare strings
leosuncin Jun 19, 2021
3276166
ignore .nyc_output directory
leosuncin Jun 19, 2021
803d263
Merge branch 'e2e-tests' into redux-toolkit
leosuncin Jun 19, 2021
b64cd12
fix generate valid values
leosuncin Jun 19, 2021
8d56d5e
Merge branch 'e2e-tests' into redux-toolkit
leosuncin Jun 19, 2021
3a31da0
fix login custom command
leosuncin Jun 19, 2021
4c0bd15
fix comment actions
leosuncin Jun 25, 2021
587bb27
add more e2e test for article page
leosuncin Jun 25, 2021
b6e6562
remove editor reducer
leosuncin Jun 26, 2021
a138c71
change the type of the action dispatched when create an article
leosuncin Jun 26, 2021
2458a72
Update README.md
khaledosman Jul 1, 2021
7c4447e
update links
khaledosman Jul 1, 2021
c16fd53
Update README.md
khaledosman Jul 1, 2021
65ce979
document API client methods
leosuncin Jun 28, 2021
488f8f7
Merge remote-tracking branch 'khaled/master' into redux-toolkit
khaledosman Jul 2, 2021
e1b46b9
merge & update app component to function component
khaledosman Jul 2, 2021
5bb3aca
convert class components to function components
khaledosman Jul 2, 2021
1124ec7
convert articleList reducer to slice
leosuncin Jun 30, 2021
dcd1856
convert common reducer to slice
leosuncin Jun 30, 2021
7895e82
Remove promiseMiddleware
leosuncin Jun 30, 2021
2f0bc55
fix fetch favorite articles in profile
leosuncin Jul 2, 2021
b45af50
regenerate NPM lock-file with npm v6
leosuncin Jul 2, 2021
4d6daeb
fix load article in editor
leosuncin Jul 2, 2021
29f4bca
document API client methods
leosuncin Jun 28, 2021
461515d
convert articleList reducer to slice
leosuncin Jun 30, 2021
3db31a2
convert common reducer to slice
leosuncin Jun 30, 2021
d709847
Remove promiseMiddleware
leosuncin Jun 30, 2021
7a498a3
fix fetch favorite articles in profile
leosuncin Jul 2, 2021
ab503d4
regenerate NPM lock-file with npm v6
leosuncin Jul 2, 2021
c340e90
fix load article in editor
leosuncin Jul 2, 2021
4d50cc2
Merge branch 'khaledosman-redux-toolkit' into redux-toolkit
leosuncin Jul 2, 2021
76425da
fix syntax error in articleList
leosuncin Jul 2, 2021
75fa8c0
refactor login component to use hooks instead of connect
leosuncin Jul 3, 2021
884bed5
refactor list error component
leosuncin Jul 3, 2021
db6e60e
refactor register component to use hooks instead of connect
leosuncin Jul 3, 2021
3a6259a
refactor settings components to use hooks instead of connect
leosuncin Jul 3, 2021
d6c612a
fix profile screen component
leosuncin Jul 3, 2021
2d3e47c
refactor editor component to use hooks instead of connect
leosuncin Jul 5, 2021
bcf3a69
refactor article component to use hooks instead of connect
leosuncin Jul 6, 2021
9ab13ab
refactor to avoid prop drilling in ArticleList
leosuncin Jul 6, 2021
5db3ef2
refactor home component to use hooks instead of connect
leosuncin Jul 6, 2021
ad2ac93
refactor app component to use hooks instead of connect
leosuncin Jul 6, 2021
ace84e0
chore: setup git hooks
leosuncin Jul 26, 2021
658114a
refactor(tags): add tags slice
leosuncin Jul 26, 2021
923f70d
test(tags): add unit tests
leosuncin Jul 26, 2021
55b59ba
refactor(tags): sidebar component
leosuncin Jul 26, 2021
0cf8177
refactor: add function to create the store
leosuncin Jul 26, 2021
869c2ae
chore: setup tests
leosuncin Jul 26, 2021
a6e8452
test(tags): sidebar component
leosuncin Jul 26, 2021
5be270b
refactor(tags): tag list component
leosuncin Jul 26, 2021
e989c78
refactor(auth): auth slice
leosuncin Jul 26, 2021
e860ce5
test(auth): auth slice
leosuncin Jul 26, 2021
fa9de44
refactor(auth): combine Login and Register into AuthScreen
leosuncin Jul 26, 2021
705f987
fix: call next action after the side effects
leosuncin Jul 26, 2021
84057d5
test(auth): login and register forms
leosuncin Jul 26, 2021
d2aaf5e
refactor(settings): remove settings reducer
leosuncin Jul 26, 2021
6b12ff0
refactor(auth): update settings component
leosuncin Jul 26, 2021
527485a
test(auth): add tests for settings screen
leosuncin Jul 26, 2021
a335bce
refactor(comments): add comments slice
leosuncin Jul 27, 2021
d3a48a3
test(comments): add tests for comments slice
leosuncin Jul 27, 2021
228458c
refactor(comments): arrange components
leosuncin Jul 27, 2021
1d889c6
test(comments): add tests for components
leosuncin Jul 27, 2021
be4f438
Merge branch 'gothinkster:master' into master
khaledosman Oct 15, 2021
0d4fbdc
fix: replace url with api.realworld.io
khaledosman Nov 8, 2021
9292e4e
migrate to react v18, getrid of history & connected-react-router, upg…
Apr 13, 2022
dd3492c
Merge remote-tracking branch 'leo/redux-toolkit' into upgrade-codebase
Apr 13, 2022
d76e8df
Merge pull request #11 from khaledosman/upgrade-codebase
khaledosman Apr 13, 2022
d5858c3
fix: fix register path matching
Apr 13, 2022
1e63f98
fixes
Apr 13, 2022
55ce19d
fixes
Apr 13, 2022
13c1bde
pure components
Apr 13, 2022
ec9a5db
navigate after login/register
Apr 13, 2022
de3e564
update dependencies
khaledosman May 15, 2023
d18f275
fix redirect handling on failed login
noalbalint Mar 13, 2024
53b0b4c
Merge pull request #17 from noalbalint/fix-login-failure-flow
khaledosman Mar 13, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# editorconfig.org
root = true

[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[*.md]
trim_trailing_whitespace = false
8 changes: 7 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ node_modules

# testing
coverage
.nyc_output

# production
build
Expand All @@ -13,4 +14,9 @@ build
.DS_Store
.env
npm-debug.log
.idea
.idea

.eslintcache

cypress/videos
cypress/screenshots
4 changes: 4 additions & 0 deletions .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

npx pretty-quick --staged
3 changes: 3 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"singleQuote": true
}
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
# ![React + Redux Example App](project-logo.png)

[![Netlify Status](https://api.netlify.com/api/v1/badges/aa569c8f-ebd5-413e-9fb2-e34facc71873/deploy-status)](https://app.netlify.com/sites/react-redux-realworld/deploys)
[![RealWorld Frontend](https://img.shields.io/badge/realworld-frontend-%23783578.svg)](http://realworld.io)

> ### React + Redux codebase containing real world examples (CRUD, auth, advanced patterns, etc) that adheres to the [RealWorld](https://github.com/gothinkster/realworld-example-apps) spec and API.

<a href="https://stackblitz.com/edit/react-redux-realworld" target="_blank"><img width="187" src="https://github.com/gothinkster/realworld/blob/master/media/edit_on_blitz.png?raw=true" /></a>&nbsp;&nbsp;<a href="https://thinkster.io/tutorials/build-a-real-world-react-redux-application" target="_blank"><img width="384" src="https://raw.githubusercontent.com/gothinkster/realworld/master/media/learn-btn-hr.png" /></a>

### [Demo](https://react-redux.realworld.io)&nbsp;&nbsp;&nbsp;&nbsp;[RealWorld](https://github.com/gothinkster/realworld)
### [Demo](https://react-redux-realworld.netlify.app/)&nbsp;&nbsp;&nbsp;&nbsp;[RealWorld](https://github.com/gothinkster/realworld)

Originally created for this [GH issue](https://github.com/reactjs/redux/issues/1353). The codebase is now feature complete; please submit bug fixes via pull requests & feedback via issues.

We also have notes in [**our wiki**](https://github.com/gothinkster/react-redux-realworld-example-app/wiki) about how the various patterns used in this codebase and how they work (thanks [@thejmazz](https://github.com/thejmazz)!)
We also have notes in [**our wiki**](https://github.com/khaledosman/react-redux-realworld-example-app/wiki) about how the various patterns used in this codebase and how they work (thanks [@thejmazz](https://github.com/thejmazz)!)


## Getting started

You can view a live demo over at https://react-redux.realworld.io/
You can view a live demo over at https://react-redux-realworld.netlify.app/

To get the frontend running locally:

Expand All @@ -29,11 +29,11 @@ Alternatively, you can add `.env` file in the root folder of project to set envi

### Making requests to the backend API

For convenience, we have a live API server running at https://conduit.productionready.io/api for the application to make requests against. You can view [the API spec here](https://github.com/GoThinkster/productionready/blob/master/api) which contains all routes & responses for the server.
For convenience, we have a live API server running at https://api.realworld.io/api for the application to make requests against. You can view [the API spec here](https://github.com/GoThinkster/productionready/blob/master/api) which contains all routes & responses for the server.

The source code for the backend server (available for Node, Rails and Django) can be found in the [main RealWorld repo](https://github.com/gothinkster/realworld).

If you want to change the API URL to a local server, simply edit `src/agent.js` and change `API_ROOT` to the local server's URL (i.e. `http://localhost:3000/api`)
If you want to change the API URL to a local server, start/build the app with the REACT_APP_BACKEND_URL environment variable pointing to the local server's URL (i.e. `REACT_APP_BACKEND_URL="http://localhost:3000/api" npm run build`)


## Functionality overview
Expand Down
9 changes: 9 additions & 0 deletions cypress.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"baseUrl": "http://localhost:4100",
"env": {
"apiUrl": "https://conduit.productionready.io/api",
"username": "warren_boyd",
"email": "[email protected]",
"password": "Pa$$w0rd!"
}
}
22 changes: 22 additions & 0 deletions cypress/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Cypress.io end-to-end tests 🚀

[Cypress.io](https://www.cypress.io) is an open source, MIT licensed end-to-end test runner

## Folder structure

These folders hold the end-to-end tests and supporting files for the [Cypress Test Runner](https://github.com/cypress-io/cypress).

- [fixtures](fixtures) folder holds optional JSON data for mocking, [read more](https://on.cypress.io/fixture)
- [integration](integration) holds the actual test files, [read more](https://on.cypress.io/writing-and-organizing-tests)
- [plugins](plugins) allow you to customize how tests are loaded, [read more](https://on.cypress.io/plugins)
- [support](support) file runs before all tests and is a great place to write or load additional custom commands, [read more](https://on.cypress.io/writing-and-organizing-tests#Support-file)

## `cypress.json` file

You can configure project options in the [../cypress.json](../cypress.json) file, see [Cypress configuration doc](https://on.cypress.io/configuration).

## More information

- [https://github.com/cypress.io/cypress](https://github.com/cypress.io/cypress)
- [https://docs.cypress.io/](https://docs.cypress.io/)
- [Writing your first Cypress test](https://on.cypress.io/intro)
5 changes: 5 additions & 0 deletions cypress/fixtures/example.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"name": "Using fixtures to represent data",
"email": "[email protected]",
"body": "Fixtures are a great way to mock data for responses to routes"
}
177 changes: 177 additions & 0 deletions cypress/integration/article-spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
// enables intelligent code completion for Cypress commands
// https://on.cypress.io/intelligent-code-completion
/// <reference types="cypress" />
/// <reference types="@testing-library/cypress" />
import faker from 'faker';

describe('Article page', () => {
beforeEach(() => {
cy.intercept('GET', '**/articles?*')
.as('getAllArticles')
.intercept('GET', '**/articles/*/comments')
.as('getCommentsForArticle')
.intercept('GET', '**/articles/*')
.as('getArticle')
.visit('/');

cy.wait('@getAllArticles').get('.preview-link').first().click();
});

it('should show the article', () => {
cy.wait('@getArticle')
.its('response.body.article')
.then((article) => {
cy.location('pathname').should('equal', `/article/${article.slug}`);

cy.findByRole('heading', { name: article.title }).should('be.visible');

cy.get('.article-meta').within(() => {
cy.findByRole('img', { name: article.author.username }).should(
'be.visible'
);

cy.findByText(article.author.username).should('be.visible');
});

cy.get('.article-content .col-xs-12')
.children()
.first()
.should('not.be.empty');

cy.get('.tag-list')
.children()
.should('have.length', article.tagList.length);
});
});

it('should require to be logged to comment', () => {
cy.findByText(/to add comments on this article/i).should('be.visible');
});
});

describe('Article page (authenticated)', () => {
const commentPlaceholder = 'Write a comment...';
const postCommentButton = 'Post Comment';

beforeEach(() => {
cy.intercept('GET', '**/articles?*')
.as('getAllArticles')
.intercept('GET', '**/articles/*/comments')
.as('getCommentsForArticle')
.intercept('GET', '**/articles/*')
.as('getArticle')
.intercept('POST', '**/articles/*/comments')
.as('createComment')
.intercept('DELETE', '**/articles/*/comments/*')
.as('deleteComment')
.visit('/')
.login();

cy.wait('@getAllArticles').get('.preview-link').first().click();
});

it('should show the comment box', () => {
cy.wait(['@getArticle', '@getCommentsForArticle']);

cy.get('.comment-form').should('exist');
});

it('should add a new comment', () => {
const comment = faker.lorem.paragraph();

cy.wait(['@getArticle', '@getCommentsForArticle']);

cy.findByPlaceholderText(commentPlaceholder).type(comment);

cy.findByRole('button', { name: postCommentButton }).click();

cy.wait('@createComment').its('response.statusCode').should('equal', 200);

cy.wait(100)
.get('.card:not(form)')
.first()
.within(() => {
cy.findByText(comment).should('exist');
});
});

it('should validate the comment box', () => {
cy.wait(['@getArticle', '@getCommentsForArticle']);

cy.findByRole('button', { name: postCommentButton }).click();

cy.wait('@createComment').its('response.statusCode').should('equal', 422);

cy.get('.error-messages').within(() => {
cy.findAllByRole('listitem').should('have.length', 1);
});
});

it('should remove my own comment', () => {
const comment = faker.lorem.sentence();

cy.wait(['@getArticle', '@getCommentsForArticle']);

cy.findByPlaceholderText(commentPlaceholder).type(comment);

cy.findByRole('button', { name: postCommentButton }).click();

cy.wait('@createComment');

cy.findByText(comment)
.as('comment')
.parent()
.parent()
.find('.mod-options i')
.click();

cy.wait('@deleteComment').its('response.statusCode').should('equal', 200);

cy.findByText(comment).should('not.exist');
});
});

describe('Article page (author)', () => {
const commentPlaceholder = 'Write a comment...';
const postCommentButton = 'Post Comment';

beforeEach(() => {
cy.intercept('GET', '**/articles/*')
.as('getArticle')
.intercept('GET', '**/articles/*/comments')
.as('getCommentsForArticle')
.intercept('POST', '**/articles/*/comments')
.as('createComment')
.intercept('DELETE', '**/articles/*')
.as('deleteArticle');

cy.visit('/')
.login()
.createArticle()
.then((article) => {
cy.visit(`/article/${article.slug}`);

cy.wait(['@getArticle', '@getCommentsForArticle']);
});
});

it('should add a new comment', () => {
const comment = faker.lorem.paragraph();

cy.findByPlaceholderText(commentPlaceholder).type(comment);

cy.findByRole('button', { name: postCommentButton }).click();

cy.wait('@createComment').its('response.statusCode').should('equal', 200);
});

it('should remove my article', () => {
cy.findByRole('button', {
name: /delete article/i,
}).click();

cy.wait('@deleteArticle').its('response.statusCode').should('equal', 200);

cy.location('pathname').should('equal', '/');
});
});
Loading