diff --git a/.babelrc b/.babelrc index 50e1714e..79250058 100644 --- a/.babelrc +++ b/.babelrc @@ -2,7 +2,6 @@ "presets": ["react-app-tools/config/babel"], "plugins": [ ["babel-plugin-lodash", { "id": ["lodash", "recompose"] }], - "babel-plugin-relay", - "babel-plugin-styled-components" + "babel-plugin-relay" ] } diff --git a/.circleci/config.yml b/.circleci/config.yml index 7af16540..312cc588 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -6,7 +6,7 @@ version: 2 jobs: build: docker: - - image: kriasoft/node:10.1.0 + - image: circleci/node:carbon steps: - checkout - restore_cache: diff --git a/.env b/.env index f8e5fdde..2faa17be 100644 --- a/.env +++ b/.env @@ -1,15 +1,17 @@ -# Firebase +# Google Cloud & Firebase +# https://console.cloud.google.com/apis/credentials # https://console.firebase.google.com/project/_/settings/general/ # https://console.firebase.google.com/project/_/settings/serviceaccounts/adminsdk -FIREBASE_PROJECT_ID=react-firebase-graphql +GCP_PROJECT=react-firebase-graphql +GCP_BROWSER_KEY=AIzaSyAsuqpqt29-TIwBAu01Nbt5QnC3FIKO4A4 +GCP_SERVER_KEY=AIzaSyAsuqpqt29-TIwBAu01Nbt5QnC3FIKO4A4 +# GCP_SERVICE_KEY={"type":"service_account","project_id":"react-firebase-graphql","private_key_id":"...","private_key":"...","client_email":"...","client_id":"...","auth_uri":"https://accounts.google.com/o/oauth2/auth","token_uri":"https://accounts.google.com/o/oauth2/token","auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs","client_x509_cert_url":"..."} FIREBASE_AUTH_DOMAIN=firebase.reactstarter.com -FIREBASE_API_BROWSER_KEY=AIzaSyAsuqpqt29-TIwBAu01Nbt5QnC3FIKO4A4 -FIREBASE_API_SERVER_KEY=AIzaSyAsuqpqt29-TIwBAu01Nbt5QnC3FIKO4A4 -FIREBASE_SERVICE_KEY={"type":"service_account","project_id":"react-firebase-graphql","private_key_id":"...","private_key":"...","client_email":"...","client_id":"...","auth_uri":"https://accounts.google.com/o/oauth2/auth","token_uri":"https://accounts.google.com/o/oauth2/token","auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs","client_x509_cert_url":"..."} # Authentication +JWT_NAME=__session_rsk JWT_SECRET=xxxxx GOOGLE_CLIENT_ID=xxxxx @@ -25,8 +27,9 @@ PGHOST=localhost PGUSER=postgres PGDATABASE=app PGPASSWORD= -PGPORT=5432 +PGAPPNAME=rsk # PGSSLMODE=require # PGSSLCERT=./ssl/client-cert.pem # PGSSLKEY=./ssl/client-key.pem # PGSSLROOTCERT=./ssl/server-ca.pem +# PGDEBUG=true diff --git a/.env.production b/.env.production new file mode 100644 index 00000000..f4876a5c --- /dev/null +++ b/.env.production @@ -0,0 +1,30 @@ +# Google Cloud & Firebase +# https://console.cloud.google.com/apis/credentials +# https://console.firebase.google.com/project/_/settings/general/ +# https://console.firebase.google.com/project/_/settings/serviceaccounts/adminsdk + +GCP_PROJECT=react-firebase-graphql +GCP_BROWSER_KEY=AIzaSyAsuqpqt29-TIwBAu01Nbt5QnC3FIKO4A4 +GCP_SERVER_KEY=AIzaSyAsuqpqt29-TIwBAu01Nbt5QnC3FIKO4A4 +# GCP_SERVICE_KEY={"type":"service_account","project_id":"react-firebase-graphql","private_key_id":"...","private_key":"...","client_email":"...","client_id":"...","auth_uri":"https://accounts.google.com/o/oauth2/auth","token_uri":"https://accounts.google.com/o/oauth2/token","auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs","client_x509_cert_url":"..."} +FIREBASE_AUTH_DOMAIN=firebase.reactstarter.com + +# Authentication + +JWT_NAME=__session +JWT_SECRET=xxxxx + +GOOGLE_CLIENT_ID=xxxxx +GOOGLE_CLIENT_SECRET=xxxxx + +FACEBOOK_APP_ID=xxxxx +FACEBOOK_APP_SECRET=xxxxx + +# PostgreSQL +# https://www.postgresql.org/docs/current/static/libpq-envars.html + +PGHOST=/cloudbuild/:: +PGUSER= +PGDATABASE= +PGPASSWORD= +PGAPPNAME=rsk diff --git a/.firebaserc b/.firebaserc index 3c6d22b1..c55a7598 100644 --- a/.firebaserc +++ b/.firebaserc @@ -1,6 +1,5 @@ { "projects": { - "prod": "react-firebase-graphql", - "dev": "react-firebase-dev" + "default": "react-firebase-graphql" } } diff --git a/.stylelintignore b/.stylelintignore deleted file mode 100644 index a119c5cd..00000000 --- a/.stylelintignore +++ /dev/null @@ -1,3 +0,0 @@ -**/mutations/** -__generated__ -src/server diff --git a/README.md b/README.md index 03f9e4fc..113d8daf 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,6 @@ This project was bootstraped with [React Starter Kit for Firebase][rfs] by [Kria - [Create React App][cra] (★ 55k) for development and test infrastructure (see [user guide][cradocs]) - [Material UI][mui] (★ 40k) to reduce development time by integrating Google's [Material Design][material] -- [Styled Components][sc] (★ 18k) for component friendly CSS styles with a great DX ([docs][scdocs]) - [Passport.js][passport] (★ 14k) for authentication configured with stateless JWT tokens for sessions - [GraphQL.js][gqljs] (★ 11k) and [Relay][relay] (★ 11k) for declarative data fetching and efficient client stage management - [Universal Router][router] (★ 1k) + [history][history] (★ 3k) for declarative routing and client-side navigation optimized for [Relay][relay] @@ -131,18 +130,11 @@ $ yarn test # Run unit tests. Or, `yarn test -- --watch` ### How to Deploy 1. Create a new **Google Cloud** project and **Cloud SQL** database. -2. Open your Google Cloud project in **Firebase** dashboard and configure Facebook authentication. -3. Update Firebase project IDs for production and development environments in `.firebaserc` file. -4. Save Firebase API key, authentication domain and GPC service key in Firebase Functions - environment. For example `firebase functions:config:set api.browserkey="..." auth.domain="..."` -5. Update database host/user/password in either `.env` or `.env.local` file and migrate your - Cloud SQL database schema to the latest version by running `yarn db-migrate`. -6. Finally, deploy your application by running: - -```bash -$ yarn deploy # Build the app and deploy to development environment -$ yarn deploy-prod # Build the app and deploy to production -``` +2. Configure authentication in **Firebase** dashboard. +3. Set Firebase project ID in `.firebaserc` file. +4. Set API keys, secrets and other settings in `.env.production` file. +5. Migrate the database by running `NODE_ENV=production yarn db-migrate`. +6. Finally, deploy your application by running `yarn deploy`. ### How to Update @@ -221,8 +213,6 @@ and [contributors](https://github.com/kriasoft/react-firebase-starter/graphs/con [fbdocs]: https://firebase.google.com/docs/web [router]: https://github.com/kriasoft/universal-router [history]: https://github.com/ReactTraining/history -[sc]: https://www.styled-components.com/ -[scdocs]: https://www.styled-components.com/docs [nodejs]: https://nodejs.org/ [yarn]: https://yarnpkg.com/ [brew]: https://brew.sh/ diff --git a/firebase.json b/firebase.json index c7f7f3b6..dba35b14 100644 --- a/firebase.json +++ b/firebase.json @@ -12,15 +12,22 @@ "scripts", "seeds", "src", - ".*", - "config-overrides.js", + ".babelrc", + ".editorconfig", + ".eslintrc", + ".firebserc", + ".flowconfig", + ".gitattributes", + ".gitignore", + ".prettierignore", + ".prettierrc", "knexfile.js", "LICENSE.txt", "README.md", "schema.graphql", "storage.rules", - "stylelint.config.js", - "*.log" + "yarn-debug.log*", + "yarn-error.log*" ] }, "hosting": { diff --git a/migrations/20180101000000_initial.js b/migrations/20180101000000_initial.js index df4c6da4..2e19161c 100644 --- a/migrations/20180101000000_initial.js +++ b/migrations/20180101000000_initial.js @@ -7,6 +7,9 @@ /* prettier-ignore */ exports.up = async db => { + await db.raw('CREATE EXTENSION IF NOT EXISTS "uuid-ossp"'); + await db.raw('CREATE EXTENSION IF NOT EXISTS "hstore"'); + await db.schema.createTable('users', table => { table.uuid('id').notNullable().defaultTo(db.raw('uuid_generate_v4()')).primary(); table.string('username', 50).unique(); diff --git a/package.json b/package.json index 3a611142..dc04cd12 100644 --- a/package.json +++ b/package.json @@ -23,18 +23,19 @@ "@babel/polyfill": "^7.0.0-beta.46", "@babel/runtime": "^7.0.0-beta.46", "@firebase/app": "^0.3.3", - "@material-ui/core": "^1.4.3", - "@material-ui/icons": "^2.0.1", + "@material-ui/core": "^3.0.2", + "@material-ui/icons": "^3.0.1", "body-parser": "^1.18.3", "classnames": "^2.2.6", "cookie": "^0.3.1", "cookie-parser": "^1.4.3", + "dotenv": "^6.0.0", "ejs": "^2.6.1", "express": "^4.16.3", "express-graphql": "^0.6.12", "firebase-admin": "^6.0.0", - "firebase-functions": "^2.0.4", - "graphql": "^0.13.2", + "firebase-functions": "^2.0.5", + "graphql": "^14.0.2", "graphql-relay": "^0.5.5", "history": "^4.7.2", "hoist-non-react-statics": "^3.0.1", @@ -50,52 +51,42 @@ "pg": "^7.4.3", "prop-types": "^15.6.2", "query-string": "^6.1.0", - "react": "^16.4.2", - "react-dom": "^16.4.2", - "react-relay": "^1.6.2", - "recompose": "^0.28.2", - "relay-runtime": "^1.6.2", + "react": "^16.5.0", + "react-dom": "^16.5.0", + "react-relay": "^1.7.0-rc.1", + "recompose": "^0.30.0", + "relay-runtime": "^1.7.0-rc.1", "request": "^2.88.0", "request-promise-native": "^1.0.5", "serialize-javascript": "^1.5.0", "slug": "^0.9.1", - "styled-components": "^3.4.2", "universal-router": "^6.0.0", "uuid": "^3.3.2", - "validator": "^10.5.0" + "validator": "^10.7.1" }, "devDependencies": { "@babel/core": "^7.0.0-beta.46", "@babel/preset-flow": "^7.0.0-beta.46", "@babel/register": "^7.0.0-beta.46", "babel-plugin-lodash": "^3.3.4", - "babel-plugin-relay": "^1.6.2", - "babel-plugin-styled-components": "^1.5.1", + "babel-plugin-relay": "^1.7.0-rc.1", "chai": "^4.1.2", - "dotenv": "^6.0.0", - "eslint-config-prettier": "^2.9.0", + "eslint-config-prettier": "^3.0.1", "eslint-plugin-flowtype": "^2.50.0", "eslint-plugin-prettier": "^2.6.2", - "flow-bin": "^0.78.0", - "husky": "^0.15.0-rc.13", - "lint-staged": "^7.2.0", + "flow-bin": "^0.80.0", + "husky": "^1.0.0-rc.13", + "lint-staged": "^7.2.2", "minimist": "^1.2.0", "prettier": "^1.14.2", "raw-loader": "^1.0.0-beta.0", - "react-app-tools": "^3.0.4", - "relay-compiler": "^1.6.2", - "stylelint": "^9.4.0", - "stylelint-config-primer": "^2.2.10", - "stylelint-config-standard": "^18.2.0", - "stylelint-config-styled-components-processor": "^0.1.1", - "stylelint-order": "^1.0.0", - "stylelint-processor-styled-components": "^1.3.2" + "react-app-tools": "^3.0.6", + "relay-compiler": "^1.7.0-rc.1" }, "lint-staged": { "*.js": [ "yarn run eslint --no-ignore --fix --max-warnings=0", "yarn run prettier --write", - "yarn run stylelint", "git add --force" ], "*.json": [ @@ -110,13 +101,13 @@ }, "scripts": { "update-schema": "node ./scripts/update-schema", - "relay": "relay-compiler --src ./src --schema ./schema.graphql --include \"**/*.js\"", + "relay": "relay-compiler --src ./src --schema ./schema.graphql", "setup": "node ./scripts/setup", "prestart": "yarn relay", "start": "react-app start", "build": "react-app build", "test": "react-app test --env=jsdom", - "lint": "eslint --ignore-path .gitignore --ignore-pattern \"!**/.*\" . && stylelint \"src/**/*.js\"", + "lint": "eslint --ignore-path .gitignore --ignore-pattern \"!**/.*\" .", "lint-fix": "eslint --ignore-path .gitignore --ignore-pattern \"!**/.*\" --fix . && yarn run prettier --write \"**/*.{js,json}\"", "db": "node ./scripts/db", "db-save": "node ./scripts/db-save", diff --git a/src/common/Layout.js b/src/common/Layout.js index d7f5f1e3..5d611f89 100644 --- a/src/common/Layout.js +++ b/src/common/Layout.js @@ -8,7 +8,6 @@ import React from 'react'; import PropTypes from 'prop-types'; -import styled, { injectGlobal } from 'styled-components'; import Avatar from '@material-ui/core/Avatar'; import Paper from '@material-ui/core/Paper'; import Button from '@material-ui/core/Button'; @@ -16,7 +15,9 @@ import Tab from '@material-ui/core/Tab'; import Tabs from '@material-ui/core/Tabs'; import Menu from '@material-ui/core/Menu'; import MenuItem from '@material-ui/core/MenuItem'; +import { withStyles } from '@material-ui/core/styles'; import { graphql, createFragmentContainer } from 'react-relay'; +import { compose } from 'recompose'; import Link from './Link'; import LayoutHeader from './LayoutHeader'; @@ -24,70 +25,56 @@ import LayoutFooter from './LayoutFooter'; import AutoUpdater from './AutoUpdater'; import withAuth from '../common/withAuth'; -injectGlobal` - html, - body, - #root { - height: 100%; - } - - body { - padding: 0; - margin: 0; - font-family: sans-serif; - } -`; - -const Container = styled.div` - height: 100vh; - background: #f9f9f9; -`; - -const Body = styled(Paper)` - max-width: 640px; - margin-top: -48px; - margin-right: auto; - margin-left: auto; - - && { - background: transparent; - } -`; - -const Content = styled.div` - padding: 1em; - background: #fff; -`; - -const StyledTabs = styled(Tabs)` - background: rgba(255, 255, 255, 0.9); -`; - -const StyledTab = styled(Tab)` - && { - min-width: inherit; - } -`; - -const Separator = styled.span` - flex-grow: 1; -`; - -const UserPhoto = styled(Avatar)` - && { - width: 32px; - height: 32px; - margin: 8px 10px; - cursor: pointer; - } -`; - -const SignInButton = styled(Button)` - && { - text-transform: none; - border-radius: 0; - } -`; +const styles = theme => ({ + '@global': { + 'html, body, #root': { + height: '100%', + }, + body: { + padding: 0, + margin: 0, + fontFamily: 'sans-serif', + }, + }, + container: { + height: '100vh', + background: '#f9f9f9', + }, + body: { + maxWidth: 640, + marginTop: -48, + marginRight: 'auto', + marginLeft: 'auto', + '&&': { + background: 'transparent', + }, + }, + toolbar: { + display: 'flex', + background: 'rgba(255, 255, 255, 0.9)', + }, + content: { + padding: theme.spacing.unit * 2, + background: theme.palette.common.white, + }, + tab: { + minWidth: 'inherit', + }, + separator: { + flexGrow: 1, + }, + + avatar: { + width: 32, + height: 32, + margin: '8px 10px', + cursor: 'pointer', + }, + login: { + textTransform: 'none', + borderRadius: 0, + }, +}); class Layout extends React.Component { static contextTypes = { @@ -113,6 +100,7 @@ class Layout extends React.Component { render() { const { + classes: s, data: { me }, } = this.props; @@ -135,17 +123,30 @@ class Layout extends React.Component { } return ( - +
- - - - - - + +
+ + + + + + {me ? ( <> - ) : ( - Sign In + )} - - {this.props.children} - +
+
{this.props.children}
+
- +
); } } -export default withAuth()( +export default compose( + withAuth(), + withStyles(styles, { withTheme: true }), +)( createFragmentContainer( Layout, graphql` diff --git a/src/common/LayoutFooter.js b/src/common/LayoutFooter.js index 68cf4aff..39d1d889 100644 --- a/src/common/LayoutFooter.js +++ b/src/common/LayoutFooter.js @@ -7,73 +7,58 @@ /* @flow */ import React from 'react'; -import styled from 'styled-components'; import Typography from '@material-ui/core/Typography'; +import { withStyles } from '@material-ui/core/styles'; import Link from './Link'; -const Container = styled.div` - max-width: 640px; - margin: 0 auto; - color: rgba(0, 0, 0, 0.4); -`; - -const Text = styled(Typography)` - padding: 1em; -`; - -const Copyright = styled.span` - padding-right: 0.5em; -`; - -const Separator = styled.span` - padding-right: 0.5em; - padding-left: 0.5em; -`; - -const ExtLink = styled.a` - &, - &:hover, - &:active, - &:visited { - color: rgba(0, 0, 0, 0.6); - text-decoration: none; - } - - &:hover { - text-decoration: underline; - } -`; - -const StyledLink = styled(Link)` - &, - &:hover, - &:active, - &:visited { - color: rgba(0, 0, 0, 0.6); - text-decoration: none; - } - - &:hover { - text-decoration: underline; - } -`; +const styles = theme => ({ + container: { + maxWidth: 640, + margin: '0 auto', + color: 'rgba(0, 0, 0, 0.4)', + }, + text: { + padding: '1em', + }, + copyright: { + paddingRight: '0.5em', + }, + separator: { + paddingRight: '0.5em', + paddingLeft: '0.5em', + }, + link: { + color: 'rgba(0, 0, 0, 0.6)', + textDecoration: 'none', + '&:hover': { + textDocoration: 'underline', + }, + }, +}); class LayoutFooter extends React.Component<{}> { render() { + const { classes: s } = this.props; return ( - - - © 2015-present - Kriasoft - | - About Us - | - Privacy - - +
+ + © 2015-present + + Kriasoft + + | + + About Us + + | + + Privacy + + +
); } } -export default LayoutFooter; +export default withStyles(styles)(LayoutFooter); diff --git a/src/common/LayoutHeader.js b/src/common/LayoutHeader.js index 779f5c37..c7f23304 100644 --- a/src/common/LayoutHeader.js +++ b/src/common/LayoutHeader.js @@ -7,61 +7,62 @@ /* @flow */ import React from 'react'; -import styled from 'styled-components'; +import { withStyles } from '@material-ui/core/styles'; -const Root = styled.div` - width: 100%; - padding: 2em 0 5em; - background-color: #3f51b5; - background-image: linear-gradient(-225deg, #3db0ef, #5e5bb7); - flex-shrink: 0; -`; - -const Container = styled.div` - max-width: 640px; - margin: 0 auto; -`; - -const Title = styled.h1` - padding: 0; - margin: 0 1rem 0.5em; - font-family: 'Roboto Mono', Roboto, Arial, sans-serif; - font-size: 2em; - font-weight: 100; - color: #fff; -`; - -const Summary = styled.p` - padding: 0; - margin: 0 1rem; - font-family: Roboto, Arial, sans-serif; - font-size: 1em; - font-weight: 100; - line-height: 1.5em; - color: #fff; - letter-spacing: 1px; - - && strong { - font-weight: 300; - } -`; +const styles = { + root: { + width: '100%', + padding: '2em 0 5em', + backgroundColor: '#3f51b5', + backgroundImage: 'linear-gradient(-225deg, #3db0ef, #5e5bb7)', + flexShrink: 0, + }, + container: { + maxWidth: 640, + margin: '0 auto', + }, + title: { + padding: 0, + margin: '0 1rem 0.5em', + fontFamily: "'Roboto Mono', Roboto, Arial, sans-serif", + fontSize: '2em', + fontWeight: 100, + color: '#fff', + }, + summary: { + padding: 0, + margin: '0 1rem', + fontFamily: 'Roboto, Arial, sans-serif', + fontSize: '1em', + fontWeight: 100, + lineHeight: '1.5em', + color: '#fff', + letterSpacing: 1, + '&& strong': { + fontWeight: 300, + }, + }, +}; class LayoutHeader extends React.Component { render() { + const { classes: s } = this.props; return ( - - - React Starter Kit - +
+
+

React Starter Kit

+

Bootstrap new React.js + Firebase{' '} - application projects
- in minutes, using modern mainstream libraries and tooling
+ application projects +
+ in minutes, using modern mainstream libraries and tooling +
with zero dependency on 3rd party frameworks. -

-
-
+

+ + ); } } -export default LayoutHeader; +export default withStyles(styles)(LayoutHeader); diff --git a/src/news/News.js b/src/news/News.js index acb35e5b..21f05b53 100644 --- a/src/news/News.js +++ b/src/news/News.js @@ -7,7 +7,6 @@ /* @flow */ import React from 'react'; -import styled from 'styled-components'; import Typography from '@material-ui/core/Typography'; import Avatar from '@material-ui/core/Avatar'; import Snakbar from '@material-ui/core/Snackbar'; @@ -19,58 +18,49 @@ import ChatBubbleOutlineIcon from '@material-ui/icons/ChatBubbleOutline'; import FavoriteIcon from '@material-ui/icons/Favorite'; import FavoriteBorderIcon from '@material-ui/icons/FavoriteBorder'; import OpenInNewIcon from '@material-ui/icons/OpenInNew'; +import { withStyles } from '@material-ui/core/styles'; import { graphql, createFragmentContainer } from 'react-relay'; import Link from '../common/Link'; import withAuth from '../common/withAuth'; import LikeStoryMutation from './mutations/LikeStory'; -const StyledListItem = styled(ListItem)` - && { - padding-right: 0; - padding-left: 0; - } -`; - -const StyledListItemText = styled(ListItemText)` - && { - padding-right: 0; - } - - && a { - color: rgba(0, 0, 0, 0.8); - text-decoration: none; - } - - && > p > a { - padding-left: 1em; - color: rgba(0, 0, 0, 0.54); - } - - && a:hover { - text-decoration: underline; - } - - && > p > a:hover { - color: rgba(0, 0, 0, 0.8); - text-decoration: none; - } - - && > p { - display: flex; - } - - && > p > span:first-child { - flex-grow: 1; - } - - && > p svg { - width: 18px; - height: 18px; - margin-right: 4px; - vertical-align: bottom; - } -`; +const styles = theme => ({ + listItem: { + paddingRight: 0, + paddingLeft: 0, + }, + listItemText: { + paddingRight: 0, + '&& a': { + color: 'rgba(0, 0, 0, 0.8)', + textDecoration: 'none', + }, + '&& > p > a': { + paddingLeft: '1em', + textDecoration: 'none', + }, + '&& a:hover': { + textDecoration: 'underline', + }, + '&& > p > a:hover': { + color: 'rgba(0, 0, 0, 0.8)', + textDecoration: 'none', + }, + '&& > p': { + display: 'flex', + }, + '&& > p > span:first-child': { + flexGrow: 1, + }, + '&& > p svg': { + width: 18, + height: 18, + marginRight: 4, + verticalAlign: 'bottom', + }, + }, +}); class News extends React.Component<{}> { state = { error: null }; @@ -93,6 +83,7 @@ class News extends React.Component<{}> { render() { const { + classes: s, data: { stories }, } = this.props; const { error } = this.state; @@ -103,11 +94,16 @@ class News extends React.Component<{}> { {(stories || []).map(x => ( - + - @@ -139,7 +135,7 @@ class News extends React.Component<{}> { } /> - + ))} @@ -148,27 +144,29 @@ class News extends React.Component<{}> { } } -export default withAuth()( - createFragmentContainer( - News, - graphql` - fragment News on Query { - stories { - id - slug - title - text - isURL - createdAt(format: "MMM Do, YYYY") - author { - username - displayName - photoURL +export default withStyles(styles)( + withAuth()( + createFragmentContainer( + News, + graphql` + fragment News on Query { + stories { + id + slug + title + text + isURL + createdAt(format: "MMM Do, YYYY") + author { + username + displayName + photoURL + } + pointsCount + pointGiven } - pointsCount - pointGiven } - } - `, + `, + ), ), ); diff --git a/src/news/Submit.js b/src/news/Submit.js index d43727ce..3472a728 100644 --- a/src/news/Submit.js +++ b/src/news/Submit.js @@ -9,7 +9,6 @@ import idx from 'idx'; import React from 'react'; import PropTypes from 'prop-types'; -import styled from 'styled-components'; import RelayPropTypes from 'react-relay/lib/RelayPropTypes'; import Typography from '@material-ui/core/Typography'; import Button from '@material-ui/core/Button'; @@ -17,16 +16,18 @@ import Input from '@material-ui/core/Input'; import InputLabel from '@material-ui/core/InputLabel'; import FormControl from '@material-ui/core/FormControl'; import FormHelperText from '@material-ui/core/FormHelperText'; +import { withStyles } from '@material-ui/core/styles'; import { graphql, createFragmentContainer } from 'react-relay'; +import { compose } from 'recompose'; import withAuth from '../common/withAuth'; import CreateStoryMutation from './mutations/CreateStory'; -const StyledFormControl = styled(FormControl)` - && { - margin-top: 1em; - } -`; +const styles = { + control: { + marginTop: '1em', + }, +}; class Submit extends React.Component<{}> { static contextTypes = { @@ -83,6 +84,7 @@ class Submit extends React.Component<{}> { } = this.context; const { + classes: s, data: { me }, } = this.props; @@ -92,7 +94,8 @@ class Submit extends React.Component<{}> { Do you have something cool to share?
- x.error.state['title'])} aria-describedby="title-text" @@ -106,8 +109,9 @@ class Submit extends React.Component<{}> { required /> {this.errorMessage('title')} - - + x.error.state['text'])} aria-describedby="text-text" @@ -123,8 +127,8 @@ class Submit extends React.Component<{}> { required /> {this.errorMessage('text')} - - + +