Repository: piotrwitek/react-redux-typescript-realworld-app
Branch: master
Commit: f92c56a61265
Files: 61
Total size: 49.5 KB
Directory structure:
gitextract_6ug6f53y/
├── .eslintrc
├── .gitignore
├── .prettierrc
├── .vscode/
│ └── settings.json
├── CODE_OF_CONDUCT.md
├── README.md
├── lambdas/
│ ├── .babelrc
│ ├── build/
│ │ └── hello.js
│ └── src/
│ └── hello.ts
├── netlify.toml
├── package.json
├── public/
│ ├── index.html
│ └── manifest.json
├── server/
│ ├── package.json
│ ├── src/
│ │ └── env.ts
│ └── tsconfig.json
├── src/
│ ├── App.test.tsx
│ ├── App.tsx
│ ├── components/
│ │ ├── BackLink.tsx
│ │ ├── FlexBox.tsx
│ │ ├── FlexColumn.tsx
│ │ └── FlexRow.tsx
│ ├── features/
│ │ ├── app/
│ │ │ └── epics.ts
│ │ └── articles/
│ │ ├── actions.ts
│ │ ├── components/
│ │ │ ├── ArticleActionsMenu.tsx
│ │ │ ├── ArticleForm.tsx
│ │ │ ├── ArticleList.tsx
│ │ │ ├── ArticleListItem.tsx
│ │ │ └── ArticleView.tsx
│ │ ├── epics.ts
│ │ ├── reducer.ts
│ │ ├── selectors.ts
│ │ └── types.d.ts
│ ├── index.css
│ ├── index.tsx
│ ├── layouts/
│ │ ├── Main.css
│ │ └── Main.tsx
│ ├── react-app-env.d.ts
│ ├── router-paths.ts
│ ├── routes/
│ │ ├── AddArticle.tsx
│ │ ├── EditArticle.tsx
│ │ ├── Home.tsx
│ │ └── ViewArticle.tsx
│ ├── serviceWorker.ts
│ ├── services/
│ │ ├── articles-api-client.ts
│ │ ├── index.ts
│ │ ├── local-storage-service.ts
│ │ ├── logger-service.ts
│ │ ├── toast-service.ts
│ │ └── types.d.ts
│ └── store/
│ ├── index.ts
│ ├── root-action.ts
│ ├── root-epic.ts
│ ├── root-reducer.ts
│ ├── types.d.ts
│ └── utils.ts
├── tsconfig.json
├── tsconfig.test.json
└── typings/
├── augmentations.d.ts
├── globals.d.ts
└── modules.d.ts
================================================
FILE CONTENTS
================================================
================================================
FILE: .eslintrc
================================================
{
"extends": [
"react-app",
"./node_modules/react-redux-typescript-scripts/eslint.js"
]
}
================================================
FILE: .gitignore
================================================
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/server/node_modules
/.pnp
.pnp.js
# testing
/coverage
# production
/build
/server/build
# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*
================================================
FILE: .prettierrc
================================================
{
"printWidth": 80,
"semi": true,
"singleQuote": true,
"trailingComma": "es5"
}
================================================
FILE: .vscode/settings.json
================================================
{
"typescript.tsdk": "node_modules/typescript/lib"
}
================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, sex characteristics, gender identity and expression,
level of experience, education, socio-economic status, nationality, personal
appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at piotrek.witek@gmail.com. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see
https://www.contributor-covenant.org/faq
================================================
FILE: README.md
================================================
# React, Redux, TypeScript - RealWorld App
## 🚧🚧🚧 UNDER CONSTRUCTION 🚧🚧🚧
### **LIVE DEMO: [LINK](https://react-redux-typescript-realworld-app.netlify.com/)**
_Reference implementation of RealWorld [JAMStack](https://jamstack.org/) Application based on ["React, Redux, TypeScript Guide"](https://github.com/piotrwitek/react-redux-typescript-guide)
and [Create React App v3.0](https://facebook.github.io/create-react-app/)._
---
## Features Roadmap:
- [x] Routing with React-Router
- [ ] User Identity
- [ ] External providers (Google, Github, Bitbucket)
- [ ] Registration / Authentication
- [x] Cross-cutting Application Services
- [x] Local Storage
- [x] Client Logger
- [x] Toasts
- [ ] Analytics
- [x] Feature Folders
- [x] `/articles` - Articles listing with CRUD Operations
- [ ] `/realtime-monitoring` - Realtime monitoring of connected users using Websockets
- [x] REST API Integration (API Client)
- [ ] WebSockets Integration
- [ ] Serverless Lambda Functions (Netlify Functions)
- [ ] Utilities (HOC, Hooks, Media Queries...)
- [ ] Typesafe Styling/Theming with CSSinJS (`Emotion`)
- [ ] ...
---
## Available Scripts
### `npm start`
Runs the app in the development modeat [http://localhost:3000](http://localhost:3000)
### `npm test`
Launches the test runner in the interactive watch mode.
See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
### `npm run build`
Builds the app for production to the `build` folder.
See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
## Learn More
This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
================================================
FILE: lambdas/.babelrc
================================================
// lambda build config
{
"presets": ["@babel/preset-typescript", "@babel/preset-env"],
"plugins": [
"@babel/transform-runtime",
"@babel/plugin-proposal-class-properties",
"@babel/plugin-transform-object-assign",
"@babel/plugin-proposal-object-rest-spread"
]
}
================================================
FILE: lambdas/build/hello.js
================================================
!function(t,r){for(var e in r)t[e]=r[e]}(exports,function(t){var r={};function e(n){if(r[n])return r[n].exports;var o=r[n]={i:n,l:!1,exports:{}};return t[n].call(o.exports,o,o.exports,e),o.l=!0,o.exports}return e.m=t,e.c=r,e.d=function(t,r,n){e.o(t,r)||Object.defineProperty(t,r,{enumerable:!0,get:n})},e.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},e.t=function(t,r){if(1&r&&(t=e(t)),8&r)return t;if(4&r&&"object"==typeof t&&t&&t.__esModule)return t;var n=Object.create(null);if(e.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:t}),2&r&&"string"!=typeof t)for(var o in t)e.d(n,o,function(r){return t[r]}.bind(null,o));return n},e.n=function(t){var r=t&&t.__esModule?function(){return t.default}:function(){return t};return e.d(r,"a",r),r},e.o=function(t,r){return Object.prototype.hasOwnProperty.call(t,r)},e.p="",e(e.s=3)}([function(t,r,e){t.exports=e(4)},function(t,r){function e(t,r,e,n,o,i,a){try{var u=t[i](a),c=u.value}catch(t){return void e(t)}u.done?r(c):Promise.resolve(c).then(n,o)}t.exports=function(t){return function(){var r=this,n=arguments;return new Promise(function(o,i){var a=t.apply(r,n);function u(t){e(a,o,i,u,c,"next",t)}function c(t){e(a,o,i,u,c,"throw",t)}u(void 0)})}}},function(t,r){t.exports=require("querystring")},function(t,r,e){"use strict";e.r(r),e.d(r,"handler",function(){return f});var n=e(0),o=e.n(n),i=e(1),a=e.n(i),u=e(2),c=e.n(u),f=function(){var t=a()(o.a.mark(function t(r,e){var n,i;return o.a.wrap(function(t){for(;;)switch(t.prev=t.next){case 0:t.t0=r.httpMethod,t.next="GET"===t.t0?3:"POST"===t.t0?4:7;break;case 3:return t.abrupt("return",{statusCode:200,body:"Hello, World!"});case 4:return n=c.a.parse(r.body),i=n.name||"World!",t.abrupt("return",{statusCode:200,body:"Hello, ".concat(i)});case 7:return t.abrupt("return",{statusCode:405,body:"Method Not Allowed"});case 8:case"end":return t.stop()}},t)}));return function(r,e){return t.apply(this,arguments)}}()},function(t,r,e){var n=function(t){"use strict";var r,e=Object.prototype,n=e.hasOwnProperty,o="function"==typeof Symbol?Symbol:{},i=o.iterator||"@@iterator",a=o.asyncIterator||"@@asyncIterator",u=o.toStringTag||"@@toStringTag";function c(t,r,e,n){var o=r&&r.prototype instanceof d?r:d,i=Object.create(o.prototype),a=new P(n||[]);return i._invoke=function(t,r,e){var n=s;return function(o,i){if(n===h)throw new Error("Generator is already running");if(n===p){if("throw"===o)throw i;return k()}for(e.method=o,e.arg=i;;){var a=e.delegate;if(a){var u=_(a,e);if(u){if(u===y)continue;return u}}if("next"===e.method)e.sent=e._sent=e.arg;else if("throw"===e.method){if(n===s)throw n=p,e.arg;e.dispatchException(e.arg)}else"return"===e.method&&e.abrupt("return",e.arg);n=h;var c=f(t,r,e);if("normal"===c.type){if(n=e.done?p:l,c.arg===y)continue;return{value:c.arg,done:e.done}}"throw"===c.type&&(n=p,e.method="throw",e.arg=c.arg)}}}(t,e,a),i}function f(t,r,e){try{return{type:"normal",arg:t.call(r,e)}}catch(t){return{type:"throw",arg:t}}}t.wrap=c;var s="suspendedStart",l="suspendedYield",h="executing",p="completed",y={};function d(){}function v(){}function g(){}var m={};m[i]=function(){return this};var w=Object.getPrototypeOf,b=w&&w(w(S([])));b&&b!==e&&n.call(b,i)&&(m=b);var x=g.prototype=d.prototype=Object.create(m);function L(t){["next","throw","return"].forEach(function(r){t[r]=function(t){return this._invoke(r,t)}})}function E(t){var r;this._invoke=function(e,o){function i(){return new Promise(function(r,i){!function r(e,o,i,a){var u=f(t[e],t,o);if("throw"!==u.type){var c=u.arg,s=c.value;return s&&"object"==typeof s&&n.call(s,"__await")?Promise.resolve(s.__await).then(function(t){r("next",t,i,a)},function(t){r("throw",t,i,a)}):Promise.resolve(s).then(function(t){c.value=t,i(c)},function(t){return r("throw",t,i,a)})}a(u.arg)}(e,o,r,i)})}return r=r?r.then(i,i):i()}}function _(t,e){var n=t.iterator[e.method];if(n===r){if(e.delegate=null,"throw"===e.method){if(t.iterator.return&&(e.method="return",e.arg=r,_(t,e),"throw"===e.method))return y;e.method="throw",e.arg=new TypeError("The iterator does not provide a 'throw' method")}return y}var o=f(n,t.iterator,e.arg);if("throw"===o.type)return e.method="throw",e.arg=o.arg,e.delegate=null,y;var i=o.arg;return i?i.done?(e[t.resultName]=i.value,e.next=t.nextLoc,"return"!==e.method&&(e.method="next",e.arg=r),e.delegate=null,y):i:(e.method="throw",e.arg=new TypeError("iterator result is not an object"),e.delegate=null,y)}function O(t){var r={tryLoc:t[0]};1 in t&&(r.catchLoc=t[1]),2 in t&&(r.finallyLoc=t[2],r.afterLoc=t[3]),this.tryEntries.push(r)}function j(t){var r=t.completion||{};r.type="normal",delete r.arg,t.completion=r}function P(t){this.tryEntries=[{tryLoc:"root"}],t.forEach(O,this),this.reset(!0)}function S(t){if(t){var e=t[i];if(e)return e.call(t);if("function"==typeof t.next)return t;if(!isNaN(t.length)){var o=-1,a=function e(){for(;++o=0;--i){var a=this.tryEntries[i],u=a.completion;if("root"===a.tryLoc)return o("end");if(a.tryLoc<=this.prev){var c=n.call(a,"catchLoc"),f=n.call(a,"finallyLoc");if(c&&f){if(this.prev=0;--e){var o=this.tryEntries[e];if(o.tryLoc<=this.prev&&n.call(o,"finallyLoc")&&this.prev=0;--r){var e=this.tryEntries[r];if(e.finallyLoc===t)return this.complete(e.completion,e.afterLoc),j(e),y}},catch:function(t){for(var r=this.tryEntries.length-1;r>=0;--r){var e=this.tryEntries[r];if(e.tryLoc===t){var n=e.completion;if("throw"===n.type){var o=n.arg;j(e)}return o}}throw new Error("illegal catch attempt")},delegateYield:function(t,e,n){return this.delegate={iterator:S(t),resultName:e,nextLoc:n},"next"===this.method&&(this.arg=r),y}},t}(t.exports);try{regeneratorRuntime=n}catch(t){Function("r","regeneratorRuntime = r")(n)}}]));
================================================
FILE: lambdas/src/hello.ts
================================================
import { ALBHandler } from 'aws-lambda';
import querystring from 'querystring';
export const handler: ALBHandler = async (event, context) => {
switch (event.httpMethod) {
case 'GET': {
return {
statusCode: 200,
body: `Hello, World!`,
};
}
case 'POST': {
const params = querystring.parse(event.body!);
const name = params.name || 'World!';
return {
statusCode: 200,
body: `Hello, ${name}`,
};
}
default:
return { statusCode: 405, body: 'Method Not Allowed' };
}
};
================================================
FILE: netlify.toml
================================================
[build]
functions = "lambdas/build" # netlify-lambda reads this for local dev server
================================================
FILE: package.json
================================================
{
"name": "react-redux-typescript-realworld-app",
"description": "RealWorld App implementation based on \"react-redux-typescript-guide\"",
"version": "0.1.0",
"private": true,
"author": "Piotr Witek (http://piotrwitek.github.io/)",
"repository": "https://github.com/piotrwitek/react-redux-typescript-realworld-app.git",
"homepage": "https://react-redux-typescript-realworld-app.netlify.com/",
"license": "MIT",
"main": "src/index.tsx",
"scripts": {
"start:client": "react-scripts start",
"start:lambdas": "netlify-lambda serve lambdas/src",
"start": "concurrently 'npm run start:client' 'npm run start:lambdas'",
"build:client": "react-scripts build",
"build:lambdas": "netlify-lambda build lambdas/src",
"build": "concurrently 'npm run build:client' 'npm run build:lambdas'",
"test": "react-scripts test",
"eject": "react-scripts eject",
"reinstall": "rm -rf ./node_modules && npm install",
"ci-check": "npm run prettier && npm run tsc && npm run test",
"prettier": "prettier --list-different 'src/**/*.ts' || (echo '\nPlease run the following command to fix:\nnpm run prettier:fix\n'; exit 1)",
"prettier:fix": "prettier --write 'src/**/*.ts'",
"tsc": "tsc -p ./ --noEmit",
"tsc:watch": "tsc -p ./ --noEmit -w",
"deploy": "openode deploy"
},
"dependencies": {
"@babel/polyfill": "7.4.3",
"@emotion/core": "10.0.10",
"@emotion/styled": "10.0.10",
"@types/aws-lambda": "8.10.24",
"@types/jest": "24.0.11",
"@types/node": "11.13.7",
"@types/prop-types": "15.7.1",
"@types/react": "16.8.14",
"@types/react-dom": "16.8.4",
"@types/react-redux": "7.0.8",
"@types/react-router-dom": "4.3.2",
"axios": "0.18.0",
"connected-react-router": "6.4.0",
"cuid": "2.1.6",
"fast-deep-equal": "2.0.1",
"formik": "1.5.2",
"netlify-lambda": "1.4.5",
"prettier": "1.17.0",
"prop-types": "15.7.2",
"react": "16.8.6",
"react-dom": "16.8.6",
"react-redux": "7.0.2",
"react-redux-typescript-scripts": "1.5.0",
"react-router-dom": "5.0.0",
"react-scripts": "3.0.0",
"react-testing-library": "6.1.2",
"react-toastify": "5.1.0",
"redux": "4.0.1",
"redux-observable": "1.1.0",
"reselect": "4.0.0",
"rxjs": "6.5.1",
"tslib": "1.9.3",
"typesafe-actions": "4.1.2",
"typescript": "3.4.5",
"utility-types": "3.5.0",
"yup": "0.27.0"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"@types/yup": "0.26.12",
"concurrently": "4.1.0"
}
}
================================================
FILE: public/index.html
================================================
React App
================================================
FILE: public/manifest.json
================================================
{
"short_name": "React App",
"name": "Create React App Sample",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}
================================================
FILE: server/package.json
================================================
{
"name": "server",
"version": "0.1.0",
"private": true,
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "...",
"build": "...",
"deploy": "openode deploy"
},
"author": "Piotrek Witek",
"license": "MIT",
"devDependencies": {
"openode": "2.0.3",
"react-redux-typescript-scripts": "1.5.0",
"typescript": "3.4.5"
},
"dependencies": {}
}
================================================
FILE: server/src/env.ts
================================================
export const DB_HOST = process.env.DB_HOST;
================================================
FILE: server/tsconfig.json
================================================
{
"include": ["src", "typings"],
"exclude": ["src/**/*.spec.*"],
"extends": "./node_modules/react-redux-typescript-scripts/tsconfig.json",
"compilerOptions": {}
}
================================================
FILE: src/App.test.tsx
================================================
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
it('renders without crashing', () => {
const div = document.createElement('div');
ReactDOM.render(, div);
ReactDOM.unmountComponentAtNode(div);
});
================================================
FILE: src/App.tsx
================================================
import React, { Component } from 'react';
import { Provider } from 'react-redux';
import { ConnectedRouter } from 'connected-react-router';
import { Switch, Route } from 'react-router';
import store, { history } from './store';
import Home from './routes/Home';
import { getPath } from './router-paths';
import AddArticle from './routes/AddArticle';
import EditArticle from './routes/EditArticle';
import ViewArticle from './routes/ViewArticle';
class App extends Component {
render() {
return (
}
/>
}
/>