diff --git a/Dockerfile b/Dockerfile
index c92722f..86bfa76 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,30 +1,12 @@
-FROM node:7.2.1-alpine
+FROM node:8.4.0-alpine
-# Need cURL to report to Rollbar
-RUN apk --no-cache add curl git
+COPY ./ /usr/src
+WORKDIR /usr/src
-# Copy app
-COPY ./ /usr/src/app
-WORKDIR /usr/src/app
+RUN npm install --silent
-# Install dev + prod dependencies and build release
-RUN npm install --no-optional --silent
-
-# Environment variables
-ENV DATABASE_PATH db/wedding.db
ENV NODE_ENV production
ENV PORT 80
EXPOSE 80
-# Run production build
-RUN npm run build -- --release --silent
-
-RUN curl https://api.rollbar.com/api/1/deploy/ \
- -F access_token=8bf333d044df48c19a6929e4b1613a8e \
- -F environment=production \
- -F revision=$(git log -n 1 --pretty=format:"%H") \
- -F local_username="$(git log -n 1 --pretty=format:"%an")"
-
-WORKDIR /usr/src/app/build
-
CMD [ "node", "server.js" ]
diff --git a/README.md b/README.md
index a08bc75..5b49c0d 100644
--- a/README.md
+++ b/README.md
@@ -1,112 +1 @@
-# Wedding RSVP site
-Forked from [React Starter Kit](https://www.reactstarterkit.com)
-development built on top of [Node.js](https://nodejs.org/),
-[Express](http://expressjs.com/), [GraphQL](http://graphql.org/) and
-[React](https://facebook.github.io/react/), containing modern web development
-tools such as [Webpack](http://webpack.github.io/), [Babel](http://babeljs.io/)
-and [Browsersync](http://www.browsersync.io/). Helping you to stay productive
-following the best practices. A solid starting point for both professionals
-and newcomers to the industry.
-
-## Getting Started
-
-### Requirements
-
- * Mac OS X, Windows, or Linux
- * [Yarn](https://yarnpkg.com/) package + [Node.js](https://nodejs.org/) v6.5 or newer
- * `node-gyp` prerequisites mentioned [here](https://github.com/nodejs/node-gyp)
- * Text editor or IDE pre-configured with React/JSX/Flow/ESlint ([learn more](./how-to-configure-text-editors.md))
-
-### Quick Start
-
-#### 1. Run `yarn install`
-
-This will install both run-time project dependencies and developer tools listed
-in [package.json](../package.json) file.
-
-#### 2. Run `yarn start`
-
-This command will build the app from the source files (`/src`) into the output
-`/build` folder. As soon as the initial build completes, it will start the
-Node.js server (`node build/server.js`) and [Browsersync](https://browsersync.io/)
-with [HMR](https://webpack.github.io/docs/hot-module-replacement) on top of it.
-
-> [http://localhost:3000/](http://localhost:3000/) — Node.js server (`build/server.js`)
-> [http://localhost:3000/graphql](http://localhost:3000/graphql) — GraphQL server and IDE
-> [http://localhost:3001/](http://localhost:3001/) — BrowserSync proxy with HMR, React Hot Transform
-> [http://localhost:3002/](http://localhost:3002/) — BrowserSync control panel (UI)
-
-Now you can open your web app in a browser, on mobile devices and start
-hacking. Whenever you modify any of the source files inside the `/src` folder,
-the module bundler ([Webpack](http://webpack.github.io/)) will recompile the
-app on the fly and refresh all the connected browsers.
-
-
-
-Note that the `yarn start` command launches the app in `development` mode,
-the compiled output files are not optimized and minimized in this case.
-You can use `--release` command line argument to check how your app works
-in release (production) mode:
-
-```shell
-$ yarn start -- --release
-```
-*NOTE: double dashes are required*
-
-
-### How to Build, Test, Deploy
-
-If you need just to build the app (without running a dev server), simply run:
-
-```shell
-$ yarn run build
-```
-
-or, for a production build:
-
-```shell
-$ yarn run build -- --release
-```
-
-or, for a production docker build:
-
-```shell
-$ yarn run build -- --release --docker
-```
-
-*NOTE: double dashes are required*
-
-After running this command, the `/build` folder will contain the compiled
-version of the app. For example, you can launch Node.js server normally by
-running `node build/server.js`.
-
-To check the source code for syntax errors and potential issues run:
-
-```shell
-$ yarn run lint
-```
-
-To launch unit tests:
-
-```shell
-$ yarn run test # Run unit tests with Mocha
-$ yarn run test:watch # Launch unit test runner and start watching for changes
-```
-
-By default, [Mocha](https://mochajs.org/) test runner is looking for test files
-matching the `src/**/*.test.js` pattern. Take a look at `src/components/Layout/Layout.test.js`
-as an example.
-
-To deploy the app, run:
-
-```shell
-$ yarn run deploy
-```
-
-The deployment script `tools/deploy.js` is configured to push the contents of
-the `/build` folder to a remote server via Git. You can easily deploy your app
-to [Azure Web Apps](https://azure.microsoft.com/en-us/services/app-service/web/),
-or [Heroku](https://www.heroku.com/) this way. Both will execute `yarn install --production`
-upon receiving new files from you. Note, you should only deploy the contents
-of the `/build` folder to a remote server.
-
+Interstitial site before 2.0
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 0000000..1911be3
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,305 @@
+{
+ "name": "wedding",
+ "version": "1.5.0",
+ "lockfileVersion": 1,
+ "requires": true,
+ "dependencies": {
+ "accepts": {
+ "version": "1.3.4",
+ "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.4.tgz",
+ "integrity": "sha1-hiRnWMfdbSGmR0/whKR0DsBesh8=",
+ "requires": {
+ "mime-types": "2.1.17",
+ "negotiator": "0.6.1"
+ }
+ },
+ "array-flatten": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
+ "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
+ },
+ "content-disposition": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz",
+ "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ="
+ },
+ "content-type": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
+ "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA=="
+ },
+ "cookie": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz",
+ "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s="
+ },
+ "cookie-signature": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
+ "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
+ },
+ "debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "depd": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz",
+ "integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k="
+ },
+ "destroy": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
+ "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
+ },
+ "ee-first": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+ "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
+ },
+ "encodeurl": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.1.tgz",
+ "integrity": "sha1-eePVhlU0aQn+bw9Fpd5oEDspTSA="
+ },
+ "escape-html": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+ "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
+ },
+ "etag": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
+ "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc="
+ },
+ "express": {
+ "version": "4.15.5",
+ "resolved": "https://registry.npmjs.org/express/-/express-4.15.5.tgz",
+ "integrity": "sha1-ZwI1ypWYiQpa6BcLg9tyK4Qu2Sc=",
+ "requires": {
+ "accepts": "1.3.4",
+ "array-flatten": "1.1.1",
+ "content-disposition": "0.5.2",
+ "content-type": "1.0.4",
+ "cookie": "0.3.1",
+ "cookie-signature": "1.0.6",
+ "debug": "2.6.9",
+ "depd": "1.1.1",
+ "encodeurl": "1.0.1",
+ "escape-html": "1.0.3",
+ "etag": "1.8.1",
+ "finalhandler": "1.0.6",
+ "fresh": "0.5.2",
+ "merge-descriptors": "1.0.1",
+ "methods": "1.1.2",
+ "on-finished": "2.3.0",
+ "parseurl": "1.3.2",
+ "path-to-regexp": "0.1.7",
+ "proxy-addr": "1.1.5",
+ "qs": "6.5.0",
+ "range-parser": "1.2.0",
+ "send": "0.15.6",
+ "serve-static": "1.12.6",
+ "setprototypeof": "1.0.3",
+ "statuses": "1.3.1",
+ "type-is": "1.6.15",
+ "utils-merge": "1.0.0",
+ "vary": "1.1.2"
+ }
+ },
+ "finalhandler": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.0.6.tgz",
+ "integrity": "sha1-AHrqM9Gk0+QgF/YkhIrVjSEvgU8=",
+ "requires": {
+ "debug": "2.6.9",
+ "encodeurl": "1.0.1",
+ "escape-html": "1.0.3",
+ "on-finished": "2.3.0",
+ "parseurl": "1.3.2",
+ "statuses": "1.3.1",
+ "unpipe": "1.0.0"
+ }
+ },
+ "forwarded": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
+ "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ="
+ },
+ "fresh": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
+ "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
+ },
+ "http-errors": {
+ "version": "1.6.2",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz",
+ "integrity": "sha1-CgAsyFcHGSp+eUbO7cERVfYOxzY=",
+ "requires": {
+ "depd": "1.1.1",
+ "inherits": "2.0.3",
+ "setprototypeof": "1.0.3",
+ "statuses": "1.3.1"
+ }
+ },
+ "inherits": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+ "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
+ },
+ "ipaddr.js": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.4.0.tgz",
+ "integrity": "sha1-KWrKh4qCGBbluF0KKFqZvP9FgvA="
+ },
+ "media-typer": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
+ "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
+ },
+ "merge-descriptors": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
+ "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E="
+ },
+ "methods": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
+ "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4="
+ },
+ "mime": {
+ "version": "1.3.4",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-1.3.4.tgz",
+ "integrity": "sha1-EV+eO2s9rylZmDyzjxSaLUDrXVM="
+ },
+ "mime-db": {
+ "version": "1.30.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz",
+ "integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE="
+ },
+ "mime-types": {
+ "version": "2.1.17",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz",
+ "integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=",
+ "requires": {
+ "mime-db": "1.30.0"
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
+ },
+ "negotiator": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz",
+ "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk="
+ },
+ "on-finished": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
+ "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
+ "requires": {
+ "ee-first": "1.1.1"
+ }
+ },
+ "parseurl": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz",
+ "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M="
+ },
+ "path-to-regexp": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
+ "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
+ },
+ "proxy-addr": {
+ "version": "1.1.5",
+ "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-1.1.5.tgz",
+ "integrity": "sha1-ccDuOxAt4/IC87ZPYI0XP8uhqRg=",
+ "requires": {
+ "forwarded": "0.1.2",
+ "ipaddr.js": "1.4.0"
+ }
+ },
+ "qs": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.0.tgz",
+ "integrity": "sha512-fjVFjW9yhqMhVGwRExCXLhJKrLlkYSaxNWdyc9rmHlrVZbk35YHH312dFd7191uQeXkI3mKLZTIbSvIeFwFemg=="
+ },
+ "range-parser": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz",
+ "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4="
+ },
+ "send": {
+ "version": "0.15.6",
+ "resolved": "https://registry.npmjs.org/send/-/send-0.15.6.tgz",
+ "integrity": "sha1-IPI6nJJbdiq4JwX+L52yUqzkfjQ=",
+ "requires": {
+ "debug": "2.6.9",
+ "depd": "1.1.1",
+ "destroy": "1.0.4",
+ "encodeurl": "1.0.1",
+ "escape-html": "1.0.3",
+ "etag": "1.8.1",
+ "fresh": "0.5.2",
+ "http-errors": "1.6.2",
+ "mime": "1.3.4",
+ "ms": "2.0.0",
+ "on-finished": "2.3.0",
+ "range-parser": "1.2.0",
+ "statuses": "1.3.1"
+ }
+ },
+ "serve-static": {
+ "version": "1.12.6",
+ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.12.6.tgz",
+ "integrity": "sha1-uXN3P2NEmTTaVOW+ul4x2fQhFXc=",
+ "requires": {
+ "encodeurl": "1.0.1",
+ "escape-html": "1.0.3",
+ "parseurl": "1.3.2",
+ "send": "0.15.6"
+ }
+ },
+ "setprototypeof": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz",
+ "integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ="
+ },
+ "statuses": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz",
+ "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4="
+ },
+ "type-is": {
+ "version": "1.6.15",
+ "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.15.tgz",
+ "integrity": "sha1-yrEPtJCeRByChC6v4a1kbIGARBA=",
+ "requires": {
+ "media-typer": "0.3.0",
+ "mime-types": "2.1.17"
+ }
+ },
+ "unpipe": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+ "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
+ },
+ "utils-merge": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.0.tgz",
+ "integrity": "sha1-ApT7kiu5N1FTVBxPcJYjHyh8ivg="
+ },
+ "vary": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
+ "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
+ }
+ }
+}
diff --git a/package.json b/package.json
index 3ab8f38..6596de4 100644
--- a/package.json
+++ b/package.json
@@ -1,226 +1,15 @@
{
"name": "wedding",
- "version": "1.4.0",
+ "version": "1.5.0",
"private": true,
"engines": {
"node": ">=6.5",
"npm": ">=3.10"
},
"dependencies": {
- "babel-polyfill": "^6.20.0",
- "babel-runtime": "^6.20.0",
- "bluebird": "^3.4.6",
- "body-parser": "^1.15.2",
- "classnames": "^2.2.5",
- "cookie-parser": "^1.4.3",
- "core-js": "^2.4.1",
- "express": "^4.14.0",
- "express-bouncer": "^0.2.0",
- "express-graphql": "^0.6.1",
- "express-jwt": "^5.1.0",
- "fastclick": "^1.0.6",
- "fbjs": "^0.8.6",
- "graphql": "^0.8.2",
- "history": "^4.5.0",
- "isomorphic-style-loader": "^1.1.0",
- "jsonwebtoken": "^7.2.1",
- "node-fetch": "^1.6.3",
- "nodemailer": "^3.1.3",
- "normalize.css": "^5.0.0",
- "passport": "^0.3.2",
- "passport-facebook": "^2.1.1",
- "pretty-error": "^2.0.2",
- "query-string": "^4.2.3",
- "react": "^15.4.1",
- "react-dom": "^15.4.1",
- "react-google-maps": "6",
- "react-icon-base": "^2.0.4",
- "react-icons": "^2.2.3",
- "rollbar": "^0.6.3",
- "sequelize": "^3.28.0",
- "slack-node": "^0.1.8",
- "source-map-support": "^0.4.6",
- "sqlite3": "^3.1.8",
- "universal-router": "^2.0.0",
- "whatwg-fetch": "^2.0.1"
- },
- "devDependencies": {
- "assets-webpack-plugin": "^3.5.0",
- "autoprefixer": "^6.5.3",
- "babel-cli": "^6.18.0",
- "babel-core": "^6.18.2",
- "babel-eslint": "^7.1.1",
- "babel-loader": "^6.2.8",
- "babel-plugin-rewire": "^1.0.0",
- "babel-plugin-transform-runtime": "^6.15.0",
- "babel-preset-latest": "^6.16.0",
- "babel-preset-react": "^6.16.0",
- "babel-preset-react-optimize": "^1.0.1",
- "babel-preset-stage-0": "^6.16.0",
- "babel-register": "^6.18.0",
- "babel-template": "^6.16.0",
- "babel-types": "^6.19.0",
- "browser-sync": "^2.18.2",
- "chai": "^3.5.0",
- "chokidar": "^1.6.1",
- "css-loader": "^0.26.0",
- "editorconfig-tools": "^0.1.1",
- "enzyme": "^2.6.0",
- "extend": "^3.0.0",
- "file-loader": "^0.9.0",
- "front-matter": "^2.1.1",
- "git-repository": "^0.1.4",
- "glob": "^7.1.1",
- "json-loader": "^0.5.4",
- "lint-staged": "^3.2.2",
- "markdown-it": "^8.2.2",
- "mkdirp": "^0.5.1",
- "mocha": "^3.1.2",
- "pixrem": "^3.0.2",
- "pleeease-filters": "^3.0.0",
- "postcss": "^5.2.5",
- "postcss-calc": "^5.3.1",
- "postcss-color-function": "^2.0.1",
- "postcss-custom-media": "^5.0.1",
- "postcss-custom-properties": "^5.0.1",
- "postcss-custom-selectors": "^3.0.0",
- "postcss-flexbugs-fixes": "^2.0.0",
- "postcss-loader": "^1.1.1",
- "postcss-media-minmax": "^2.1.2",
- "postcss-nested": "^1.0.0",
- "postcss-nesting": "^2.3.1",
- "postcss-partial-import": "^2.1.0",
- "postcss-pseudoelements": "^3.0.0",
- "postcss-selector-matches": "^2.0.5",
- "postcss-selector-not": "^2.0.0",
- "postcss-url": "^5.1.2",
- "pre-commit": "^1.2.2",
- "raw-loader": "^0.5.1",
- "react-addons-test-utils": "15.4.1",
- "react-deep-force-update": "^2.0.1",
- "react-hot-loader": "^3.0.0-beta.6",
- "redbox-react": "^1.3.3",
- "rimraf": "^2.5.4",
- "sinon": "^2.0.0-pre.3",
- "stylefmt": "^5.0.2",
- "stylelint": "^7.6.0",
- "stylelint-config-standard": "^15.0.0",
- "url-loader": "^0.5.7",
- "webpack": "^1.13.3",
- "webpack-hot-middleware": "^2.13.2",
- "webpack-middleware": "^1.5.1"
- },
- "optionalDependencies": {
- "eslint": "^3.10.2",
- "eslint-config-airbnb": "^13.0.0",
- "eslint-loader": "^1.6.1",
- "eslint-plugin-css-modules": "^1.0.9",
- "eslint-plugin-import": "^2.2.0",
- "eslint-plugin-jsx-a11y": "^2.2.3",
- "eslint-plugin-react": "^6.7.1"
- },
- "babel": {
- "presets": [
- "react",
- "stage-0"
- ],
- "plugins": [
- "syntax-trailing-function-commas",
- "transform-async-to-generator",
- "transform-es2015-destructuring",
- "transform-es2015-parameters",
- "transform-es2015-duplicate-keys",
- "transform-es2015-modules-commonjs",
- "transform-exponentiation-operator",
- "transform-runtime"
- ],
- "env": {
- "test": {
- "plugins": [
- "rewire"
- ]
- }
- }
- },
- "eslintConfig": {
- "parser": "babel-eslint",
- "extends": [
- "airbnb",
- "plugin:css-modules/recommended"
- ],
- "plugins": [
- "css-modules"
- ],
- "globals": {
- "__DEV__": true
- },
- "env": {
- "browser": true
- },
- "rules": {
- "arrow-parens": "off",
- "generator-star-spacing": "off",
- "import/extensions": "off",
- "import/no-extraneous-dependencies": "off",
- "react/forbid-prop-types": "off",
- "react/jsx-filename-extension": "off",
- "react/no-danger": "off",
- "react/no-unused-prop-types": "off",
- "react/prefer-stateless-function": "off"
- }
- },
- "stylelint": {
- "extends": "stylelint-config-standard",
- "rules": {
- "string-quotes": "single",
- "property-no-unknown": [
- true,
- {
- "ignoreProperties": [
- "composes"
- ]
- }
- ],
- "selector-pseudo-class-no-unknown": [
- true,
- {
- "ignorePseudoClasses": [
- "global"
- ]
- }
- ]
- }
- },
- "pre-commit": "lint:staged",
- "lint-staged": {
- "*.{md,sh,txt,xml,html,json}": [
- "editorconfig-tools fix",
- "git add"
- ],
- "*.{js,jsx}": [
- "eslint --fix",
- "git add"
- ],
- "*.{css,less,scss,sss}": [
- "stylefmt",
- "stylelint",
- "git add"
- ]
+ "express": "^4.15.5"
},
"scripts": {
- "lint:js": "eslint src tools",
- "lint:css": "stylelint \"src/**/*.{css,less,scss,sss}\"",
- "lint:staged": "lint-staged",
- "lint": "npm run lint:js && npm run lint:css",
- "test": "mocha \"src/**/*.test.js\" --require babel-register --require test/setup.js",
- "test:watch": "npm run test -- --reporter min --watch",
- "clean": "babel-node tools/run clean",
- "copy": "babel-node tools/run copy",
- "bundle": "babel-node tools/run bundle",
- "build": "babel-node tools/run build",
- "deploy": "babel-node tools/run deployToAzureWebApps",
- "render": "babel-node tools/run render",
- "serve": "babel-node tools/run runServer",
- "start": "babel-node tools/run start"
+ "start": "node server.js"
}
}
diff --git a/public/apple-touch-icon.png b/public/apple-touch-icon.png
deleted file mode 100644
index 41f32f2..0000000
Binary files a/public/apple-touch-icon.png and /dev/null differ
diff --git a/public/browserconfig.xml b/public/browserconfig.xml
deleted file mode 100644
index 46de5d3..0000000
--- a/public/browserconfig.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/public/crossdomain.xml b/public/crossdomain.xml
deleted file mode 100644
index 818b822..0000000
--- a/public/crossdomain.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
diff --git a/public/favicon.ico b/public/favicon.ico
deleted file mode 100644
index a1838b3..0000000
Binary files a/public/favicon.ico and /dev/null differ
diff --git a/public/humans.txt b/public/humans.txt
deleted file mode 100644
index ed65c14..0000000
--- a/public/humans.txt
+++ /dev/null
@@ -1,15 +0,0 @@
-# humanstxt.org/
-# The humans responsible & technology colophon
-
-# TEAM
-
- Daniel Head -- Developer/Groom -- @danhead
-
-# THANKS
-
- Hana Becka, for saying yes
-
-# TECHNOLOGY COLOPHON
-
- CSS3, HTML5, JavaScript
- React, Flux, SuperAgent
diff --git a/public/images/four.jpg b/public/images/four.jpg
new file mode 100755
index 0000000..1d68734
Binary files /dev/null and b/public/images/four.jpg differ
diff --git a/public/images/one.jpg b/public/images/one.jpg
new file mode 100755
index 0000000..7e482f7
Binary files /dev/null and b/public/images/one.jpg differ
diff --git a/public/images/three.jpg b/public/images/three.jpg
new file mode 100755
index 0000000..b23c9db
Binary files /dev/null and b/public/images/three.jpg differ
diff --git a/public/images/two.jpg b/public/images/two.jpg
new file mode 100755
index 0000000..c4e128a
Binary files /dev/null and b/public/images/two.jpg differ
diff --git a/public/img/cervenalhota_2560.jpg b/public/img/cervenalhota_2560.jpg
deleted file mode 100644
index 4eccec3..0000000
Binary files a/public/img/cervenalhota_2560.jpg and /dev/null differ
diff --git a/public/img/church_2560.jpg b/public/img/church_2560.jpg
deleted file mode 100644
index 4621678..0000000
Binary files a/public/img/church_2560.jpg and /dev/null differ
diff --git a/public/img/offley_2560.jpg b/public/img/offley_2560.jpg
deleted file mode 100644
index e45ed4d..0000000
Binary files a/public/img/offley_2560.jpg and /dev/null differ
diff --git a/public/img/prague_2560.jpg b/public/img/prague_2560.jpg
deleted file mode 100644
index 1b5566a..0000000
Binary files a/public/img/prague_2560.jpg and /dev/null differ
diff --git a/public/index.html b/public/index.html
new file mode 100644
index 0000000..d9fca1f
--- /dev/null
+++ b/public/index.html
@@ -0,0 +1,102 @@
+
+
+
+
+
+ Daniel and Hana - Thank you
+
+
+
+ Thank you to all who joined us to celebrate our special day.
+ Our full photo album is coming soon.
+
+
+
+
diff --git a/public/robots.txt b/public/robots.txt
deleted file mode 100644
index d0e5f1b..0000000
--- a/public/robots.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-# www.robotstxt.org/
-
-# Allow crawling of all content
-User-agent: *
-Disallow:
diff --git a/public/tile-wide.png b/public/tile-wide.png
deleted file mode 100644
index d927c40..0000000
Binary files a/public/tile-wide.png and /dev/null differ
diff --git a/public/tile.png b/public/tile.png
deleted file mode 100644
index 9114cab..0000000
Binary files a/public/tile.png and /dev/null differ
diff --git a/server.js b/server.js
new file mode 100644
index 0000000..cf66fb6
--- /dev/null
+++ b/server.js
@@ -0,0 +1,6 @@
+const express = require('express');
+const app = express();
+app.use(express.static('public'));
+app.listen(80);
+console.log('App listening on port 80');
+
diff --git a/src/client.js b/src/client.js
deleted file mode 100644
index 0575fdb..0000000
--- a/src/client.js
+++ /dev/null
@@ -1,189 +0,0 @@
-import 'babel-polyfill';
-import React from 'react';
-import ReactDOM from 'react-dom';
-import FastClick from 'fastclick';
-import UniversalRouter from 'universal-router';
-import queryString from 'query-string';
-import { createPath } from 'history/PathUtils';
-import history from './core/history';
-import App from './components/App';
-import { ErrorReporter, deepForceUpdate } from './core/devUtils';
-
-// Global (context) variables that can be easily accessed from any React component
-// https://facebook.github.io/react/docs/context.html
-const context = {
- // Enables critical path CSS rendering
- // https://github.com/kriasoft/isomorphic-style-loader
- insertCss: (...styles) => {
- // eslint-disable-next-line no-underscore-dangle
- const removeCss = styles.map(x => x._insertCss());
- return () => { removeCss.forEach(f => f()); };
- },
-};
-
-function updateTag(tagName, keyName, keyValue, attrName, attrValue) {
- const node = document.head.querySelector(`${tagName}[${keyName}="${keyValue}"]`);
- if (node && node.getAttribute(attrName) === attrValue) return;
-
- // Remove and create a new tag in order to make it work with bookmarks in Safari
- if (node) {
- node.parentNode.removeChild(node);
- }
- if (typeof attrValue === 'string') {
- const nextNode = document.createElement(tagName);
- nextNode.setAttribute(keyName, keyValue);
- nextNode.setAttribute(attrName, attrValue);
- document.head.appendChild(nextNode);
- }
-}
-function updateMeta(name, content) {
- updateTag('meta', 'name', name, 'content', content);
-}
-function updateCustomMeta(property, content) { // eslint-disable-line no-unused-vars
- updateTag('meta', 'property', property, 'content', content);
-}
-function updateLink(rel, href) { // eslint-disable-line no-unused-vars
- updateTag('link', 'rel', rel, 'href', href);
-}
-
-// Switch off the native scroll restoration behavior and handle it manually
-// https://developers.google.com/web/updates/2015/09/history-api-scroll-restoration
-const scrollPositionsHistory = {};
-if (window.history && 'scrollRestoration' in window.history) {
- window.history.scrollRestoration = 'manual';
-}
-
-let onRenderComplete = function initialRenderComplete() {
- const elem = document.getElementById('css');
- if (elem) elem.parentNode.removeChild(elem);
- onRenderComplete = function renderComplete(route, location) {
- document.title = route.title;
-
- updateMeta('description', route.description);
- // Update necessary tags in at runtime here, ie:
- // updateMeta('keywords', route.keywords);
- // updateCustomMeta('og:url', route.canonicalUrl);
- // updateCustomMeta('og:image', route.imageUrl);
- // updateLink('canonical', route.canonicalUrl);
- // etc.
-
- let scrollX = 0;
- let scrollY = 0;
- const pos = scrollPositionsHistory[location.key];
- if (pos) {
- scrollX = pos.scrollX;
- scrollY = pos.scrollY;
- } else {
- const targetHash = location.hash.substr(1);
- if (targetHash) {
- const target = document.getElementById(targetHash);
- if (target) {
- scrollY = window.pageYOffset + target.getBoundingClientRect().top;
- }
- }
- }
-
- // Restore the scroll position if it was saved into the state
- // or scroll to the given #hash anchor
- // or scroll to top of the page
- window.scrollTo(scrollX, scrollY);
-
- // Google Analytics tracking. Don't send 'pageview' event after
- // the initial rendering, as it was already sent
- if (window.ga) {
- window.ga('send', 'pageview', createPath(location));
- }
- };
-};
-
-// Make taps on links and buttons work fast on mobiles
-FastClick.attach(document.body);
-
-const container = document.getElementById('app');
-let appInstance;
-let currentLocation = history.location;
-let routes = require('./routes').default;
-
-// Re-render the app when window.location changes
-async function onLocationChange(location) {
- // Remember the latest scroll position for the previous location
- scrollPositionsHistory[currentLocation.key] = {
- scrollX: window.pageXOffset,
- scrollY: window.pageYOffset,
- };
- // Delete stored scroll position for next page if any
- if (history.action === 'PUSH') {
- delete scrollPositionsHistory[location.key];
- }
- currentLocation = location;
-
- try {
- // Traverses the list of routes in the order they are defined until
- // it finds the first route that matches provided URL path string
- // and whose action method returns anything other than `undefined`.
- const route = await UniversalRouter.resolve(routes, {
- path: location.pathname,
- query: queryString.parse(location.search),
- });
-
- // Prevent multiple page renders during the routing process
- if (currentLocation.key !== location.key) {
- return;
- }
-
- if (route.redirect) {
- history.replace(route.redirect);
- return;
- }
-
- appInstance = ReactDOM.render(
- {route.component} ,
- container,
- () => onRenderComplete(route, location),
- );
- } catch (error) {
- console.error(error); // eslint-disable-line no-console
-
- // Current url has been changed during navigation process, do nothing
- if (currentLocation.key !== location.key) {
- return;
- }
-
- // Display the error in full-screen for development mode
- if (process.env.NODE_ENV !== 'production') {
- appInstance = null;
- document.title = `Error: ${error.message}`;
- ReactDOM.render( , container);
- return;
- }
-
- // Avoid broken navigation in production mode by a full page reload on error
- window.location.reload();
- }
-}
-
-// Handle client-side navigation by using HTML5 History API
-// For more information visit https://github.com/mjackson/history#readme
-history.listen(onLocationChange);
-onLocationChange(currentLocation);
-
-// Enable Hot Module Replacement (HMR)
-if (module.hot) {
- module.hot.accept('./routes', () => {
- routes = require('./routes').default; // eslint-disable-line global-require
-
- if (appInstance) {
- try {
- // Force-update the whole tree, including components that refuse to update
- deepForceUpdate(appInstance);
- } catch (error) {
- appInstance = null;
- document.title = `Hot Update Error: ${error.message}`;
- ReactDOM.render( , container);
- return;
- }
- }
-
- onLocationChange(currentLocation);
- });
-}
diff --git a/src/components/App.js b/src/components/App.js
deleted file mode 100644
index 28ce58f..0000000
--- a/src/components/App.js
+++ /dev/null
@@ -1,52 +0,0 @@
-import React, { PropTypes } from 'react';
-
-const ContextType = {
- // Enables critical path CSS rendering
- // https://github.com/kriasoft/isomorphic-style-loader
- insertCss: PropTypes.func.isRequired,
-};
-
-/**
- * The top-level React component setting context (global) variables
- * that can be accessed from all the child components.
- *
- * https://facebook.github.io/react/docs/context.html
- *
- * Usage example:
- *
- * const context = {
- * history: createBrowserHistory(),
- * store: createStore(),
- * };
- *
- * ReactDOM.render(
- *
- *
- *
- *
- * ,
- * container,
- * );
- */
-class App extends React.PureComponent {
-
- static propTypes = {
- context: PropTypes.shape(ContextType).isRequired,
- children: PropTypes.element.isRequired,
- };
-
- static childContextTypes = ContextType;
-
- getChildContext() {
- return this.props.context;
- }
-
- render() {
- // NOTE: If you need to add or modify header, footer etc. of the app,
- // please do that inside the Layout component.
- return React.Children.only(this.props.children);
- }
-
-}
-
-export default App;
diff --git a/src/components/Button/Button.css b/src/components/Button/Button.css
deleted file mode 100644
index 0de60bc..0000000
--- a/src/components/Button/Button.css
+++ /dev/null
@@ -1,27 +0,0 @@
-@import '../variables.css';
-
-.root {
- display: block;
- box-sizing: border-box;
- margin: 0;
- padding: 10px 16px;
- width: 100%;
- opacity: 0.75;
- outline: 0;
- border: 4px solid #fff;
- border-radius: 14px;
- background: var(--colour-nearblack);
- color: #fff;
- text-align: center;
- text-decoration: none;
- font-size: 18px;
- line-height: 1.3333333;
- cursor: pointer;
- transition: opacity ease-in-out 0.25s, box-shadow ease-in-out 0.25s;
-}
-
-.root:hover,
-.root:focus {
- opacity: 0.9;
- box-shadow: 0 0 4px #fff;
-}
diff --git a/src/components/Button/Button.js b/src/components/Button/Button.js
deleted file mode 100644
index 072c8ce..0000000
--- a/src/components/Button/Button.js
+++ /dev/null
@@ -1,28 +0,0 @@
-import React, { PropTypes } from 'react';
-import withStyles from 'isomorphic-style-loader/lib/withStyles';
-import s from './Button.css';
-
-class Button extends React.Component {
- static propTypes = {
- to: PropTypes.string,
- children: PropTypes.node,
- onClick: PropTypes.func,
- };
-
- handleClick = (event) => {
- if (this.props.onClick) {
- this.props.onClick(event);
- }
-
- if (this.props.to) {
- window.location.href = this.props.to;
- }
- };
-
- render() {
- const { children, ...props } = this.props;
- return {children} ;
- }
-}
-
-export default withStyles(s)(Button);
diff --git a/src/components/Button/package.json b/src/components/Button/package.json
deleted file mode 100644
index 7fff590..0000000
--- a/src/components/Button/package.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "name": "Button",
- "version": "1.0.0",
- "private": true,
- "main": "./Button.js"
-}
diff --git a/src/components/Html.js b/src/components/Html.js
deleted file mode 100644
index 6107dbd..0000000
--- a/src/components/Html.js
+++ /dev/null
@@ -1,47 +0,0 @@
-import React, { PropTypes } from 'react';
-import { analytics } from '../config';
-
-class Html extends React.Component {
- static propTypes = {
- title: PropTypes.string.isRequired,
- description: PropTypes.string.isRequired,
- style: PropTypes.string,
- scripts: PropTypes.arrayOf(PropTypes.string.isRequired),
- children: PropTypes.string,
- };
-
- render() {
- const { title, description, style, scripts, children } = this.props;
- return (
-
-
-
-
- {title}
-
-
-
-
- {style && }
-
-
-
-
- {scripts && scripts.map(script => )}
- {analytics.google.trackingId &&
-
- }
- {analytics.google.trackingId &&
-
- }
-
-
- );
- }
-}
-
-export default Html;
diff --git a/src/components/Layout/Layout.css b/src/components/Layout/Layout.css
deleted file mode 100644
index f408ed7..0000000
--- a/src/components/Layout/Layout.css
+++ /dev/null
@@ -1,173 +0,0 @@
-@import '../../../node_modules/normalize.css/normalize.css';
-@import '../variables.css';
-
-/*
- * Base styles
- * ========================================================================== */
-
-html {
- color: #222;
- font-weight: 100;
- font-size: 1em; /* ~16px; */
- font-family: var(--font-family-base);
- line-height: 1.375; /* ~22px */
-}
-
-body {
- overflow-x: hidden;
-}
-
-a {
- color: #0074c2;
-}
-
-/*
- * Remove text-shadow in selection highlight:
- * https://twitter.com/miketaylr/status/12228805301
- *
- * These selection rule sets have to be separate.
- * Customize the background color to match your design.
- */
-
-::-moz-selection {
- background: #b3d4fc;
- text-shadow: none;
-}
-
-::selection {
- background: #b3d4fc;
- text-shadow: none;
-}
-
-/*
- * A better looking default horizontal rule
- */
-
-hr {
- display: block;
- height: 1px;
- border: 0;
- border-top: 1px solid #ccc;
- margin: 1em 0;
- padding: 0;
-}
-
-/*
- * Remove the gap between audio, canvas, iframes,
- * images, videos and the bottom of their containers:
- * https://github.com/h5bp/html5-boilerplate/issues/440
- */
-
-audio,
-canvas,
-iframe,
-img,
-svg,
-video {
- vertical-align: middle;
-}
-
-/*
- * Remove default fieldset styles.
- */
-
-fieldset {
- border: 0;
- margin: 0;
- padding: 0;
-}
-
-/*
- * Allow only vertical resizing of textareas.
- */
-
-textarea {
- resize: vertical;
-}
-
-/*
- * Browser upgrade prompt
- * ========================================================================== */
-
-:global(.browserupgrade) {
- margin: 0.2em 0;
- background: #ccc;
- color: #000;
- padding: 0.2em 0;
-}
-
-/*
- * Print styles
- * Inlined to avoid the additional HTTP request:
- * http://www.phpied.com/delay-loading-your-print-css/
- * ========================================================================== */
-
-@media print {
- *,
- *::before,
- *::after {
- background: transparent !important;
- color: #000 !important; /* Black prints faster: http://www.sanbeiji.com/archives/953 */
- box-shadow: none !important;
- text-shadow: none !important;
- }
-
- a,
- a:visited {
- text-decoration: underline;
- }
-
- a[href]::after {
- content: ' (' attr(href) ')';
- }
-
- abbr[title]::after {
- content: ' (' attr(title) ')';
- }
-
- /*
- * Don't show links that are fragment identifiers,
- * or use the `javascript:` pseudo protocol
- */
-
- a[href^='#']::after,
- a[href^='javascript:']::after {
- content: '';
- }
-
- pre,
- blockquote {
- border: 1px solid #999;
- page-break-inside: avoid;
- }
-
- /*
- * Printing Tables:
- * http://css-discuss.incutio.com/wiki/Printing_Tables
- */
-
- thead {
- display: table-header-group;
- }
-
- tr,
- img {
- page-break-inside: avoid;
- }
-
- img {
- max-width: 100% !important;
- }
-
- p,
- h2,
- h3 {
- orphans: 3;
- widows: 3;
- }
-
- h2,
- h3 {
- page-break-after: avoid;
- }
-}
diff --git a/src/components/Layout/Layout.js b/src/components/Layout/Layout.js
deleted file mode 100644
index e60a35b..0000000
--- a/src/components/Layout/Layout.js
+++ /dev/null
@@ -1,22 +0,0 @@
-import React, { PropTypes } from 'react';
-import withStyles from 'isomorphic-style-loader/lib/withStyles';
-import s from './Layout.css';
-import Navigation from '../Navigation';
-
-class Layout extends React.Component {
- static propTypes = {
- children: PropTypes.node.isRequired,
- current: PropTypes.string,
- };
-
- render() {
- return (
-
-
- {this.props.children}
-
- );
- }
-}
-
-export default withStyles(s)(Layout);
diff --git a/src/components/Layout/Layout.test.js b/src/components/Layout/Layout.test.js
deleted file mode 100644
index 2b91f95..0000000
--- a/src/components/Layout/Layout.test.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-env mocha */
-/* eslint-disable padded-blocks, no-unused-expressions */
-
-import React from 'react';
-import { expect } from 'chai';
-import { render } from 'enzyme';
-import App from '../App';
-import Layout from './Layout';
-
-describe('Layout', () => {
-
- it('renders children correctly', () => {
- const wrapper = render(
- {} }}>
-
-
-
- ,
- );
- expect(wrapper.find('div.child').length).to.eq(1);
- });
-
-});
diff --git a/src/components/Layout/package.json b/src/components/Layout/package.json
deleted file mode 100644
index 275e16e..0000000
--- a/src/components/Layout/package.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "name": "Layout",
- "version": "1.0.0",
- "private": true,
- "main": "./Layout.js"
-}
diff --git a/src/components/Link/Link.js b/src/components/Link/Link.js
deleted file mode 100644
index 565fc42..0000000
--- a/src/components/Link/Link.js
+++ /dev/null
@@ -1,42 +0,0 @@
-import React, { PropTypes } from 'react';
-import history from '../../core/history';
-
-function isLeftClickEvent(event) {
- return event.button === 0;
-}
-
-function isModifiedEvent(event) {
- return !!(event.metaKey || event.altKey || event.ctrlKey || event.shiftKey);
-}
-
-class Link extends React.Component {
- static propTypes = {
- to: PropTypes.string.isRequired,
- children: PropTypes.node,
- onClick: PropTypes.func,
- };
-
- handleClick = (event) => {
- if (this.props.onClick) {
- this.props.onClick(event);
- }
-
- if (isModifiedEvent(event) || !isLeftClickEvent(event)) {
- return;
- }
-
- if (event.defaultPrevented === true) {
- return;
- }
-
- event.preventDefault();
- history.push(this.props.to);
- };
-
- render() {
- const { to, children, ...props } = this.props;
- return {children} ;
- }
-}
-
-export default Link;
diff --git a/src/components/Link/package.json b/src/components/Link/package.json
deleted file mode 100644
index 22dfb95..0000000
--- a/src/components/Link/package.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "name": "Link",
- "version": "1.0.0",
- "private": true,
- "main": "./Link.js"
-}
diff --git a/src/components/Map/Map.css b/src/components/Map/Map.css
deleted file mode 100644
index d9c811c..0000000
--- a/src/components/Map/Map.css
+++ /dev/null
@@ -1,21 +0,0 @@
-.root {
- height: 360px;
- width: 100%;
- max-width: 480px;
- overflow: hidden;
- text-shadow: none;
-}
-
-.map {
- height: 360px;
- width: 100%;
- max-width: 480px;
-}
-
-.info {
- color: #000;
-}
-
-.infoTitle {
- margin: 2px 0 10px;
-}
diff --git a/src/components/Map/Map.js b/src/components/Map/Map.js
deleted file mode 100644
index a843200..0000000
--- a/src/components/Map/Map.js
+++ /dev/null
@@ -1,103 +0,0 @@
-import React, { PropTypes } from 'react';
-import withStyles from 'isomorphic-style-loader/lib/withStyles';
-import { withGoogleMap, GoogleMap, Marker, InfoWindow } from 'react-google-maps';
-import s from './Map.css';
-
-class Map extends React.Component {
- static propTypes = {
- defaultZoom: PropTypes.number.isRequired,
- defaultCenter: PropTypes.shape({
- lat: PropTypes.number.isRequired,
- lng: PropTypes.number.isRequired,
- }).isRequired,
- markers: PropTypes.arrayOf(PropTypes.shape({
- title: PropTypes.string.isRequired,
- position: PropTypes.shape({
- lat: PropTypes.number.isRequired,
- lng: PropTypes.number.isRequired,
- }).isRequired,
- showInfo: PropTypes.boolean,
- infoContent: PropTypes.string,
- })).isRequired,
- };
-
- constructor(props) {
- super(props);
- this.state = {
- markers: this.props.markers,
- };
- }
-
- handleMarkerClick = (targetMarker) => {
- this.setState({
- markers: this.state.markers.map(marker => {
- if (marker === targetMarker) {
- return {
- ...marker,
- showInfo: true,
- };
- }
- return marker;
- }),
- });
- };
-
- handleMarkerClose = (targetMarker) => {
- this.setState({
- markers: this.state.markers.map(marker => {
- if (marker === targetMarker) {
- return {
- ...marker,
- showInfo: false,
- };
- }
- return marker;
- }),
- });
- }
-
- render() {
- const GMap = withGoogleMap(() => (
-
- {this.state.markers.map((marker, index) => (
- this.handleMarkerClick(marker)}
- >
- {marker.showInfo && (
- this.handleMarkerClose(marker)}
- >
-
-
- {marker.url ? (
- {marker.title}
- ) : marker.title }
-
- {marker.infoContent}
-
-
- )}
-
- ))}
-
- ));
- return (
-
- }
- mapElement={
-
- }
- />
- );
- }
-}
-
-export default withStyles(s)(Map);
diff --git a/src/components/Map/package.json b/src/components/Map/package.json
deleted file mode 100644
index ad1f326..0000000
--- a/src/components/Map/package.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "name": "Map",
- "version": "1.0.0",
- "private": true,
- "main": "./Map.js"
-}
diff --git a/src/components/Navigation/Navigation.css b/src/components/Navigation/Navigation.css
deleted file mode 100644
index 18c78bc..0000000
--- a/src/components/Navigation/Navigation.css
+++ /dev/null
@@ -1,43 +0,0 @@
-.root {
- position: fixed;
- top: 0;
- right: 0;
- left: 0;
- height: 40px;
- overflow: hidden;
- z-index: 100;
- background: rgba(0, 0, 0, 0.1);
- transition: background 0.3s, ease-in;
-}
-
-.navDark {
- background: rgba(60, 60, 60, 0.95);
-}
-
-.container {
- overflow-x: auto;
- overflow-y: hidden;
- white-space: nowrap;
- text-align: center;
-}
-
-.link {
- display: inline-block;
- padding: 8px 2% 6px;
- text-decoration: none;
- font-size: 1.125em;
- border-bottom: 2px solid transparent;
- transition: color 0.3s ease-in, border-color 0.3s ease-in;
-}
-
-.link,
-.link:visited {
- color: rgba(255, 255, 255, 0.8);
-}
-
-.active,
-.link:active,
-.link:hover {
- color: rgba(255, 255, 255, 1);
- border-color: #fff;
-}
diff --git a/src/components/Navigation/Navigation.js b/src/components/Navigation/Navigation.js
deleted file mode 100644
index 0c26dd4..0000000
--- a/src/components/Navigation/Navigation.js
+++ /dev/null
@@ -1,57 +0,0 @@
-import React, { PropTypes } from 'react';
-import withStyles from 'isomorphic-style-loader/lib/withStyles';
-import s from './Navigation.css';
-import Link from '../Link';
-
-class Navigation extends React.Component {
- static propTypes = {
- current: PropTypes.string,
- };
-
- constructor(props) {
- super(props);
- this.state = {
- scrollAtTop: true,
- };
- }
-
- componentDidMount() {
- window.addEventListener('scroll', this.handleScroll);
- }
-
- componentWillUnmount() {
- window.removeEventListener('scroll', this.handleScroll);
- }
-
- handleScroll = (event) => {
- const scrollTop = event.srcElement.body.scrollTop;
- this.setState({
- scrollAtTop: scrollTop < 10,
- });
- };
-
- render() {
- if (!this.props.current) {
- return null;
- }
- return (
-
-
- RSVP
- Church
- Venue
- Hotels
- Transport
-
-
- );
- }
-}
-
-export default withStyles(s)(Navigation);
diff --git a/src/components/Navigation/package.json b/src/components/Navigation/package.json
deleted file mode 100644
index 9dcd3f8..0000000
--- a/src/components/Navigation/package.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "name": "Navigation",
- "version": "1.1.1",
- "private": true,
- "main": "./Navigation.js"
-}
diff --git a/src/components/Page/Page.css b/src/components/Page/Page.css
deleted file mode 100644
index 5132a91..0000000
--- a/src/components/Page/Page.css
+++ /dev/null
@@ -1,12 +0,0 @@
-@import '../variables.css';
-
-.root {
- padding-left: 20px;
- padding-right: 20px;
-}
-
-.container {
- margin: 0 auto;
- padding: 0 0 40px;
- max-width: var(--max-content-width);
-}
diff --git a/src/components/Page/Page.js b/src/components/Page/Page.js
deleted file mode 100644
index e76ea67..0000000
--- a/src/components/Page/Page.js
+++ /dev/null
@@ -1,24 +0,0 @@
-import React, { PropTypes } from 'react';
-import withStyles from 'isomorphic-style-loader/lib/withStyles';
-import s from './Page.css';
-
-class Page extends React.Component {
- static propTypes = {
- title: PropTypes.string,
- html: PropTypes.string.isRequired,
- };
-
- render() {
- const { title, html } = this.props;
- return (
-
- );
- }
-}
-
-export default withStyles(s)(Page);
diff --git a/src/components/Page/package.json b/src/components/Page/package.json
deleted file mode 100644
index a66eb35..0000000
--- a/src/components/Page/package.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "name": "Page",
- "version": "1.0.0",
- "private": true,
- "main": "./Page.js"
-}
diff --git a/src/components/RsvpButton/RsvpButton.css b/src/components/RsvpButton/RsvpButton.css
deleted file mode 100644
index 5f23fbe..0000000
--- a/src/components/RsvpButton/RsvpButton.css
+++ /dev/null
@@ -1,102 +0,0 @@
-@import '../variables.css';
-
-.root {
- margin: 0 auto;
- max-width: 420px;
- position: relative;
-}
-
-.rsvp,
-.rsvpForm {
- position: absolute;
- width: 100%;
- transition: opacity ease-in-out 0.25s;
- display: none;
- opacity: 0;
-}
-
-.rsvpVisible,
-.rsvpFormVisible {
- display: block;
- opacity: 1;
-}
-
-.formGroup {
- margin-bottom: 15px;
-}
-
-.label {
- display: inline-block;
- position: fixed;
- top: -1000px;
- left: -1000px;
-}
-
-.input {
- display: block;
- box-sizing: border-box;
- padding: 12px 16px;
- width: 100%;
- height: 50px;
- opacity: 0.75;
- outline: 0;
- border: 3px solid #fff;
- border-radius: 14px;
- background: #fff;
- color: #616161;
- font-size: 18px;
- line-height: 1.3333333;
- transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;
-}
-
-.input:focus {
- opacity: 1;
- box-shadow: 0 0 4px #fff;
-}
-
-.inputInvalid {
- animation: shake 0.5s linear;
-}
-
-.invalidMsg {
- display: none;
- padding: 10px 16px;
- border: 2px solid var(--colour-red);
- border-radius: 14px;
- background: var(--colour-nearblack);
- color: #fff;
- text-decoration: none;
- font-size: 18px;
- line-height: 1.3333333;
- transition: opacity ease-in-out 0.25s, box-shadow ease-in-out 0.25s;
-}
-
-.invalidMsgVisible {
- display: inline-block;
- opacity: 0.9;
-}
-
-@keyframes shake {
- 8%,
- 41% {
- transform: translateX(-10px);
- }
-
- 25%,
- 58% {
- transform: translateX(10px);
- }
-
- 75% {
- transform: translateX(-5px);
- }
-
- 92% {
- transform: translateX(5px);
- }
-
- 0%,
- 100% {
- transform: translateX(0);
- }
-}
diff --git a/src/components/RsvpButton/RsvpButton.js b/src/components/RsvpButton/RsvpButton.js
deleted file mode 100644
index a7d2c5a..0000000
--- a/src/components/RsvpButton/RsvpButton.js
+++ /dev/null
@@ -1,152 +0,0 @@
-import React, { PropTypes } from 'react';
-import withStyles from 'isomorphic-style-loader/lib/withStyles';
-import s from './RsvpButton.css';
-import fetch from '../../core/fetch';
-import Button from '../Button';
-
-class RsvpButton extends React.Component {
- static propTypes = {
- focusCallback: PropTypes.func,
- };
-
- constructor(props) {
- super(props);
- this.state = {};
- }
-
- showRsvpForm = () => {
- this.setState({ showRsvpForm: true });
- setTimeout(() => {
- this.rsvpInput.focus();
- }, 500);
- }
-
- handleRsvpFocus = () => {
- if (this.props.focusCallback) {
- this.props.focusCallback(true);
- }
- this.setState({ inputError: false });
- }
-
- handleRsvpBlur = () => {
- if (this.props.focusCallback) {
- this.props.focusCallback(false);
- }
- this.setState({ showRsvpForm: false });
- }
-
- handleRsvpChange = () => {
- this.setState({ inputInvalidMsg: null });
- if (this.rsvpInput.value && this.rsvpInput.value.length === 4) {
- this.validateRsvp();
- }
- }
-
- handleFormSubmit = (event) => {
- event.preventDefault();
- this.validateRsvp();
- }
-
- validateRsvp = () => {
- fetch(`rsvp/${this.rsvpInput.value}`, {
- method: 'get',
- credentials: 'include',
- }).then(data => {
- if (data.status === 200) {
- location.href = data.url;
- } else if (data.status === 429) {
- this.setState({
- inputInvalid: true,
- inputInvalidMsg: 'You have made too many incorrect attempts. Please try again later.',
- inputDisabled: true,
- });
- setTimeout(() => {
- this.setState({
- inputInvalid: false,
- inputDisabled: false,
- });
- }, 10 * 60 * 1000);
- } else {
- this.setState({
- inputInvalid: true,
- inputInvalidMsg: 'Sorry, that RSVP code is invalid.',
- });
- setTimeout(() => {
- this.setState({
- inputInvalid: false,
- });
- }, 500);
- }
- }).catch(() => {
- this.setState({
- inputInvalid: true,
- inputInvalidMsg: 'Sorry, there was a problem validating your RSVP code, please try again later.',
- });
- });
- }
-
- render() {
- return (
-
-
-
- RSVP
-
-
-
-
-
- {this.state.inputInvalidMsg}
-
-
-
- );
- }
-}
-
-export default withStyles(s)(RsvpButton);
diff --git a/src/components/RsvpButton/package.json b/src/components/RsvpButton/package.json
deleted file mode 100644
index ea1ba77..0000000
--- a/src/components/RsvpButton/package.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "name": "RsvpButton",
- "version": "1.0.0",
- "private": true,
- "main": "./RsvpButton.js"
-}
diff --git a/src/components/RsvpCard/RsvpCard.css b/src/components/RsvpCard/RsvpCard.css
deleted file mode 100644
index 4487307..0000000
--- a/src/components/RsvpCard/RsvpCard.css
+++ /dev/null
@@ -1,94 +0,0 @@
-@import '../variables.css';
-
-.root {
- width: 100%;
- margin: 0 0 40px;
- padding: 20px;
- border: 3px solid #fff;
- border-radius: 14px;
- background-color: rgba(0, 0, 0, 0.4);
- color: #fff;
- text-align: left;
-}
-
-@media (--sm-viewport) {
- .root {
- width: 40%;
- max-width: 400px;
- }
-}
-
-.formGroup {
- position: relative;
- margin-bottom: 15px;
-}
-
-.label {
- display: inline-block;
- margin-bottom: 5px;
- max-width: 100%;
- font-weight: 700;
-}
-
-.input {
- display: block;
- box-sizing: border-box;
- padding: 12px 16px;
- width: 100%;
- height: 50px;
- opacity: 0.75;
- outline: 0;
- border: 3px solid #fff;
- border-radius: 14px;
- background-color: #fff;
- color: #616161;
- font-size: 18px;
- line-height: 1.3333333;
- transition: border-color ease-in-out 0.3s, box-shadow ease-in-out 0.3s, background-color ease-in-out 0.3s;
-}
-
-.input:disabled {
- opacity: 0.5;
-}
-
-.input:focus {
- opacity: 1;
- box-shadow: 0 0 4px #fff;
-}
-
-.inputSuccess {
- background-color: var(--colour-green);
-}
-
-.inputError {
- background-color: var(--colour-red);
-}
-
-.rsvpDetails {
- display: none;
-}
-
-.rsvpDetailsVisible {
- display: block;
-}
-
-.iconContainer {
- display: inline-block;
- position: absolute;
- top: 35px;
- right: 15px;
-}
-
-.rsvpSummary {
- opacity: 0;
- font-size: 18px;
- transition: opacity ease-in-out 0.4s;
-}
-
-.rsvpSummarySuccess {
- opacity: 1;
-}
-
-.rsvpSummaryReadOnly {
- opacity: 1;
-}
diff --git a/src/components/RsvpCard/RsvpCard.js b/src/components/RsvpCard/RsvpCard.js
deleted file mode 100644
index 63a3953..0000000
--- a/src/components/RsvpCard/RsvpCard.js
+++ /dev/null
@@ -1,294 +0,0 @@
-import React, { PropTypes } from 'react';
-import cx from 'classnames';
-import withStyles from 'isomorphic-style-loader/lib/withStyles';
-import { MdCheck, MdError } from 'react-icons/lib/md';
-import s from './RsvpCard.css';
-import { starters, mains } from '../../config';
-
-class RsvpCard extends React.Component {
- static propTypes = {
- focusCallback: PropTypes.func,
- className: PropTypes.string,
- person: PropTypes.shape({
- key: PropTypes.string,
- firstname: PropTypes.string,
- lastname: PropTypes.string,
- email: PropTypes.string,
- password: PropTypes.string,
- completed: PropTypes.boolean,
- attending: PropTypes.boolean,
- ceremony: PropTypes.boolean,
- dietary: PropTypes.string,
- starter: PropTypes.string,
- main: PropTypes.string,
- }).isRequired,
- isEditable: PropTypes.bool.isRequired,
- };
-
- constructor(props) {
- super(props);
- this.state = {
- detailsVisible: this.props.person.attending,
- saveAttending: this.props.person.attending ? 'saved' : null,
- saveStarter: this.props.person.starter !== '-1' ? 'saved' : null,
- saveMain: this.props.person.main !== '-1' ? 'saved' : null,
- saveDietary: this.props.person.dietary ? 'saved' : null,
- };
-
- if (!this.props.isEditable) {
- this.state.summaryState = 'readonly';
- this.state.summary = 'Sorry, you can no longer change your RSVP.';
- }
- }
-
- isRSVPComplete(prop, value) {
- function isOK(str) {
- return (str === 'saved' || str === 'success');
- }
-
- if (prop === 'attending' && value === 'false') { return true; }
-
- if (!this.props.person.ceremony) { return true; }
-
- return (isOK(this.state.saveAttending) &&
- isOK(this.state.saveStarter) &&
- isOK(this.state.saveMain));
- }
-
- saveData(prop, value) {
- const stateKey = `save${prop.charAt(0).toUpperCase()}${prop.slice(1)}`;
- const state = {};
-
- fetch('/rsvp/save', {
- method: 'post',
- headers: {
- Accept: 'application/json',
- 'Content-Type': 'application/json',
- },
- body: JSON.stringify({
- key: this.props.person.key,
- prop,
- value,
- }),
- credentials: 'include',
- }).then(res => res.json())
- .then(data => {
- state[stateKey] = data.success ? 'success' : 'error';
- this.setState(state);
- if (this.isRSVPComplete(prop, value)) {
- this.setState({
- summaryState: 'success',
- summary: `Thanks ${this.props.person.firstname}, your RSVP has been received`,
- });
-
- if (!this.state.saveCompleted) {
- this.setState({ saveCompleted: true });
- this.saveData('completed', true);
- }
- }
-
- state[stateKey] = data.success ? 'saved' : 'error';
- setTimeout(() => {
- this.setState(state);
- }, 1000);
- }).catch(() => {
- state[stateKey] = 'error';
- });
- }
-
- handleAttendingChange = (event) => {
- this.saveData('attending', event.target.value);
- this.setState({
- detailsVisible: event.target.value === 'true',
- attendingResponse: event.target.value === 'true' ? '👍' : '☹️',
- });
- };
-
- handleDietaryBlur = (event) => {
- this.saveData('dietary', event.target.value);
- };
-
- handleDietaryChange = (event) => {
- const value = event.target.value;
- clearTimeout(this.dietaryChangeTimer);
- this.dietaryChangeTimer = setTimeout(() => {
- this.saveData('dietary', value);
- }, 5000);
- }
-
- handleStarterChange = (event) => {
- this.saveData('starter', event.target.value);
- };
-
- handleMainChange = (event) => {
- this.saveData('main', event.target.value);
- };
-
- handleFormSubmit = (event) => {
- event.preventDefault();
- };
-
- render() {
- return (
-
-
- {this.props.person.firstname} {this.props.person.lastname}
- {this.state.attendingResponse}
-
-
-
- {this.state.summary}
-
-
- );
- }
-}
-
-export default withStyles(s)(RsvpCard);
diff --git a/src/components/RsvpCard/package.json b/src/components/RsvpCard/package.json
deleted file mode 100644
index b633f89..0000000
--- a/src/components/RsvpCard/package.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "name": "RsvpCard",
- "version": "1.0.0",
- "private": true,
- "main": "./RsvpCard.js"
-}
diff --git a/src/components/variables.css b/src/components/variables.css
deleted file mode 100644
index 1db3bce..0000000
--- a/src/components/variables.css
+++ /dev/null
@@ -1,35 +0,0 @@
-:root {
- /*
- * Typography
- * ======================================================================== */
-
- --font-family-base: 'Palanquin Dark', 'Segoe UI', 'HelveticaNeue-Light', sans-serif;
- --font-family-cursive: 'Niconne', cursive;
-
- /*
- * Layout
- * ======================================================================== */
-
- --max-content-width: 1000px;
-
- /*
- * Media queries breakpoints
- * ======================================================================== */
-
- @custom-media --xs-viewport (min-width: 480px);
- @custom-media --sm-viewport (min-width: 768px);
- @custom-media --md-viewport (min-width: 992px);
- @custom-media --lg-viewport (min-width: 1200px);
-
- /*
- * Colour palette
- * ======================================================================== */
-
- --colour-nearblack: #282828;
- --colour-primary: #6495ed;
- --colour-secondary: #2a6feb;
- --colour-tertiary: #2a6feb;
- --colour-grey: #ccc;
- --colour-green: #87eda2;
- --colour-red: #fa7575;
-}
diff --git a/src/core/admin.js b/src/core/admin.js
deleted file mode 100644
index 52e2ee3..0000000
--- a/src/core/admin.js
+++ /dev/null
@@ -1,6 +0,0 @@
-import { adminUsers } from '../config';
-
-export default function (email) {
- return adminUsers.indexOf(email) !== -1;
-}
-
diff --git a/src/core/devUtils.js b/src/core/devUtils.js
deleted file mode 100644
index 0690d22..0000000
--- a/src/core/devUtils.js
+++ /dev/null
@@ -1,13 +0,0 @@
-/* eslint-disable global-require */
-
-if (module.hot || process.env.NODE_ENV !== 'production') {
- module.exports = {
- // The red box (aka red screen of death) component to display your errors
- // https://github.com/commissure/redbox-react
- ErrorReporter: require('redbox-react').default,
-
- // Force-updates React component tree recursively
- // https://github.com/gaearon/react-deep-force-update
- deepForceUpdate: require('react-deep-force-update'),
- };
-}
diff --git a/src/core/emailer.js b/src/core/emailer.js
deleted file mode 100644
index 65f630c..0000000
--- a/src/core/emailer.js
+++ /dev/null
@@ -1,69 +0,0 @@
-import Nodemailer from 'nodemailer';
-import { email, starters, mains, prettifyDate } from '../config';
-import Rollbar from './rollbar';
-import Settings from '../data/models/Settings';
-
-const transporter = Nodemailer.createTransport({
- service: 'gmail',
- auth: {
- user: email.senderAddress,
- pass: email.password,
- },
-});
-
-// Debounce sending the email to avoid spamming
-const emailTimers = {};
-
-function getEmailText(person) {
- return `Dear ${person.firstname}.\n\n
-Thanks for your RSVP, ${person.attending ? 'we\'re delighted to hear you will be attending' : 'we\'re sorry to hear you will not be attending'}.\n
-${person.attending ? `Your meal choices are ${starters[person.starter]} and ${mains[person.main]}.\n` : ''}
-${person.attending && person.dietary && person.dietary.trim().length > 0 ? `Your dietary requirements are: ${person.dietary}.\n` : ''}
-You can modify your RSVP up until ${prettifyDate(person.enddate)} here: https://danielandhana.com/${person.password}.\n
-${person.attending ? 'See you at our wedding,' : 'Hope to see you soon,'}\n
-Daniel and Hana
-`;
-}
-
-function getEmailHTML(person) {
- return `Dear ${person.firstname}.
-Thanks for your RSVP, ${person.attending ? 'we\'re delighted to hear you will be attending' : 'we\'re sorry to hear you will not be attending'}.
-${person.attending ? `Your meal choices are ${starters[person.starter]} and ${mains[person.main]} .
` : ''}
-${person.attending && person.dietary && person.dietary.trim().length > 0 ? `Your dietary requirements are: ${person.dietary} .
` : ''}
-You can modify your RSVP up until ${prettifyDate(person.enddate)} here .
-${person.attending ? 'See you at our wedding,' : 'Hope to see you soon,'}
-Daniel and Hana
-`;
-}
-
-export const sendRSVPEmail = function sendRSVPEmail(person) {
- Settings.findAll().then(data => {
- if (data[0].email && person.email) {
- const mailOptions = {
- from: `"${email.senderName}" <${email.senderAddress}>`,
- to: person.email,
- subject: 'Thank you for your RSVP',
- text: getEmailText(person),
- html: getEmailHTML(person),
- };
- // send mail with defined transport object
- transporter.sendMail(mailOptions, (error) => {
- if (error) {
- Rollbar.handleError(error);
- }
- });
- }
- }).catch(err => {
- Rollbar.handleError(err);
- });
-};
-
-export const sendRSVPEmailWithDebounce = function sendRSVPEmailWithDebounce(person) {
- if (person.key) {
- // Stop previous email
- clearTimeout(emailTimers[person.key]);
- emailTimers[person.key] = setTimeout(() => {
- sendRSVPEmail(person);
- }, email.debounce);
- }
-};
diff --git a/src/core/fetch/fetch.client.js b/src/core/fetch/fetch.client.js
deleted file mode 100644
index b71a29a..0000000
--- a/src/core/fetch/fetch.client.js
+++ /dev/null
@@ -1,6 +0,0 @@
-import 'whatwg-fetch';
-
-export default self.fetch.bind(self);
-export const Headers = self.Headers;
-export const Request = self.Request;
-export const Response = self.Response;
diff --git a/src/core/fetch/fetch.server.js b/src/core/fetch/fetch.server.js
deleted file mode 100644
index 4ce721c..0000000
--- a/src/core/fetch/fetch.server.js
+++ /dev/null
@@ -1,24 +0,0 @@
-import Promise from 'bluebird';
-import fetch, { Request, Headers, Response } from 'node-fetch';
-import { host } from '../../config';
-
-fetch.Promise = Promise;
-Response.Promise = Promise;
-
-function localUrl(url) {
- if (url.startsWith('//')) {
- return `https:${url}`;
- }
-
- if (url.startsWith('http')) {
- return url;
- }
-
- return `http://${host}${url}`;
-}
-
-function localFetch(url, options) {
- return fetch(localUrl(url), options);
-}
-
-export { localFetch as default, Request, Headers, Response };
diff --git a/src/core/fetch/package.json b/src/core/fetch/package.json
deleted file mode 100644
index 0fa7625..0000000
--- a/src/core/fetch/package.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "private": true,
- "name": "fetch",
- "main": "./fetch.server.js",
- "browser": "./fetch.client.js"
-}
diff --git a/src/core/fetchQL.js b/src/core/fetchQL.js
deleted file mode 100644
index 46851ea..0000000
--- a/src/core/fetchQL.js
+++ /dev/null
@@ -1,17 +0,0 @@
-import fetch from './fetch';
-
-export default function (query, params) {
- return fetch('/graphql', {
- method: 'post',
- headers: {
- Accept: 'application/json',
- 'Content-Type': 'application/json',
- },
- body: JSON.stringify({
- query,
- params,
- }),
- credentials: 'include',
- });
-}
-
diff --git a/src/core/history.js b/src/core/history.js
deleted file mode 100644
index d39e193..0000000
--- a/src/core/history.js
+++ /dev/null
@@ -1,5 +0,0 @@
-import createBrowserHistory from 'history/createBrowserHistory';
-
-// Navigation manager, e.g. history.push('/home')
-// https://github.com/mjackson/history
-export default process.env.BROWSER && createBrowserHistory();
diff --git a/src/core/passport.js b/src/core/passport.js
deleted file mode 100644
index 43402e1..0000000
--- a/src/core/passport.js
+++ /dev/null
@@ -1,121 +0,0 @@
-/**
- * Passport.js reference implementation.
- * The database schema used in this sample is available at
- * https://github.com/membership/membership.db/tree/master/postgres
- */
-
-import passport from 'passport';
-import { Strategy as FacebookStrategy } from 'passport-facebook';
-import { User, UserLogin, UserClaim, UserProfile } from '../data/models';
-import { auth as config } from '../config';
-
-/**
- * Sign in with Facebook.
- */
-passport.use(new FacebookStrategy({
- clientID: config.facebook.id,
- clientSecret: config.facebook.secret,
- callbackURL: '/login/facebook/return',
- profileFields: ['name', 'email', 'link', 'locale', 'timezone'],
- passReqToCallback: true,
-}, (req, accessToken, refreshToken, profile, done) => {
- /* eslint-disable no-underscore-dangle */
- const loginName = 'facebook';
- const claimType = 'urn:facebook:access_token';
- const fooBar = async () => {
- if (req.user) {
- const userLogin = await UserLogin.findOne({
- attributes: ['name', 'key'],
- where: { name: loginName, key: profile.id },
- });
- if (userLogin) {
- // There is already a Facebook account that belongs to you.
- // Sign in with that account or delete it, then link it with your current account.
- done();
- } else {
- const user = await User.create({
- id: req.user.id,
- email: profile._json.email,
- logins: [
- { name: loginName, key: profile.id },
- ],
- claims: [
- { type: claimType, value: profile.id },
- ],
- profile: {
- displayName: profile.displayName,
- gender: profile._json.gender,
- picture: `https://graph.facebook.com/${profile.id}/picture?type=large`,
- },
- }, {
- include: [
- { model: UserLogin, as: 'logins' },
- { model: UserClaim, as: 'claims' },
- { model: UserProfile, as: 'profile' },
- ],
- });
- done(null, {
- id: user.id,
- email: user.email,
- });
- }
- } else {
- const users = await User.findAll({
- attributes: ['id', 'email'],
- where: { '$logins.name$': loginName, '$logins.key$': profile.id },
- include: [
- {
- attributes: ['name', 'key'],
- model: UserLogin,
- as: 'logins',
- required: true,
- },
- ],
- });
- if (users.length) {
- const user = users[0];
- done(null, {
- id: user.id,
- email: user.email,
- });
- } else {
- let user = await User.findOne({ where: { email: profile._json.email } });
- if (user) {
- // There is already an account using this email address. Sign in to
- // that account and link it with Facebook manually from Account Settings.
- done(null);
- } else {
- user = await User.create({
- email: profile._json.email,
- emailConfirmed: true,
- logins: [
- { name: loginName, key: profile.id },
- ],
- claims: [
- { type: claimType, value: accessToken },
- ],
- profile: {
- displayName: profile.displayName,
- gender: profile._json.gender,
- picture: `https://graph.facebook.com/${profile.id}/picture?type=large`,
- },
- }, {
- include: [
- { model: UserLogin, as: 'logins' },
- { model: UserClaim, as: 'claims' },
- { model: UserProfile, as: 'profile' },
- ],
- });
- done(null, {
- id: user.id,
- email: user.email,
- });
- }
- }
- }
- };
-
- fooBar().catch(done);
-}));
-
-export default passport;
diff --git a/src/core/rollbar.js b/src/core/rollbar.js
deleted file mode 100644
index beeae1d..0000000
--- a/src/core/rollbar.js
+++ /dev/null
@@ -1,19 +0,0 @@
-import Rollbar from 'rollbar';
-import { analytics } from '../config';
-
-const serverToken = analytics.rollbar.serverToken;
-
-export default {
- errorHandler() {
- return Rollbar.errorHandler(serverToken);
- },
- handleError(err) {
- return Rollbar.handleError(err);
- },
- init() {
- Rollbar.init(serverToken);
- Rollbar.handleUncaughtExceptionsAndRejections(serverToken, {
- exitOnUncaughtException: true,
- });
- },
-};
diff --git a/src/core/slack.js b/src/core/slack.js
deleted file mode 100644
index a7420db..0000000
--- a/src/core/slack.js
+++ /dev/null
@@ -1,38 +0,0 @@
-import Slack from 'slack-node';
-import { slack as slackCfg } from '../config';
-import Rollbar from './rollbar';
-import Settings from '../data/models/Settings';
-
-const slack = new Slack();
-slack.setWebhook(slackCfg.webhook);
-
-// Debounce sending the slack message to avoid spamming
-const slackTimers = {};
-
-export const sendSlackMsg = function sendSlackMsg(text, channel) {
- Settings.findAll().then(data => {
- if (data[0].slack) {
- slack.webhook({
- channel,
- username: 'weddingbot',
- text,
- }, err => {
- if (err) {
- Rollbar.handleError(err);
- }
- });
- }
- }).catch(err => {
- Rollbar.handleError(err);
- });
-};
-
-export const sendSlackMsgWithDebounce = function sendSlackMsgWithDebounce(text, channel, key) {
- if (key) {
- // Stop previous msg
- clearTimeout(slackTimers[key]);
- slackTimers[key] = setTimeout(() => {
- sendSlackMsg(text, channel);
- }, slackCfg.debounce);
- }
-};
diff --git a/src/data/models/.eslintrc b/src/data/models/.eslintrc
deleted file mode 100644
index 5e3752b..0000000
--- a/src/data/models/.eslintrc
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "rules": {
- "new-cap": 0
- }
-}
diff --git a/src/data/models/Person.js b/src/data/models/Person.js
deleted file mode 100644
index 31317a8..0000000
--- a/src/data/models/Person.js
+++ /dev/null
@@ -1,81 +0,0 @@
-import DataType from 'sequelize';
-import Model from '../sequelize';
-
-const passwordChars = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'j', 'm', 'n', 'p', 'q', 'r', 't', 'u',
- 'w', 'x', 'y', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'M', 'N', 'P', 'Q', 'R', 'T', 'U', 'W',
- 'X', 'Y', '2', '3', '4', '6', '7', '8', '9'];
-
-function generatePassword() {
- let pwd = '';
- for (let i = 0; i < 4; i += 1) {
- pwd += passwordChars[Math.floor(Math.random() * passwordChars.length)];
- }
- return pwd;
-}
-
-const Person = Model.define('Person', {
- key: {
- type: DataType.UUID,
- defaultValue: DataType.UUIDV1,
- primaryKey: true,
- },
-
- password: {
- type: DataType.STRING(4),
- defaultValue() {
- return generatePassword();
- },
- },
-
- firstname: {
- type: DataType.STRING(50),
- },
-
- lastname: {
- type: DataType.STRING(50),
- },
-
- email: {
- type: DataType.STRING(255),
- },
-
- completed: {
- type: DataType.BOOLEAN,
- defaultValue: false,
- },
-
- attending: {
- type: DataType.BOOLEAN,
- },
-
- ceremony: {
- type: DataType.BOOLEAN,
- },
-
- dietary: {
- type: DataType.STRING(255),
- },
-
- starter: {
- type: DataType.INTEGER,
- defaultValue: -1,
- },
-
- main: {
- type: DataType.INTEGER,
- defaultValue: -1,
- },
-
- enddate: {
- type: DataType.DATE,
- },
-
-}, {
-
- indexes: [
- { fields: ['email'] },
- ],
-
-});
-
-export default Person;
diff --git a/src/data/models/Settings.js b/src/data/models/Settings.js
deleted file mode 100644
index d7269c3..0000000
--- a/src/data/models/Settings.js
+++ /dev/null
@@ -1,23 +0,0 @@
-import DataType from 'sequelize';
-import Model from '../sequelize';
-
-const Settings = Model.define('Settings', {
- key: {
- type: DataType.UUID,
- defaultValue: DataType.UUIDV1,
- primaryKey: true,
- },
-
- slack: {
- type: DataType.BOOLEAN,
- defaultValue: false,
- },
-
- email: {
- type: DataType.BOOLEAN,
- defaultValue: false,
- },
-
-});
-
-export default Settings;
diff --git a/src/data/models/User.js b/src/data/models/User.js
deleted file mode 100644
index 31defc6..0000000
--- a/src/data/models/User.js
+++ /dev/null
@@ -1,30 +0,0 @@
-import DataType from 'sequelize';
-import Model from '../sequelize';
-
-const User = Model.define('User', {
-
- id: {
- type: DataType.UUID,
- defaultValue: DataType.UUIDV1,
- primaryKey: true,
- },
-
- email: {
- type: DataType.STRING(255),
- validate: { isEmail: true },
- },
-
- emailConfirmed: {
- type: DataType.BOOLEAN,
- defaultValue: false,
- },
-
-}, {
-
- indexes: [
- { fields: ['email'] },
- ],
-
-});
-
-export default User;
diff --git a/src/data/models/UserClaim.js b/src/data/models/UserClaim.js
deleted file mode 100644
index 3f432fb..0000000
--- a/src/data/models/UserClaim.js
+++ /dev/null
@@ -1,16 +0,0 @@
-import DataType from 'sequelize';
-import Model from '../sequelize';
-
-const UserClaim = Model.define('UserClaim', {
-
- type: {
- type: DataType.STRING,
- },
-
- value: {
- type: DataType.STRING,
- },
-
-});
-
-export default UserClaim;
diff --git a/src/data/models/UserLogin.js b/src/data/models/UserLogin.js
deleted file mode 100644
index 654e4c4..0000000
--- a/src/data/models/UserLogin.js
+++ /dev/null
@@ -1,18 +0,0 @@
-import DataType from 'sequelize';
-import Model from '../sequelize';
-
-const UserLogin = Model.define('UserLogin', {
-
- name: {
- type: DataType.STRING(50),
- primaryKey: true,
- },
-
- key: {
- type: DataType.STRING(100),
- primaryKey: true,
- },
-
-});
-
-export default UserLogin;
diff --git a/src/data/models/UserProfile.js b/src/data/models/UserProfile.js
deleted file mode 100644
index 56e2067..0000000
--- a/src/data/models/UserProfile.js
+++ /dev/null
@@ -1,33 +0,0 @@
-import DataType from 'sequelize';
-import Model from '../sequelize';
-
-const UserProfile = Model.define('UserProfile', {
-
- userId: {
- type: DataType.UUID,
- primaryKey: true,
- },
-
- displayName: {
- type: DataType.STRING(100),
- },
-
- picture: {
- type: DataType.STRING(255),
- },
-
- gender: {
- type: DataType.STRING(50),
- },
-
- location: {
- type: DataType.STRING(100),
- },
-
- website: {
- type: DataType.STRING(255),
- },
-
-});
-
-export default UserProfile;
diff --git a/src/data/models/index.js b/src/data/models/index.js
deleted file mode 100644
index 4bceac7..0000000
--- a/src/data/models/index.js
+++ /dev/null
@@ -1,34 +0,0 @@
-import sequelize from '../sequelize';
-import User from './User';
-import UserLogin from './UserLogin';
-import UserClaim from './UserClaim';
-import UserProfile from './UserProfile';
-import Person from './Person';
-
-User.hasMany(UserLogin, {
- foreignKey: 'userId',
- as: 'logins',
- onUpdate: 'cascade',
- onDelete: 'cascade',
-});
-
-User.hasMany(UserClaim, {
- foreignKey: 'userId',
- as: 'claims',
- onUpdate: 'cascade',
- onDelete: 'cascade',
-});
-
-User.hasOne(UserProfile, {
- foreignKey: 'userId',
- as: 'profile',
- onUpdate: 'cascade',
- onDelete: 'cascade',
-});
-
-function sync(...args) {
- return sequelize.sync(...args);
-}
-
-export default { sync };
-export { User, UserLogin, UserClaim, UserProfile, Person };
diff --git a/src/data/queries/getAllPersons.js b/src/data/queries/getAllPersons.js
deleted file mode 100644
index f7f0725..0000000
--- a/src/data/queries/getAllPersons.js
+++ /dev/null
@@ -1,25 +0,0 @@
-import { GraphQLList as List } from 'graphql';
-import PersonItemType from '../types/PersonItemType';
-import Person from '../models/Person';
-import admin from '../../core/admin';
-
-const person = {
- type: new List(PersonItemType),
- resolve({ request }) {
- const params = request.body.params;
- const user = request.user || {};
- const isAdmin = admin(user.email);
-
- if (params && params.code) {
- return Person.findAll({
- where: {
- password: params.code,
- },
- });
- }
- return isAdmin && Person.findAll();
- },
-};
-
-export default person;
-
diff --git a/src/data/queries/getPersonByKey.js b/src/data/queries/getPersonByKey.js
deleted file mode 100644
index 990c3ff..0000000
--- a/src/data/queries/getPersonByKey.js
+++ /dev/null
@@ -1,22 +0,0 @@
-import { GraphQLList as List } from 'graphql';
-import PersonItemType from '../types/PersonItemType';
-import Person from '../models/Person';
-
-const getPersonByKey = {
- type: new List(PersonItemType),
- resolve({ request }) {
- const params = request.body.params;
-
- if (params && params.key) {
- return Person.findAll({
- where: {
- key: params.key,
- },
- limit: 1,
- });
- }
- return false;
- },
-};
-
-export default getPersonByKey;
diff --git a/src/data/queries/getPersonsByPassword.js b/src/data/queries/getPersonsByPassword.js
deleted file mode 100644
index 8b2a2f7..0000000
--- a/src/data/queries/getPersonsByPassword.js
+++ /dev/null
@@ -1,22 +0,0 @@
-import { GraphQLList as List } from 'graphql';
-import PersonItemType from '../types/PersonItemType';
-import Person from '../models/Person';
-
-const getPersonsByPassword = {
- type: new List(PersonItemType),
- resolve({ request }) {
- const params = request.body.params;
-
- if (params && params.password) {
- return Person.findAll({
- where: {
- password: params.password,
- },
- });
- }
- return false;
- },
-};
-
-export default getPersonsByPassword;
-
diff --git a/src/data/queries/me.js b/src/data/queries/me.js
deleted file mode 100644
index 8275259..0000000
--- a/src/data/queries/me.js
+++ /dev/null
@@ -1,13 +0,0 @@
-import UserType from '../types/UserType';
-
-const me = {
- type: UserType,
- resolve({ request }) {
- return request.user && {
- id: request.user.id,
- email: request.user.email,
- };
- },
-};
-
-export default me;
diff --git a/src/data/queries/settings.js b/src/data/queries/settings.js
deleted file mode 100644
index ddc066f..0000000
--- a/src/data/queries/settings.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import { GraphQLList as List } from 'graphql';
-import SettingsItemType from '../types/SettingsItemType';
-import Settings from '../models/Settings';
-
-const settings = {
- type: new List(SettingsItemType),
- resolve() {
- return Settings.findAll();
- },
-};
-
-export default settings;
diff --git a/src/data/schema.js b/src/data/schema.js
deleted file mode 100644
index 37e041a..0000000
--- a/src/data/schema.js
+++ /dev/null
@@ -1,25 +0,0 @@
-import {
- GraphQLSchema as Schema,
- GraphQLObjectType as ObjectType,
-} from 'graphql';
-
-import me from './queries/me';
-import getAllPersons from './queries/getAllPersons';
-import getPersonByKey from './queries/getPersonByKey';
-import getPersonsByPassword from './queries/getPersonsByPassword';
-import settings from './queries/settings';
-
-const schema = new Schema({
- query: new ObjectType({
- name: 'Query',
- fields: {
- me,
- getAllPersons,
- getPersonByKey,
- getPersonsByPassword,
- settings,
- },
- }),
-});
-
-export default schema;
diff --git a/src/data/sequelize.js b/src/data/sequelize.js
deleted file mode 100644
index a5e950e..0000000
--- a/src/data/sequelize.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import Sequelize from 'sequelize';
-import { databasePath } from '../config';
-
-const sequelize = new Sequelize({
- dialect: 'sqlite',
- storage: databasePath,
- define: {
- freezeTableName: true,
- },
-});
-
-export default sequelize;
diff --git a/src/data/types/PersonItemType.js b/src/data/types/PersonItemType.js
deleted file mode 100644
index 402e2d2..0000000
--- a/src/data/types/PersonItemType.js
+++ /dev/null
@@ -1,27 +0,0 @@
-import {
- GraphQLObjectType as ObjectType,
- GraphQLID as ID,
- GraphQLString as StringType,
- GraphQLBoolean as BooleanType,
- GraphQLNonNull as NonNull,
-} from 'graphql';
-
-const PersonItemType = new ObjectType({
- name: 'PersonItem',
- fields: {
- key: { type: new NonNull(ID) },
- password: { type: StringType },
- firstname: { type: StringType },
- lastname: { type: StringType },
- email: { type: StringType },
- completed: { type: BooleanType },
- attending: { type: BooleanType },
- ceremony: { type: BooleanType },
- dietary: { type: StringType },
- starter: { type: StringType },
- main: { type: StringType },
- enddate: { type: StringType },
- },
-});
-
-export default PersonItemType;
diff --git a/src/data/types/SettingsItemType.js b/src/data/types/SettingsItemType.js
deleted file mode 100644
index be44aa6..0000000
--- a/src/data/types/SettingsItemType.js
+++ /dev/null
@@ -1,17 +0,0 @@
-import {
- GraphQLObjectType as ObjectType,
- GraphQLID as ID,
- GraphQLBoolean as BooleanType,
- GraphQLNonNull as NonNull,
-} from 'graphql';
-
-const SettingsItemType = new ObjectType({
- name: 'SettingsItem',
- fields: {
- key: { type: new NonNull(ID) },
- slack: { type: BooleanType },
- email: { type: BooleanType },
- },
-});
-
-export default SettingsItemType;
diff --git a/src/data/types/UserType.js b/src/data/types/UserType.js
deleted file mode 100644
index 86f0f00..0000000
--- a/src/data/types/UserType.js
+++ /dev/null
@@ -1,16 +0,0 @@
-import {
- GraphQLObjectType as ObjectType,
- GraphQLID as ID,
- GraphQLString as StringType,
- GraphQLNonNull as NonNull,
-} from 'graphql';
-
-const UserType = new ObjectType({
- name: 'User',
- fields: {
- id: { type: new NonNull(ID) },
- email: { type: StringType },
- },
-});
-
-export default UserType;
diff --git a/src/routes/accomodation/Accomodation.css b/src/routes/accomodation/Accomodation.css
deleted file mode 100644
index 05724b8..0000000
--- a/src/routes/accomodation/Accomodation.css
+++ /dev/null
@@ -1,55 +0,0 @@
-@import '../../components/variables.css';
-
-.root {
- width: 100vw;
- height: 100vh;
-}
-
-.bgImage {
- position: fixed;
- width: 100vw;
- height: 100vh;
- background: url('/img/offley_2560.jpg');
- background-size: cover;
- background-position-x: 54%;
- background-position-y: 66%;
- background-color: #c1c1c1;
- filter: grayscale(1) brightness(0.4);
- z-index: -1;
- transition: filter ease-in-out 0.5s;
-}
-
-.container {
- padding-top: 50px;
- margin: 0 20px;
-}
-
-.headings {
- max-width: 640px;
- margin: 0 auto 40px;
- text-align: center;
- color: #fff;
- text-shadow: 3px 3px 8px var(--colour-nearblack);
- font-size: 1.3em;
-}
-
-.headings h1 {
- margin: 0 0 10px;
-}
-
-.content {
- max-width: 960px;
- margin: 0 auto;
- color: #fff;
- text-shadow: 1px 1px 4px var(--colour-nearblack);
-}
-
-.hotelLink {
- color: rgba(255, 255, 255, 0.8);
- transition: color 0.3s ease-in;
-}
-
-.hotelLink:hover,
-.hotelLink:focus {
- color: rgba(255, 255, 255, 1);
-}
diff --git a/src/routes/accomodation/Accomodation.js b/src/routes/accomodation/Accomodation.js
deleted file mode 100644
index 3dcc59a..0000000
--- a/src/routes/accomodation/Accomodation.js
+++ /dev/null
@@ -1,84 +0,0 @@
-import React from 'react';
-import withStyles from 'isomorphic-style-loader/lib/withStyles';
-import s from './Accomodation.css';
-import Map from '../../components/Map';
-
-const offley = {
- title: 'Offley Place',
- url: 'http://www.offleyplace.com/',
- position: {
- lat: 51.9282,
- lng: -0.3332,
- },
- showInfo: true,
-};
-
-const hotels = [
- {
- title: 'Hilton Garden Inn',
- url: 'http://hiltongardeninn3.hilton.com/en/hotels/united-kingdom/hilton-garden-inn-luton-north-LTNNOGI/index.html',
- position: {
- lat: 51.9116,
- lng: -0.3883,
- },
- },
- {
- title: 'Premier Inn',
- url: 'http://www.premierinn.com/gb/en/hotels/england/hertfordshire/hitchin/hitchin-town-centre.html',
- position: {
- lat: 51.9493,
- lng: -0.2762,
- },
- },
- {
- title: 'Lodge Farm House',
- url: 'http://lodgefarmbandb.co.uk',
- position: {
- lat: 51.9054,
- lng: -0.3354,
- },
- },
- {
- title: 'Red Lion Inn',
- url: 'http://www.theredliongreatoffley.co.uk',
- position: {
- lat: 51.9266,
- lng: -0.3348,
- },
- },
-];
-
-class Accomodation extends React.Component {
- constructor(props) {
- super(props);
- this.markers = [offley].concat(hotels);
- }
-
- render() {
- return (
-
-
-
-
-
Local hotels
-
-
-
The following hotels are near Offley Place:
-
-
-
-
-
- );
- }
-}
-
-export default withStyles(s)(Accomodation);
diff --git a/src/routes/accomodation/index.js b/src/routes/accomodation/index.js
deleted file mode 100644
index b431238..0000000
--- a/src/routes/accomodation/index.js
+++ /dev/null
@@ -1,15 +0,0 @@
-import React from 'react';
-import Accomodation from './Accomodation';
-import Layout from '../../components/Layout';
-
-export default {
-
- path: '/hotels',
-
- action() {
- return {
- title: 'Hotels',
- component: ,
- };
- },
-};
diff --git a/src/routes/admin/Admin.css b/src/routes/admin/Admin.css
deleted file mode 100644
index 9d6ba74..0000000
--- a/src/routes/admin/Admin.css
+++ /dev/null
@@ -1,28 +0,0 @@
-@import '../../components/variables.css';
-
-.root {
- padding-left: 20px;
- padding-right: 20px;
-}
-
-.container {
- margin: 0 auto;
- padding: 0 0 40px;
- max-width: var(--max-content-width);
-}
-
-.formGroup {
- position: relative;
- margin-bottom: 15px;
-}
-
-.label {
- display: inline-block;
- margin-bottom: 5px;
- max-width: 100%;
- font-weight: 700;
-}
-
-.input {
- margin-left: 10px;
-}
diff --git a/src/routes/admin/Admin.js b/src/routes/admin/Admin.js
deleted file mode 100644
index 65f0b82..0000000
--- a/src/routes/admin/Admin.js
+++ /dev/null
@@ -1,106 +0,0 @@
-import React, { PropTypes } from 'react';
-import withStyles from 'isomorphic-style-loader/lib/withStyles';
-import s from './Admin.css';
-import Link from '../../components/Link';
-import Button from '../../components/Button';
-
-class Admin extends React.Component {
- static propTypes = {
- title: PropTypes.string.isRequired,
- people: PropTypes.arrayOf(PropTypes.shape({
- key: PropTypes.string.isRequired,
- firstname: PropTypes.string,
- lastname: PropTypes.string,
- email: PropTypes.string,
- password: PropTypes.string,
- attending: PropTypes.boolean,
- })).isRequired,
- starters: PropTypes.arrayOf(PropTypes.shape({
- name: PropTypes.string,
- total: PropTypes.integer,
- })).isRequired,
- mains: PropTypes.arrayOf(PropTypes.shape({
- name: PropTypes.string,
- total: PropTypes.integer,
- })).isRequired,
- build: PropTypes.shape({
- hash: PropTypes.string,
- time: PropTypes.string,
- }),
- settings: PropTypes.shape({
- slack: PropTypes.boolean,
- email: PropTypes.boolean,
- }),
- };
-
- render() {
- return (
-
-
-
{this.props.title}
-
-
People
-
{this.props.people.length} people
-
{this.props.people.filter(person => person.completed).length} responses
-
Manage people
-
-
-
Food
-
Starters
-
- {this.props.starters.map((starter, index) => (
- {starter.name} - {starter.total}
- ))}
-
-
Mains
-
- {this.props.mains.map((main, index) => (
- {main.name} - {main.total}
- ))}
-
-
-
-
-
- Build time: {this.props.build.time}
-
-
-
- );
- }
-}
-
-export default withStyles(s)(Admin);
diff --git a/src/routes/admin/index.js b/src/routes/admin/index.js
deleted file mode 100644
index 6b6ddd6..0000000
--- a/src/routes/admin/index.js
+++ /dev/null
@@ -1,67 +0,0 @@
-import React from 'react';
-import Layout from '../../components/Layout';
-import fetchQL from '../../core/fetchQL';
-import fetch from '../../core/fetch';
-import { starters, mains } from '../../config';
-
-const title = 'Admin';
-
-export default {
-
- path: '/admin',
-
- async action() {
- const resp = await fetchQL('{getAllPersons{key,firstname,lastname,email,password,completed,starter,main}}');
- const configResp = await fetch('/config.json', {
- headers: {
- Accept: 'application/json',
- 'Content-Type': 'application/json',
- },
- credentials: 'include',
- });
-
- const settingsResp = await fetchQL('{settings{slack,email}}');
- const { data } = await resp.json();
- const config = await configResp.json();
- let settings = await settingsResp.json();
- if (settings && settings.data && settings.data.settings && settings.data.settings[0]) {
- settings = settings.data.settings[0];
- } else {
- settings = {
- slack: false,
- email: false,
- };
- }
-
- const people = data.getAllPersons || [];
-
- const food = {
- starters: starters.map((name, index) => {
- const total = people.filter(person => person.starter === `${index}`).length;
- return { name, total };
- }),
- mains: mains.map((name, index) => {
- const total = people.filter(person => person.main === `${index}`).length;
- return { name, total };
- }),
- };
-
- const Admin = await new Promise((resolve) => {
- require.ensure([], (require) => resolve(require('./Admin').default), 'admin');
- });
-
- return {
- title,
- chunk: 'admin',
- component: ,
- };
- },
-
-};
diff --git a/src/routes/adminPeople/AdminPeople.css b/src/routes/adminPeople/AdminPeople.css
deleted file mode 100644
index c8cc616..0000000
--- a/src/routes/adminPeople/AdminPeople.css
+++ /dev/null
@@ -1,83 +0,0 @@
-@import '../../components/variables.css';
-
-.root {
- padding-left: 20px;
- padding-right: 20px;
-}
-
-.container {
- margin: 0 auto;
- padding: 0 0 40px;
- max-width: var(--max-content-width);
-}
-
-table {
- border-spacing: 0;
-}
-
-td {
- position: relative;
- padding: 0 14px;
-}
-
-.formGroup {
- position: relative;
- margin-bottom: 15px;
-}
-
-.label {
- display: inline-block;
- margin-bottom: 5px;
- max-width: 100%;
- font-weight: 700;
-}
-
-.input {
- display: block;
- box-sizing: border-box;
- padding: 10px 16px;
- width: 100%;
- height: 46px;
- outline: 0;
- border: 1px solid var(--colour-grey);
- border-radius: 0;
- background-color: #fff;
- box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
- color: #616161;
- font-size: 18px;
- line-height: 1.3333333;
- transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s, background-color ease-in-out 0.15s;
-}
-
-.input:focus {
- border-color: var(--colour-tertiary);
- box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(0, 116, 194, 0.6);
-}
-
-.personForm {
- display: none;
-}
-
-.personFormVisible {
- display: block;
-}
-
-.sortIcon {
- display: none;
- position: absolute;
- top: 50%;
- left: 0;
- transform: translateY(-50%);
-}
-
-.showSortIcon {
- display: inline-block;
-}
-
-.importForm {
- display: none;
-}
-
-.importFormVisible {
- display: block;
-}
diff --git a/src/routes/adminPeople/AdminPeople.js b/src/routes/adminPeople/AdminPeople.js
deleted file mode 100644
index 1052a3b..0000000
--- a/src/routes/adminPeople/AdminPeople.js
+++ /dev/null
@@ -1,325 +0,0 @@
-import React, { PropTypes } from 'react';
-import withStyles from 'isomorphic-style-loader/lib/withStyles';
-import s from './AdminPeople.css';
-import Link from '../../components/Link';
-import Button from '../../components/Button';
-import { prettifyDate } from '../../config';
-
-class AdminPeople extends React.Component {
- static propTypes = {
- title: PropTypes.string.isRequired,
- people: PropTypes.arrayOf(PropTypes.shape({
- key: PropTypes.string.isRequired,
- firstname: PropTypes.string,
- lastname: PropTypes.string,
- completed: PropTypes.boolean,
- ceremony: PropTypes.boolean,
- email: PropTypes.string,
- password: PropTypes.string,
- attending: PropTypes.boolean,
- enddate: PropTypes.string,
- })).isRequired,
- };
-
- constructor(props) {
- super(props);
- this.state = {
- people: this.props.people,
- personFormVisible: false,
- sortDirection: false,
- };
- }
-
- sortPeople = (event, sortedBy) => {
- event.preventDefault();
- const sortDirection = (sortedBy === this.state.sortedBy) ? !this.state.sortDirection : true;
- this.setState({
- sortedBy,
- sortDirection,
- people: this.props.people.sort((a, b) => {
- if (a[sortedBy] > b[sortedBy]) {
- return sortDirection ? 1 : -1;
- }
- return sortDirection ? -1 : 1;
- }),
- });
- }
-
- togglePersonForm = (event) => {
- event.preventDefault();
- this.setState({ personFormVisible: !this.state.personFormVisible });
- }
-
- openImportForm = (event) => {
- event.preventDefault();
- this.setState({ openImportForm: true });
- }
-
- render() {
- return (
-
-
-
{this.props.title}
-
- {this.state.people.length === 0 ?
No people yet ☹️
:
-
- }
-
-
-
-
Import data
- {!this.state.openImportForm ? ' / ' : null}
- {!this.state.openImportForm ?
Export data : null}
-
-
-
-
- );
- }
-}
-
-export default withStyles(s)(AdminPeople);
diff --git a/src/routes/adminPeople/index.js b/src/routes/adminPeople/index.js
deleted file mode 100644
index a0a0866..0000000
--- a/src/routes/adminPeople/index.js
+++ /dev/null
@@ -1,32 +0,0 @@
-import React from 'react';
-import Layout from '../../components/Layout';
-import fetchQL from '../../core/fetchQL';
-
-const title = 'People';
-
-export default {
-
- path: '/admin/people',
-
- async action() {
- const resp = await fetchQL('{getAllPersons{key,firstname,lastname,email,ceremony,completed,password,enddate}}');
-
- let people = await resp.json();
- if (people.data && people.data.getAllPersons) {
- people = people.data.getAllPersons;
- } else {
- people = [];
- }
-
- const AdminPeople = await new Promise((resolve) => {
- require.ensure([], (require) => resolve(require('./AdminPeople').default), 'adminPeople');
- });
-
- return {
- title,
- chunk: 'admin',
- component: ,
- };
- },
-
-};
diff --git a/src/routes/adminPerson/AdminPerson.css b/src/routes/adminPerson/AdminPerson.css
deleted file mode 100644
index 584efa8..0000000
--- a/src/routes/adminPerson/AdminPerson.css
+++ /dev/null
@@ -1,49 +0,0 @@
-@import '../../components/variables.css';
-
-.root {
- padding-left: 20px;
- padding-right: 20px;
-}
-
-.container {
- margin: 0 auto;
- padding: 0 0 40px;
- max-width: var(--max-content-width);
-}
-
-.formGroup {
- position: relative;
- margin-bottom: 15px;
-}
-
-.label {
- display: inline-block;
- margin-bottom: 5px;
- max-width: 100%;
- font-weight: 700;
-}
-
-.input {
- display: block;
- box-sizing: border-box;
- padding: 10px 16px;
- width: 100%;
- height: 46px;
- outline: 0;
- border: 1px solid var(--colour-grey);
- border-radius: 0;
- background-color: #fff;
- box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
- color: #616161;
- font-size: 18px;
- line-height: 1.3333333;
- transition:
- border-color ease-in-out 0.15s,
- box-shadow ease-in-out 0.15s,
- background-color ease-in-out 0.15s;
-}
-
-.input:focus {
- border-color: var(--colour-tertiary);
- box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(0, 116, 194, 0.6);
-}
diff --git a/src/routes/adminPerson/AdminPerson.js b/src/routes/adminPerson/AdminPerson.js
deleted file mode 100644
index a66bd57..0000000
--- a/src/routes/adminPerson/AdminPerson.js
+++ /dev/null
@@ -1,142 +0,0 @@
-import React, { PropTypes } from 'react';
-import withStyles from 'isomorphic-style-loader/lib/withStyles';
-import s from './AdminPerson.css';
-import Button from '../../components/Button';
-
-class AdminPerson extends React.Component {
- static propTypes = {
- title: PropTypes.string.isRequired,
- person: PropTypes.shape({
- key: PropTypes.string.isRequired,
- firstname: PropTypes.string,
- lastname: PropTypes.string,
- completed: PropTypes.boolean,
- email: PropTypes.string,
- password: PropTypes.string,
- attending: PropTypes.boolean,
- ceremony: PropTypes.boolean,
- enddate: PropTypes.string,
- }).isRequired,
- };
-
- state = {
- firstname: this.props.person.firstname,
- lastname: this.props.person.lastname,
- };
-
- getISODate = (date) => {
- const d = new Date(date);
- const year = d.getFullYear();
- const month = d.getMonth() + 1 < 10 ? `0${d.getMonth() + 1}` : d.getMonth() + 1;
- const day = d.getDate() < 10 ? `0${d.getDate()}` : d.getDate();
- return `${year}-${month}-${day}`;
- }
-
- handleFirstnameChange = (event) => {
- this.setState({ firstname: event.target.value });
- }
-
- handleLastnameChange = (event) => {
- this.setState({ lastname: event.target.value });
- }
-
- render() {
- return (
-
- );
- }
-}
-
-export default withStyles(s)(AdminPerson);
diff --git a/src/routes/adminPerson/index.js b/src/routes/adminPerson/index.js
deleted file mode 100644
index c972f61..0000000
--- a/src/routes/adminPerson/index.js
+++ /dev/null
@@ -1,38 +0,0 @@
-import React from 'react';
-import Layout from '../../components/Layout';
-import fetchQL from '../../core/fetchQL';
-
-export default {
-
- path: '/admin/person/:key',
-
- async action({ params }) {
- if (!params.key) {
- return { redirect: '/admin' };
- }
-
- const resp = await fetchQL('{getPersonByKey{key,firstname,lastname,email,completed,password,ceremony,starter,main,dietary,enddate}}', {
- key: params.key,
- });
-
- let person = await resp.json();
- if (person.data && person.data.getPersonByKey && person.data.getPersonByKey.length === 1) {
- person = person.data.getPersonByKey[0];
- } else {
- return { redirect: '/admin' };
- }
-
- const AdminPerson = await new Promise((resolve) => {
- require.ensure([], (require) => resolve(require('./AdminPerson').default), 'adminPerson');
- });
-
- const title = `${person.firstname} ${person.lastname}`;
-
- return {
- title,
- chunk: 'admin',
- component: ,
- };
- },
-
-};
diff --git a/src/routes/ceremony/Ceremony.css b/src/routes/ceremony/Ceremony.css
deleted file mode 100644
index a6b9773..0000000
--- a/src/routes/ceremony/Ceremony.css
+++ /dev/null
@@ -1,49 +0,0 @@
-@import '../../components/variables.css';
-
-.root {
- width: 100vw;
- height: 100vh;
-}
-
-.bgImage {
- position: fixed;
- width: 100vw;
- height: 100vh;
- background: url('/img/church_2560.jpg');
- background-size: cover;
- background-position-x: 54%;
- background-position-y: 66%;
- background-color: #c1c1c1;
- filter: grayscale(1) brightness(0.4);
- z-index: -1;
- transition: filter ease-in-out 0.5s;
-}
-
-.container {
- padding-top: 50px;
- margin: 0 20px;
-}
-
-.headings {
- max-width: 640px;
- margin: 0 auto 40px;
- text-align: center;
- color: #fff;
- text-shadow: 3px 3px 8px var(--colour-nearblack);
- font-size: 1.3em;
-}
-
-.headings h1 {
- margin: 0 0 10px;
-}
-
-.subheading {
- font-family: var(--font-family-cursive);
-}
-
-.content {
- max-width: 960px;
- margin: 0 auto;
- color: #fff;
- text-shadow: 1px 1px 4px var(--colour-nearblack);
-}
diff --git a/src/routes/ceremony/Ceremony.js b/src/routes/ceremony/Ceremony.js
deleted file mode 100644
index 7eb75eb..0000000
--- a/src/routes/ceremony/Ceremony.js
+++ /dev/null
@@ -1,65 +0,0 @@
-import React from 'react';
-import withStyles from 'isomorphic-style-loader/lib/withStyles';
-import s from './Ceremony.css';
-import Map from '../../components/Map';
-
-const church = {
- title: 'All Saints\' Church',
- position: {
- lat: 51.7109,
- lng: -0.4479,
- },
- showInfo: true,
-};
-
-const carPark = {
- title: 'Langley Hill Car Park',
- position: {
- lat: 51.7121,
- lng: -0.4507,
- },
- showInfo: true,
-};
-
-class Ceremony extends React.Component {
- constructor(props) {
- super(props);
- this.markers = [church, carPark];
- }
-
- render() {
- return (
-
-
-
-
-
All Saints’ Church
- Church Lane Kings Langley WD4 8JS
-
-
-
When
-
The ceremony begins at 1pm
-
Where
-
The church is located at the southern end of Kings Langley high street.
- Free parking is available on Langley Hill.
-
-
About the church
-
All Saints Church is a medieval church with parts dating from the 13th century.
- The main features of the church are the beautiful reredos, depicting
- The Last Supper, and the fine Jacobean pulpit with its intricate carvings.
- The Tower has a peal of 8 bells that are regularly rung before Services.
-
The church was chosen because it is Dan’s family church.
-
-
-
- );
- }
-}
-
-export default withStyles(s)(Ceremony);
diff --git a/src/routes/ceremony/index.js b/src/routes/ceremony/index.js
deleted file mode 100644
index a49d479..0000000
--- a/src/routes/ceremony/index.js
+++ /dev/null
@@ -1,15 +0,0 @@
-import React from 'react';
-import Ceremony from './Ceremony';
-import Layout from '../../components/Layout';
-
-export default {
-
- path: '/church',
-
- action() {
- return {
- title: 'All Saints\' Church',
- component: ,
- };
- },
-};
diff --git a/src/routes/error/ErrorPage.css b/src/routes/error/ErrorPage.css
deleted file mode 100644
index 41c90f9..0000000
--- a/src/routes/error/ErrorPage.css
+++ /dev/null
@@ -1,47 +0,0 @@
-* {
- line-height: 1.2;
- margin: 0;
-}
-
-html {
- color: #888;
- display: table;
- font-family: sans-serif;
- height: 100%;
- text-align: center;
- width: 100%;
-}
-
-body {
- display: table-cell;
- vertical-align: middle;
- padding: 2em;
-}
-
-h1 {
- color: #555;
- font-size: 2em;
- font-weight: 400;
-}
-
-p {
- margin: 0 auto;
- width: 280px;
-}
-
-pre {
- text-align: left;
- margin-top: 2rem;
-}
-
-@media only screen and (max-width: 280px) {
- body,
- p {
- width: 95%;
- }
-
- h1 {
- font-size: 1.5em;
- margin: 0 0 0.3em;
- }
-}
diff --git a/src/routes/error/ErrorPage.js b/src/routes/error/ErrorPage.js
deleted file mode 100644
index f2ebcb3..0000000
--- a/src/routes/error/ErrorPage.js
+++ /dev/null
@@ -1,32 +0,0 @@
-import React, { PropTypes } from 'react';
-import withStyles from 'isomorphic-style-loader/lib/withStyles';
-import s from './ErrorPage.css';
-
-class ErrorPage extends React.Component {
- static propTypes = {
- error: PropTypes.object.isRequired,
- };
-
- render() {
- if (process.env.NODE_ENV !== 'production') {
- const { error } = this.props;
- return (
-
-
{error.name}
-
{error.message}
-
{error.stack}
-
- );
- }
-
- return (
-
-
Error
-
Sorry, a critical error occurred on this page.
-
- );
- }
-}
-
-export { ErrorPage as ErrorPageWithoutStyle };
-export default withStyles(s)(ErrorPage);
diff --git a/src/routes/error/index.js b/src/routes/error/index.js
deleted file mode 100644
index c145a1e..0000000
--- a/src/routes/error/index.js
+++ /dev/null
@@ -1,17 +0,0 @@
-import React from 'react';
-import ErrorPage from './ErrorPage';
-
-export default {
-
- path: '/error',
-
- action({ error }) {
- return {
- title: error.name,
- description: error.message,
- component: ,
- status: error.status || 500,
- };
- },
-
-};
diff --git a/src/routes/home/Home.css b/src/routes/home/Home.css
deleted file mode 100644
index ad8e1f3..0000000
--- a/src/routes/home/Home.css
+++ /dev/null
@@ -1,55 +0,0 @@
-@import '../../components/variables.css';
-
-.root {
- width: 100vw;
- height: 100vh;
-}
-
-.bgImage {
- position: fixed;
- width: 100vw;
- height: 100vh;
- background: url('/img/prague_2560.jpg');
- background-size: cover;
- background-position-x: 54%;
- background-position-y: 66%;
- background-color: #c1c1c1;
- filter: grayscale(1) brightness(0.6);
- z-index: -1;
- transition: filter ease-in-out 0.5s;
-}
-
-.bgImageFocus {
- filter: grayscale(0.4) brightness(1);
-}
-
-.container {
- padding-top: 50px;
- margin: 0 20px;
-}
-
-.headings {
- max-width: 640px;
- margin: 0 auto 40px;
- text-align: center;
- color: #fff;
- text-shadow: 3px 3px 8px var(--colour-nearblack);
- font-size: 1.3em;
-}
-
-.headings h1 {
- margin: 0 0 10px;
-}
-
-.headings h2 {
- margin: 0 0 60px;
-}
-
-.headings h3 {
- margin: 0 0 20px;
- font-family: var(--font-family-cursive);
-}
-
-.rsvp {
- padding-top: 10vh;
-}
diff --git a/src/routes/home/Home.js b/src/routes/home/Home.js
deleted file mode 100644
index cc3fffb..0000000
--- a/src/routes/home/Home.js
+++ /dev/null
@@ -1,43 +0,0 @@
-import React from 'react';
-import withStyles from 'isomorphic-style-loader/lib/withStyles';
-import s from './Home.css';
-import RsvpButton from '../../components/RsvpButton';
-
-class Home extends React.Component {
-
- constructor(props) {
- super(props);
- this.state = {};
- }
-
- focusBgImage = (focus) => {
- this.setState({ focusBgImage: focus });
- }
-
- render() {
- return (
-
-
-
-
-
Daniel and Hana
- are getting married
- - 27th July 2017 -
-
-
-
-
-
-
- );
- }
-}
-
-export default withStyles(s)(Home);
diff --git a/src/routes/home/index.js b/src/routes/home/index.js
deleted file mode 100644
index eb54b44..0000000
--- a/src/routes/home/index.js
+++ /dev/null
@@ -1,15 +0,0 @@
-import React from 'react';
-import Home from './Home';
-import Layout from '../../components/Layout';
-
-export default {
-
- path: '/',
-
- action() {
- return {
- title: 'Welcome',
- component: ,
- };
- },
-};
diff --git a/src/routes/index.js b/src/routes/index.js
deleted file mode 100644
index cd55aae..0000000
--- a/src/routes/index.js
+++ /dev/null
@@ -1,36 +0,0 @@
-/* eslint-disable global-require */
-
-// The top-level (parent) route
-export default {
-
- path: '/',
-
- // Keep in mind, routes are evaluated in order
- children: [
- require('./home').default,
- require('./rsvp').default,
- require('./ceremony').default,
- require('./reception').default,
- require('./accomodation').default,
- require('./transport').default,
- require('./login').default,
- require('./admin').default,
- require('./adminPeople').default,
- require('./adminPerson').default,
-
- // Wildcard routes, e.g. { path: '*', ... } (must go last)
- require('./notFound').default,
- ],
-
- async action({ next }) {
- // Execute each child route until one of them return the result
- const route = await next();
-
- // Provide default values for title, description etc.
- route.title = `${route.title || 'Untitled Page'} - Daniel and Hana's Wedding`;
- route.description = route.description || '';
-
- return route;
- },
-
-};
diff --git a/src/routes/login/Login.css b/src/routes/login/Login.css
deleted file mode 100644
index 0c0a475..0000000
--- a/src/routes/login/Login.css
+++ /dev/null
@@ -1,47 +0,0 @@
-@import '../../components/variables.css';
-
-.root {
- padding-left: 20px;
- padding-right: 20px;
-}
-
-.container {
- margin: 0 auto;
- padding: 0 0 40px;
- max-width: 380px;
-}
-
-.formGroup {
- margin-bottom: 15px;
-}
-
-.facebook {
- display: block;
- box-sizing: border-box;
- margin: 0;
- padding: 10px 16px;
- width: 100%;
- outline: 0;
- border: 1px solid #3b5998;
- border-radius: 0;
- background: #3b5998;
- color: #fff;
- text-align: center;
- text-decoration: none;
- font-size: 18px;
- line-height: 1.3333333;
- cursor: pointer;
-}
-
-.facebook:hover {
- background: #2d4373;
-}
-
-.icon {
- display: inline-block;
- margin: -2px 12px -2px 0;
- width: 20px;
- height: 20px;
- vertical-align: middle;
- fill: currentColor;
-}
diff --git a/src/routes/login/Login.js b/src/routes/login/Login.js
deleted file mode 100644
index 7fbdc70..0000000
--- a/src/routes/login/Login.js
+++ /dev/null
@@ -1,37 +0,0 @@
-import React, { PropTypes } from 'react';
-import withStyles from 'isomorphic-style-loader/lib/withStyles';
-import s from './Login.css';
-
-class Login extends React.Component {
- static propTypes = {
- title: PropTypes.string.isRequired,
- };
-
- render() {
- return (
-
- );
- }
-}
-
-export default withStyles(s)(Login);
diff --git a/src/routes/login/index.js b/src/routes/login/index.js
deleted file mode 100644
index f1e39e9..0000000
--- a/src/routes/login/index.js
+++ /dev/null
@@ -1,17 +0,0 @@
-import React from 'react';
-import Layout from '../../components/Layout';
-import Login from './Login';
-
-const title = 'Log In';
-
-export default {
-
- path: '/login',
-
- async action() {
- return {
- title,
- component: ,
- };
- },
-};
diff --git a/src/routes/notFound/NotFound.css b/src/routes/notFound/NotFound.css
deleted file mode 100644
index f7898e4..0000000
--- a/src/routes/notFound/NotFound.css
+++ /dev/null
@@ -1,12 +0,0 @@
-@import '../../components/variables.css';
-
-.root {
- padding-left: 20px;
- padding-right: 20px;
-}
-
-.container {
- margin: 0 auto;
- padding: 50px 0 40px;
- max-width: var(--max-content-width);
-}
diff --git a/src/routes/notFound/NotFound.js b/src/routes/notFound/NotFound.js
deleted file mode 100644
index d85f29a..0000000
--- a/src/routes/notFound/NotFound.js
+++ /dev/null
@@ -1,22 +0,0 @@
-import React, { PropTypes } from 'react';
-import withStyles from 'isomorphic-style-loader/lib/withStyles';
-import s from './NotFound.css';
-
-class NotFound extends React.Component {
- static propTypes = {
- title: PropTypes.string.isRequired,
- };
-
- render() {
- return (
-
-
-
{this.props.title}
-
Sorry, the page you were trying to view does not exist.
-
-
- );
- }
-}
-
-export default withStyles(s)(NotFound);
diff --git a/src/routes/notFound/index.js b/src/routes/notFound/index.js
deleted file mode 100644
index 8a91911..0000000
--- a/src/routes/notFound/index.js
+++ /dev/null
@@ -1,19 +0,0 @@
-import React from 'react';
-import Layout from '../../components/Layout';
-import NotFound from './NotFound';
-
-const title = 'Page Not Found';
-
-export default {
-
- path: '*',
-
- action() {
- return {
- title,
- component: ,
- status: 404,
- };
- },
-
-};
diff --git a/src/routes/reception/Reception.css b/src/routes/reception/Reception.css
deleted file mode 100644
index 1ea2c81..0000000
--- a/src/routes/reception/Reception.css
+++ /dev/null
@@ -1,49 +0,0 @@
-@import '../../components/variables.css';
-
-.root {
- width: 100vw;
- height: 100vh;
-}
-
-.bgImage {
- position: fixed;
- width: 100vw;
- height: 100vh;
- background: url('/img/offley_2560.jpg');
- background-size: cover;
- background-position-x: 54%;
- background-position-y: 66%;
- background-color: #c1c1c1;
- filter: grayscale(1) brightness(0.4);
- z-index: -1;
- transition: filter ease-in-out 0.5s;
-}
-
-.container {
- padding-top: 50px;
- margin: 0 20px;
-}
-
-.headings {
- max-width: 640px;
- margin: 0 auto 40px;
- text-align: center;
- color: #fff;
- text-shadow: 3px 3px 8px var(--colour-nearblack);
- font-size: 1.3em;
-}
-
-.headings h1 {
- margin: 0 0 10px;
-}
-
-.subheading {
- font-family: var(--font-family-cursive);
-}
-
-.content {
- max-width: 960px;
- margin: 0 auto;
- color: #fff;
- text-shadow: 1px 1px 4px var(--colour-nearblack);
-}
diff --git a/src/routes/reception/Reception.js b/src/routes/reception/Reception.js
deleted file mode 100644
index f5c4923..0000000
--- a/src/routes/reception/Reception.js
+++ /dev/null
@@ -1,66 +0,0 @@
-import React from 'react';
-import withStyles from 'isomorphic-style-loader/lib/withStyles';
-import s from './Reception.css';
-import Map from '../../components/Map';
-
-const offley = {
- title: 'Offley Place',
- url: 'http://www.offleyplace.com/',
- position: {
- lat: 51.9282,
- lng: -0.3332,
- },
- showInfo: true,
-};
-
-class Reception extends React.Component {
- render() {
- return (
-
-
-
-
-
Offley Place
- Kings Walden Road
- Great Offley
- Hitchin
- SG5 3DX
-
-
-
When
-
The Reception will begin at 3pm, Wedding Breakfast at 5pm
- followed by music until late.
-
Where
-
The venue is approximately a 30 minute drive from the Church.
-
-
About Offley Place
-
Legend has it that in the 8th century, King Offa discovered the bones of
- Saint Alban and set about creating St Albans Abbey in a tribute to him.
- While it was being completed he looked for a place to call home and
- discovered the local area. After building a grand palace the village is
- thought to have become known as Great Off Lee.
-
Great Offley Place was first built in the 17th century. Rebuilt in 1810
- but still retaining a Tudor porch and a 17th century wing, the grand house
- has a long history which has seen the same family line keep ownership for
- an impressive 350 years.
-
In 1929 the family ownership was brought to an end when the last owner,
- Guy George, sold the estate to a director of WH Smith who was well liked
- in the village and built a cricket pavilion and pitch.
-
When World War II broke out it was sold again, this time to become a
- teacher training college, and then finally in 2003 it was taken over again
- and transformed into the luxury hotel, wedding venue and restaurant it
- is today.
-
-
-
- );
- }
-}
-
-export default withStyles(s)(Reception);
diff --git a/src/routes/reception/index.js b/src/routes/reception/index.js
deleted file mode 100644
index dafa054..0000000
--- a/src/routes/reception/index.js
+++ /dev/null
@@ -1,15 +0,0 @@
-import React from 'react';
-import Reception from './Reception';
-import Layout from '../../components/Layout';
-
-export default {
-
- path: '/venue',
-
- action() {
- return {
- title: 'Offley Place',
- component: ,
- };
- },
-};
diff --git a/src/routes/rsvp/Rsvp.css b/src/routes/rsvp/Rsvp.css
deleted file mode 100644
index da7536b..0000000
--- a/src/routes/rsvp/Rsvp.css
+++ /dev/null
@@ -1,55 +0,0 @@
-@import '../../components/variables.css';
-
-.root {
- width: 100vw;
- height: 100vh;
-}
-
-.bgImage {
- position: fixed;
- width: 100vw;
- height: 100vh;
- background: url('/img/cervenalhota_2560.jpg');
- background-size: cover;
- background-position-x: 30%;
- background-position-y: 66%;
- background-color: #c1c1c1;
- filter: grayscale(1) brightness(0.6);
- z-index: -1;
- transition: filter ease-in-out 0.5s;
-}
-
-.bgImageFocus {
- filter: grayscale(0.4) brightness(0.8);
-}
-
-.container {
- padding-top: 5vh;
- margin: 0 20px;
- text-align: center;
-}
-
-.heading {
- font-family: var(--font-family-cursive);
- text-align: center;
- margin-top: 0;
- font-size: 4em;
- color: #fff;
- text-shadow: 2px 2px 6px var(--colour-nearblack);
-}
-
-.flexContainer {
- display: flex;
- flex-flow: row wrap;
- justify-content: space-around;
-}
-
-.notes {
- display: inline-block;
- margin: 0 auto 40px;
- padding: 0 15px;
- border: 3px solid #fff;
- border-radius: 14px;
- background-color: rgba(0, 0, 0, 0.4);
- color: #fff;
-}
diff --git a/src/routes/rsvp/Rsvp.js b/src/routes/rsvp/Rsvp.js
deleted file mode 100644
index 33c8a3f..0000000
--- a/src/routes/rsvp/Rsvp.js
+++ /dev/null
@@ -1,63 +0,0 @@
-import React, { PropTypes } from 'react';
-import withStyles from 'isomorphic-style-loader/lib/withStyles';
-import s from './Rsvp.css';
-import RsvpCard from '../../components/RsvpCard';
-
-class Rsvp extends React.Component {
- static propTypes = {
- title: PropTypes.string.isRequired,
- people: PropTypes.arrayOf(PropTypes.shape({
- firstname: PropTypes.string,
- lastname: PropTypes.string,
- email: PropTypes.string,
- ceremony: PropTypes.boolean,
- dietary: PropTypes.string,
- starter: PropTypes.string,
- main: PropTypes.string,
- enddate: PropTypes.string,
- })).isRequired,
- rsvpEnd: PropTypes.string.isRequired,
- isEditable: PropTypes.bool.isRequired,
- };
-
- constructor(props) {
- super(props);
- this.state = {};
- }
-
- focusCallback = () => {
- this.setState({ focusBgImage: focus });
- }
-
- render() {
- return (
-
-
-
-
Odpovezte prosím
-
- {this.props.people.map(person => (
-
- ))}
-
-
-
Changes are automatically saved.
- You can modify the above details up until {this.props.rsvpEnd}
-
-
-
- );
- }
-}
-
-export default withStyles(s)(Rsvp);
diff --git a/src/routes/rsvp/index.js b/src/routes/rsvp/index.js
deleted file mode 100644
index 47daac8..0000000
--- a/src/routes/rsvp/index.js
+++ /dev/null
@@ -1,55 +0,0 @@
-import React from 'react';
-import Layout from '../../components/Layout';
-import fetchQL from '../../core/fetchQL';
-import Rsvp from './Rsvp';
-import NotFound from '../notFound/NotFound';
-import { prettifyDate } from '../../config';
-
-let title = 'RSVP';
-export default {
-
- path: '/rsvp/:password',
-
- isEditable(date) {
- return new Date() < new Date(date);
- },
-
- async action({ params }) {
- if (!params.password) {
- return { redirect: '/' };
- }
-
- const resp = await fetchQL('{getPersonsByPassword{key,firstname,lastname,attending,ceremony,dietary,starter,main,enddate}}', {
- password: params.password,
- });
-
- const { data } = await resp.json();
- const people = data && data.getPersonsByPassword;
- if (!people || people.length === 0) {
- title = 'RSVP Not Found';
- return {
- title,
- component: ,
- status: 404,
- };
- }
-
- // Assuming all connected guests have the same invite
- const firstDate = people[0].enddate;
-
- return {
- title,
- component: (
-
-
-
- ),
- };
- },
-
-};
diff --git a/src/routes/transport/Transport.css b/src/routes/transport/Transport.css
deleted file mode 100644
index 5665593..0000000
--- a/src/routes/transport/Transport.css
+++ /dev/null
@@ -1,55 +0,0 @@
-@import '../../components/variables.css';
-
-.root {
- width: 100vw;
- height: 100vh;
-}
-
-.bgImage {
- position: fixed;
- width: 100vw;
- height: 100vh;
- background: url('/img/offley_2560.jpg');
- background-size: cover;
- background-position-x: 54%;
- background-position-y: 66%;
- background-color: #c1c1c1;
- filter: grayscale(1) brightness(0.4);
- z-index: -1;
- transition: filter ease-in-out 0.5s;
-}
-
-.container {
- padding-top: 50px;
- margin: 0 20px;
-}
-
-.headings {
- max-width: 640px;
- margin: 0 auto 40px;
- text-align: center;
- color: #fff;
- text-shadow: 3px 3px 8px var(--colour-nearblack);
- font-size: 1.3em;
-}
-
-.headings h1 {
- margin: 0 0 10px;
-}
-
-.content {
- max-width: 960px;
- margin: 0 auto;
- color: #fff;
- text-shadow: 1px 1px 4px var(--colour-nearblack);
-}
-
-.tel {
- color: rgba(255, 255, 255, 0.8);
- transition: color 0.3s ease-in;
-}
-
-.tel:hover,
-.tel:focus {
- color: rgba(255, 255, 255, 1);
-}
diff --git a/src/routes/transport/Transport.js b/src/routes/transport/Transport.js
deleted file mode 100644
index d6fc752..0000000
--- a/src/routes/transport/Transport.js
+++ /dev/null
@@ -1,84 +0,0 @@
-import React from 'react';
-import withStyles from 'isomorphic-style-loader/lib/withStyles';
-import s from './Transport.css';
-import Map from '../../components/Map';
-
-const offley = {
- title: 'Offley Place',
- url: 'http://www.offleyplace.com/',
- position: {
- lat: 51.9282,
- lng: -0.3332,
- },
- showInfo: true,
-};
-
-const stations = [
- {
- title: 'Hitchin',
- position: {
- lat: 51.9532,
- lng: -0.2655,
- },
- },
- {
- title: 'Luton',
- position: {
- lat: 51.8820,
- lng: -0.4171,
- },
- },
- {
- title: 'Luton Airport Parkway',
- position: {
- lat: 51.8724,
- lng: -0.3984,
- },
- },
-];
-
-class Transport extends React.Component {
- constructor(props) {
- super(props);
- this.markers = [offley].concat(stations);
- }
- render() {
- return (
-
-
-
-
-
Transport
-
-
-
Train
-
There are 3 stations nearby, Hitchin, Luton and Luton Parkway (Airport).
- All trains terminate at London St Pancras or London Kings Cross
-
-
Car
-
Offley Place has secure parking facilities.
-
Taxi
-
The following taxi companies are recommended:
-
-
-
-
- );
- }
-}
-
-export default withStyles(s)(Transport);
diff --git a/src/routes/transport/index.js b/src/routes/transport/index.js
deleted file mode 100644
index edc0e79..0000000
--- a/src/routes/transport/index.js
+++ /dev/null
@@ -1,15 +0,0 @@
-import React from 'react';
-import Transport from './Transport';
-import Layout from '../../components/Layout';
-
-export default {
-
- path: '/transport',
-
- action() {
- return {
- title: 'Transport',
- component: ,
- };
- },
-};
diff --git a/src/server.js b/src/server.js
deleted file mode 100644
index f69725c..0000000
--- a/src/server.js
+++ /dev/null
@@ -1,428 +0,0 @@
-import 'babel-polyfill';
-import path from 'path';
-import express from 'express';
-import cookieParser from 'cookie-parser';
-import bodyParser from 'body-parser';
-import expressJwt from 'express-jwt';
-import expressGraphQL from 'express-graphql';
-import jwt from 'jsonwebtoken';
-import React from 'react';
-import ReactDOM from 'react-dom/server';
-import UniversalRouter from 'universal-router';
-import PrettyError from 'pretty-error';
-import Bouncer from 'express-bouncer';
-import App from './components/App';
-import Html from './components/Html';
-import { ErrorPageWithoutStyle } from './routes/error/ErrorPage';
-import errorPageStyle from './routes/error/ErrorPage.css';
-import passport from './core/passport';
-import admin from './core/admin';
-import models from './data/models';
-import schema from './data/schema';
-import routes from './routes';
-import assets from './assets'; // eslint-disable-line import/no-unresolved
-import { port, auth, starters, mains, exportApiKey } from './config';
-import Person from './data/models/Person';
-import Settings from './data/models/Settings';
-import Rollbar from './core/rollbar';
-import { sendSlackMsg, sendSlackMsgWithDebounce } from './core/slack';
-import sequelize from './data/sequelize';
-import { sendRSVPEmailWithDebounce } from './core/emailer';
-
-const app = express();
-
-Rollbar.init();
-const bouncer = Bouncer(10 * 60 * 1000, 60 * 60 * 1000, 5);
-bouncer.blocked = (req, res, next, remaining) => {
- let time = Math.ceil(remaining / 1000);
- let suffix = 'seconds';
- if (time > 120) {
- time = Math.ceil(time / 60);
- suffix = 'minutes';
- }
- const body = `You have made too many incorrect attempts. Please wait ${time} ${suffix}.`;
- const uAgent = req.headers['user-agent'];
- const ip = req.headers['x-forwarded-for'];
- sendSlackMsg(`Bouncer block\nIP address: ${ip}\nUser agent: ${uAgent}\nDuration: ${time} ${suffix}`, '#wedding-site');
- res.status(429).send(body);
-};
-
-// Tell any CSS tooling (such as Material UI) to use all vendor prefixes if the
-// user agent is not known.
-// -----------------------------------------------------------------------------
-global.navigator = global.navigator || {};
-global.navigator.userAgent = global.navigator.userAgent || 'all';
-
-//
-// Register Node.js middleware
-// -----------------------------------------------------------------------------
-app.use(express.static(path.join(__dirname, 'public')));
-app.use(cookieParser());
-app.use(bodyParser.urlencoded({ extended: true }));
-app.use(bodyParser.json());
-
-//
-// Authentication
-// -----------------------------------------------------------------------------
-app.use(expressJwt({
- secret: auth.jwt.secret,
- credentialsRequired: false,
- getToken: req => req.cookies.id_token,
-}));
-app.use(passport.initialize());
-
-if (process.env.NODE_ENV !== 'production') {
- app.enable('trust proxy');
-}
-app.get('/login/facebook',
- passport.authenticate('facebook', { scope: ['email', 'user_location'], session: false }),
-);
-app.get('/login/facebook/return',
- passport.authenticate('facebook', { failureRedirect: '/login', session: false }),
- (req, res) => {
- const expiresIn = 60 * 60 * 24 * 180; // 180 days
- const token = jwt.sign(req.user, auth.jwt.secret, { expiresIn });
- res.cookie('id_token', token, { maxAge: 1000 * expiresIn, httpOnly: true });
- res.redirect('/');
- },
-);
-
-//
-// Register API middleware
-// -----------------------------------------------------------------------------
-app.use('/graphql', expressGraphQL(req => ({
- schema,
- graphiql: process.env.NODE_ENV !== 'production',
- rootValue: { request: req },
- pretty: process.env.NODE_ENV !== 'production',
-})));
-
-//
-// Register RSVP routes
-// -----------------------------------------------------------------------------
-// TODO: This could do with cleaning up, to prevent duplicate bouncer tests and Person queries
-
-app.get('/:code', bouncer.block, (req, res, next) => {
- try {
- // Hijack router to test if url is a RSVP code
- if (req.params.code.length === 4) {
- // Possibly a password
- Person.findAll({ where: { password: req.params.code } })
- .then(data => {
- if (data.length > 0) {
- // It is a password
- bouncer.reset(req);
- res.redirect(`/rsvp/${req.params.code}`);
- } else {
- next();
- }
- }).catch((err) => {
- Rollbar.handleError(err);
- next(err);
- });
- } else {
- bouncer.reset(req);
- next();
- }
- } catch (err) {
- Rollbar.handleError(err);
- next(err);
- }
-});
-
-app.post('/rsvp', (req, res) => {
- res.redirect(`/rsvp/${req.body.code}`);
-});
-
-app.get('/rsvp/:code', bouncer.block, (req, res, next) => {
- Person.findAll({ where: { password: req.params.code } })
- .then(data => {
- if (data.length > 0) {
- bouncer.reset(req);
- }
- next();
- }).catch((err) => {
- Rollbar.handleError(err);
- next(err);
- });
-});
-
-app.post('/rsvp/save', (req, res) => {
- try {
- Person.findOne({
- where: { key: req.body.key },
- }).then(data => {
- const endDate = new Date(data.enddate);
- if (new Date() < endDate) {
- const update = {};
- update[req.body.prop] = req.body.value;
- return Person.update(update, {
- where: {
- key: req.body.key,
- },
- }).then(() => {
- if (data.completed) {
- const attending = `\nAttending: ${data.attending ? 'Yes' : 'No'}`;
- const starter = (data.attending && data.starter !== -1) ? `\nStarter: ${starters[data.starter]}` : '';
- const main = (data.attending && data.main !== -1) ? `\nMain: ${mains[data.main]}` : '';
- const dietary = (data.attending && data.dietary) ? `\nDietary requirements: ${data.dietary}` : '';
- sendSlackMsgWithDebounce(`${data.firstname} ${data.lastname} has saved their RSVP:${attending}${starter}${main}${dietary}`, '#wedding-rsvps', req.body.key);
- sendRSVPEmailWithDebounce(data);
- }
- return res.json({
- success: true,
- prop: req.body.prop,
- });
- }).catch(err => {
- Rollbar.handleError(err);
- res.json({
- success: false,
- err,
- });
- });
- }
- return res.json({
- success: false,
- err: 'RSVP end date has elapsed',
- });
- }).catch(err => {
- Rollbar.handleError(err);
- res.json({
- success: false,
- err,
- });
- });
- } catch (err) {
- Rollbar.handleError(err);
- res.json({
- success: false,
- err,
- });
- }
-});
-
-//
-// Register Admin routes
-// -----------------------------------------------------------------------------
-//
-
-app.get('/login', (req, res, next) => {
- try {
- if (req.user && admin(req.user.email)) {
- res.redirect('/admin');
- } else {
- next();
- }
- } catch (err) {
- Rollbar.handleError(err);
- next(err);
- }
-});
-
-app.use('/admin*', (req, res, next) => {
- try {
- // Allow if api key is valid and path is /admin/people/export
- if (req.headers['x-api-key'] === exportApiKey && req.originalUrl === '/admin/people/export') {
- next();
- } else if (!req.user || !admin(req.user.email)) {
- res.redirect(401, '/login');
- } else {
- next();
- }
- } catch (err) {
- Rollbar.handleError(err);
- next(err);
- }
-});
-
-app.post('/admin/person', (req, res, next) => {
- try {
- const data = {
- firstname: req.body.firstname,
- lastname: req.body.lastname,
- email: req.body.email,
- ceremony: req.body.ceremony,
- enddate: new Date(req.body.enddate),
- };
-
- if (req.body.password && req.body.password !== '') {
- data.password = req.body.password;
- }
- let promise;
- if (req.body.key) {
- promise = Person.update(data, {
- where: { key: req.body.key },
- });
- } else {
- promise = Person.create(data);
- }
- promise.then(() => {
- res.redirect('/admin/people');
- }).catch(err => {
- Rollbar.handleError(err);
- next(err);
- });
- } catch (err) {
- Rollbar.handleError(err);
- next(err);
- }
-});
-
-app.post('/admin/person/delete', (req, res, next) => {
- try {
- if (req.body.key) {
- Person.destroy({
- where: { key: req.body.key },
- }).then(() => {
- res.redirect('/admin/people');
- });
- }
- } catch (err) {
- Rollbar.handleError(err);
- next(err);
- }
-});
-
-app.get('/admin/people/export', (req, res, next) => {
- try {
- Person.findAll()
- .then(data => {
- res.json(data);
- })
- .catch(err => {
- Rollbar.handleError(err);
- next(err);
- });
- } catch (err) {
- Rollbar.handleError(err);
- next(err);
- }
-});
-
-app.post('/admin/people/import', (req, res, next) => {
- try {
- if (req.body.importdata && req.body.importdata.length > 0) {
- const data = JSON.parse(req.body.importdata);
- Person.destroy({ where: {} }).then(() => {
- const promises = [];
- data.map(person => promises.push(Person.create(person)));
- sequelize.Promise.all(promises).then(() => {
- res.redirect(201, '/admin/people');
- });
- }).catch(err => {
- Rollbar.handleError(err);
- next(err);
- });
- } else {
- res.redirect(400, '/admin/people');
- }
- } catch (err) {
- Rollbar.handleError(err);
- next(err);
- }
-});
-
-app.post('/admin/settings', (req, res, next) => {
- try {
- Settings.destroy({ where: {} }).then(() => {
- const settings = {
- slack: !!req.body.slack,
- email: !!req.body.email,
- };
- Settings.create(settings).then(() => {
- res.redirect(201, '/admin');
- }).catch(err => {
- Rollbar.handleError(err);
- next(err);
- });
- }).catch(err => {
- Rollbar.handleError(err);
- next(err);
- });
- } catch (err) {
- Rollbar.handleError(err);
- next(err);
- }
-});
-
-
-//
-// Register server-side rendering middleware
-// -----------------------------------------------------------------------------
-app.get('*', async (req, res, next) => {
- try {
- const css = new Set();
- // Global (context) variables that can be easily accessed from any React component
- // https://facebook.github.io/react/docs/context.html
- const context = {
- // Enables critical path CSS rendering
- // https://github.com/kriasoft/isomorphic-style-loader
- insertCss: (...styles) => {
- // eslint-disable-next-line no-underscore-dangle
- styles.forEach(style => css.add(style._getCss()));
- },
- };
- const route = await UniversalRouter.resolve(routes, {
- path: req.path,
- query: req.query,
- agent: req.headers['user-agent'],
- });
-
- if (route.redirect) {
- res.redirect(route.status || 302, route.redirect);
- return;
- }
-
- const data = { ...route };
- data.children = ReactDOM.renderToString({route.component} );
- data.style = [...css].join('');
- data.scripts = [
- assets.vendor.js,
- assets.client.js,
- ];
- if (assets[route.chunk]) {
- data.scripts.push(assets[route.chunk].js);
- }
-
- const html = ReactDOM.renderToStaticMarkup(