├── client
├── src
│ ├── utils
│ │ ├── data.jsx
│ │ ├── restClient.js
│ │ └── MapContainer.js
│ ├── index.css
│ ├── img
│ │ ├── home.jpg
│ │ ├── carousel.png
│ │ ├── ceremony.jpg
│ │ ├── greetings.jpg
│ │ └── testimonial.jpg
│ ├── App.test.js
│ ├── css
│ │ ├── navigationBar.css
│ │ ├── main.css
│ │ ├── greetings.css
│ │ ├── RSVP.css
│ │ ├── home.css
│ │ └── ceremony.css
│ ├── index.js
│ ├── components
│ │ ├── Location.jsx
│ │ ├── Home.jsx
│ │ ├── Ceremony.jsx
│ │ ├── NavigationBar.jsx
│ │ ├── Greetings.jsx
│ │ └── RSVP.jsx
│ ├── App.css
│ ├── App.js
│ ├── logo.svg
│ ├── ReactScrollableAnchor.js
│ └── registerServiceWorker.js
├── run_dev.sh
├── build
│ ├── home.jpg
│ ├── favicon.ico
│ ├── static
│ │ └── media
│ │ │ ├── home.1f400a9e.jpg
│ │ │ ├── greetings.bfd7a3df.jpg
│ │ │ ├── glyphicons-halflings-regular.e18bbf61.ttf
│ │ │ ├── glyphicons-halflings-regular.f4769f9b.eot
│ │ │ ├── glyphicons-halflings-regular.fa277232.woff
│ │ │ ├── glyphicons-halflings-regular.448c34a5.woff2
│ │ │ ├── logo.5d5d9eef.svg
│ │ │ └── glyphicons-halflings-regular.89889688.svg
│ ├── manifest.json
│ ├── index.html
│ ├── asset-manifest.json
│ └── service-worker.js
├── public
│ ├── home.jpg
│ ├── favicon.ico
│ ├── manifest.json
│ └── index.html
├── .gitignore
└── package.json
├── .gitignore
├── Procfile
├── app.db
├── app.test.db
├── requirements.txt
├── test.py
├── README.md
└── app.py
/client/src/utils/data.jsx:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /venv
2 | /__pycache__
3 |
--------------------------------------------------------------------------------
/Procfile:
--------------------------------------------------------------------------------
1 |
2 | web: gunicorn app:app
3 |
--------------------------------------------------------------------------------
/app.db:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liranfar/flask-react-on-heroku/HEAD/app.db
--------------------------------------------------------------------------------
/app.test.db:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liranfar/flask-react-on-heroku/HEAD/app.test.db
--------------------------------------------------------------------------------
/client/run_dev.sh:
--------------------------------------------------------------------------------
1 | export REACT_APP_USERS_SERVICE_URL=http://localhost:8000
2 | npm start
3 |
--------------------------------------------------------------------------------
/client/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: sans-serif;
5 | }
6 |
--------------------------------------------------------------------------------
/client/build/home.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liranfar/flask-react-on-heroku/HEAD/client/build/home.jpg
--------------------------------------------------------------------------------
/client/public/home.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liranfar/flask-react-on-heroku/HEAD/client/public/home.jpg
--------------------------------------------------------------------------------
/client/src/img/home.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liranfar/flask-react-on-heroku/HEAD/client/src/img/home.jpg
--------------------------------------------------------------------------------
/client/build/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liranfar/flask-react-on-heroku/HEAD/client/build/favicon.ico
--------------------------------------------------------------------------------
/client/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liranfar/flask-react-on-heroku/HEAD/client/public/favicon.ico
--------------------------------------------------------------------------------
/client/src/img/carousel.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liranfar/flask-react-on-heroku/HEAD/client/src/img/carousel.png
--------------------------------------------------------------------------------
/client/src/img/ceremony.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liranfar/flask-react-on-heroku/HEAD/client/src/img/ceremony.jpg
--------------------------------------------------------------------------------
/client/src/img/greetings.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liranfar/flask-react-on-heroku/HEAD/client/src/img/greetings.jpg
--------------------------------------------------------------------------------
/client/src/img/testimonial.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liranfar/flask-react-on-heroku/HEAD/client/src/img/testimonial.jpg
--------------------------------------------------------------------------------
/client/build/static/media/home.1f400a9e.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liranfar/flask-react-on-heroku/HEAD/client/build/static/media/home.1f400a9e.jpg
--------------------------------------------------------------------------------
/client/build/static/media/greetings.bfd7a3df.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liranfar/flask-react-on-heroku/HEAD/client/build/static/media/greetings.bfd7a3df.jpg
--------------------------------------------------------------------------------
/client/build/static/media/glyphicons-halflings-regular.e18bbf61.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liranfar/flask-react-on-heroku/HEAD/client/build/static/media/glyphicons-halflings-regular.e18bbf61.ttf
--------------------------------------------------------------------------------
/client/build/static/media/glyphicons-halflings-regular.f4769f9b.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liranfar/flask-react-on-heroku/HEAD/client/build/static/media/glyphicons-halflings-regular.f4769f9b.eot
--------------------------------------------------------------------------------
/client/build/static/media/glyphicons-halflings-regular.fa277232.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liranfar/flask-react-on-heroku/HEAD/client/build/static/media/glyphicons-halflings-regular.fa277232.woff
--------------------------------------------------------------------------------
/client/build/static/media/glyphicons-halflings-regular.448c34a5.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liranfar/flask-react-on-heroku/HEAD/client/build/static/media/glyphicons-halflings-regular.448c34a5.woff2
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | click==6.7
2 | Flask==1.0.2
3 | Flask-Cors==3.0.4
4 | Flask-SQLAlchemy==2.3.2
5 | gunicorn==19.8.1
6 | itsdangerous==0.24
7 | Jinja2==2.10
8 | MarkupSafe==1.0
9 | psycopg2==2.7.4
10 | six==1.11.0
11 | SQLAlchemy==1.2.8
12 | Werkzeug==0.14.1
13 |
--------------------------------------------------------------------------------
/client/src/App.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import App from './App';
4 |
5 | it('renders without crashing', () => {
6 | const div = document.createElement('div');
7 | ReactDOM.render(, div);
8 | ReactDOM.unmountComponentAtNode(div);
9 | });
10 |
--------------------------------------------------------------------------------
/client/src/css/navigationBar.css:
--------------------------------------------------------------------------------
1 | #navigation-bar {
2 | font-family: 'EB Garamond',serif;
3 | margin-bottom: 0;
4 | border-radius: 0px;
5 | background-color: white;
6 | border-color: green;
7 |
8 | }
9 |
10 | #navigation-bar li a:hover, #navigation-bar li a:visited , #navigation-bar li a:focus {
11 | color:black;
12 | }
13 |
--------------------------------------------------------------------------------
/client/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 |
6 | # testing
7 | /coverage
8 |
9 | # production
10 | # /build
11 |
12 | # misc
13 | .DS_Store
14 | .env.local
15 | .env.development.local
16 | .env.test.local
17 | .env.production.local
18 |
19 | npm-debug.log*
20 | yarn-debug.log*
21 | yarn-error.log*
22 |
--------------------------------------------------------------------------------
/client/build/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | }
10 | ],
11 | "start_url": "./index.html",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
16 |
--------------------------------------------------------------------------------
/client/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | }
10 | ],
11 | "start_url": "./index.html",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
16 |
--------------------------------------------------------------------------------
/client/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import './index.css';
4 | import App from './App';
5 | import registerServiceWorker from './registerServiceWorker';
6 | import ReactScrollableAnchor from './ReactScrollableAnchor';
7 | // ReactDOM.render(, document.getElementById('root'));
8 | ReactDOM.render(, document.getElementById('root'));
9 | registerServiceWorker();
10 |
--------------------------------------------------------------------------------
/client/src/components/Location.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import MapContainer from '../utils/MapContainer'
3 | import ScrollableAnchor from 'react-scrollable-anchor'
4 | export default props => {
5 | const { id } = props
6 | return
7 |
12 |
13 | }
--------------------------------------------------------------------------------
/client/src/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | text-align: center;
3 | }
4 |
5 | .App-logo {
6 | animation: App-logo-spin infinite 20s linear;
7 | height: 80px;
8 | }
9 |
10 | .App-header {
11 | background-color: #222;
12 | height: 150px;
13 | padding: 20px;
14 | color: white;
15 | }
16 |
17 | .App-title {
18 | font-size: 1.5em;
19 | }
20 |
21 | .App-intro {
22 | font-size: large;
23 | }
24 |
25 | @keyframes App-logo-spin {
26 | from { transform: rotate(0deg); }
27 | to { transform: rotate(360deg); }
28 | }
29 |
--------------------------------------------------------------------------------
/client/build/index.html:
--------------------------------------------------------------------------------
1 |
Gili & Matan - The Wedding
--------------------------------------------------------------------------------
/client/src/utils/restClient.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios'
2 |
3 | export default (logMessage) => {
4 | console.log(logMessage);
5 | axios.get(`${process.env.REACT_APP_USERS_SERVICE_URL}/users/ping`, {
6 | // params :{
7 | // dataType: 'json'
8 | // }
9 | })
10 | .then(function (response) {
11 | console.log('SUCCESS', response)
12 | })
13 | .catch(function (error) {
14 | console.log('ERROR', error)
15 | });
16 | }
17 |
--------------------------------------------------------------------------------
/client/src/components/Home.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ScrollableAnchor from 'react-scrollable-anchor'
3 | import '../css/home.css'
4 | export default (props) => {
5 | const { id } = props;
6 | return
7 |
8 |
9 |
10 |
11 |
Gili & Matan
12 | Are getting
13 | MARRIED!
14 |
15 |
16 |
17 |
18 |
19 | }
--------------------------------------------------------------------------------
/client/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "client",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "axios": "^0.18.0",
7 | "bootstrap": "^3.3.7",
8 | "google-maps-react": "^2.0.2",
9 | "react": "^16.4.0",
10 | "react-bootstrap": "^0.32.1",
11 | "react-dom": "^16.4.0",
12 | "react-full-page": "^0.1.4",
13 | "react-scripts": "1.1.4",
14 | "react-scrollable-anchor": "^0.6.1"
15 | },
16 | "scripts": {
17 | "start": "react-scripts start",
18 | "build": "react-scripts build",
19 | "test": "react-scripts test --env=jsdom",
20 | "eject": "react-scripts eject"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/client/src/css/main.css:
--------------------------------------------------------------------------------
1 | div.line {
2 | position: absolute;
3 | z-index: 4;
4 | top: -26px;
5 | left: 0;
6 | width: 100%;
7 | height: 24px;
8 | background-color: #a4c956;
9 | }
10 |
11 | div.line:before {
12 | content: '';
13 | position: absolute;
14 | top: -3px;
15 | left: 0;
16 | width: 100%;
17 | height: 3px;
18 | background-color: #b9d57d;
19 | }
20 |
21 | div.line:after {
22 | content: '';
23 | position: absolute;
24 | bottom: -3px;
25 | left: 0;
26 | width: 100%;
27 | height: 3px;
28 | background-color: #b9d57d;
29 | }
30 |
31 | div.line-bottom {
32 | top: 97%;
33 | }
--------------------------------------------------------------------------------
/client/src/components/Ceremony.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import '../css/ceremony.css'
3 | import ScrollableAnchor from 'react-scrollable-anchor'
4 |
5 | export default props => {
6 | const { id } = props;
7 | return
8 |
9 |
10 |
11 |
12 |
13 |
The Ceremony
14 | Will Be Held On
15 | July 6, 2018
16 | 11:00 - Reception | 12:00 - Ceremony
17 |
18 |
19 |
20 |
21 |
22 |
23 | }
--------------------------------------------------------------------------------
/client/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import logo from './logo.svg';
3 | import './App.css';
4 | import handleClick from './utils/restClient';
5 |
6 | class App extends Component {
7 | constructor(){
8 | super();
9 |
10 | this.state = {};
11 | this.handleClick = handleClick.bind(this);
12 | }
13 |
14 | render() {
15 | return (
16 |
17 |
18 |
19 | Welcome to React
20 |
21 |
22 | To get started, edit src/App.js and save to reload.
23 |
24 |
31 |
32 | );
33 | }
34 | }
35 |
36 | export default App;
37 |
--------------------------------------------------------------------------------
/client/build/asset-manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "main.css": "static/css/main.f84a3ebb.css",
3 | "main.css.map": "static/css/main.f84a3ebb.css.map",
4 | "main.js": "static/js/main.b6a0aaa4.js",
5 | "main.js.map": "static/js/main.b6a0aaa4.js.map",
6 | "static/media/glyphicons-halflings-regular.eot": "static/media/glyphicons-halflings-regular.f4769f9b.eot",
7 | "static/media/glyphicons-halflings-regular.svg": "static/media/glyphicons-halflings-regular.89889688.svg",
8 | "static/media/glyphicons-halflings-regular.ttf": "static/media/glyphicons-halflings-regular.e18bbf61.ttf",
9 | "static/media/glyphicons-halflings-regular.woff": "static/media/glyphicons-halflings-regular.fa277232.woff",
10 | "static/media/glyphicons-halflings-regular.woff2": "static/media/glyphicons-halflings-regular.448c34a5.woff2",
11 | "static/media/greetings.jpg": "static/media/greetings.bfd7a3df.jpg",
12 | "static/media/home.jpg": "static/media/home.1f400a9e.jpg",
13 | "static/media/logo.svg": "static/media/logo.5d5d9eef.svg"
14 | }
--------------------------------------------------------------------------------
/client/src/components/NavigationBar.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {
3 | Navbar,
4 | Nav,
5 | NavItem,
6 | NavDropdown,
7 | MenuItem,
8 | Button
9 | } from 'react-bootstrap'
10 | import '../css/navigationBar.css'
11 |
12 | export default (props) => {
13 |
14 | const { brand,id } = props;
15 |
16 | return
17 |
18 |
19 | {brand}
20 |
21 |
22 |
23 |
24 |
41 |
42 |
43 |
44 |
45 |
46 | }
--------------------------------------------------------------------------------
/client/src/components/Greetings.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import '../css/greetings.css'
3 | import carousel_img from '../img/testimonial.jpg'
4 | import { Carousel } from 'react-bootstrap'
5 | import ScrollableAnchor from 'react-scrollable-anchor'
6 |
7 | export default (props) => {
8 | const greetings = props.greetings
9 | // const greetings = ['1', '2']
10 | const greeetingsElements = greetings.map((greeting, index) => {
11 | return
12 |
13 | {/*

*/}
14 |
15 |
16 |
{greeting.content}
17 | {/*
18 | {greeting.name} */}
19 |
20 |
21 |
22 |
23 |
24 | })
25 |
26 | return (
27 |
28 |
29 |
Greetings
30 |
31 | {greeetingsElements}
32 |
33 |
34 | );
35 |
36 |
37 | }
--------------------------------------------------------------------------------
/test.py:
--------------------------------------------------------------------------------
1 | from flask_testing import TestCase
2 | import json
3 | import unittest
4 | from app import db, app
5 |
6 |
7 | class BaseTestCase(TestCase):
8 | def create_app(self):
9 | app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///app.test.db'
10 | app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
11 | return app
12 |
13 | def setUp(self):
14 | db.create_all()
15 | db.session.commit()
16 |
17 | def tearDown(self):
18 | db.session.remove()
19 | db.drop_all()
20 |
21 |
22 | class TestRsvp(BaseTestCase):
23 | def test_rsvp_added(self):
24 | """Ensure the Rsvp has beed added succefully"""
25 | with self.client:
26 | response = self.client.post(
27 | '/rsvp',
28 | data=json.dumps({
29 | 'fullName': 'michael',
30 | 'email': 'michael@mherman.org',
31 | 'message': 'see you there!'
32 | }),
33 | content_type='application/json',
34 | )
35 | data = json.loads(response.data.decode())
36 | self.assertEqual(response.status_code, 201)
37 | self.assertIn('success', data['status'])
38 | self.assertIn('RSVP has been added', data['message'])
39 |
40 |
41 |
42 | if __name__ == '__main__':
43 | unittest.main()
--------------------------------------------------------------------------------
/client/src/css/greetings.css:
--------------------------------------------------------------------------------
1 | div#greetings {
2 | text-align: center;
3 | background-image: url(../img/greetings.jpg);
4 | height: 70vh;
5 | width: 100%;
6 | padding-top: 15px;
7 | padding-bottom: 50px;
8 | /* margin-bottom: 15px; */
9 | }
10 |
11 | .carousel {
12 | height: 75%;
13 | background-color: rgba(0,0,0,0.2);
14 | }
15 |
16 | div#greetings h1 {
17 | padding-bottom: 30px;
18 | font-size: 85px;
19 | line-height: 87px;
20 | font-weight: 700;
21 | color: #fff;
22 | text-shadow: 2px 1px 0 rgba(0,0,0,0.2);
23 | text-align: center;
24 | font-family: 'Dancing Script',cursive;
25 | }
26 |
27 | .testimonial {
28 | max-width: 850px;
29 | margin: 25px auto;
30 | padding: 0 20px;
31 | }
32 |
33 | .testimonial-avatar {
34 | /* width: 100px; */
35 | border-radius: 50%;
36 | }
37 |
38 | .testimonial-quote {
39 | display: block;
40 | font-size: 24px;
41 | font-weight: 300;
42 | padding: 45px 0px 0px 0px;
43 | position: relative;
44 | left: 0;
45 | right: 0;
46 | color: #fff;
47 | }
48 |
49 | ol li {
50 | background-color: black !important;
51 | }
52 | ol.carousel-indicators {
53 | bottom: 0px;
54 | display: none;
55 | }
56 |
57 | .carousel-control.right, .carousel-control.left {
58 | background-image: none;
59 | }
60 |
61 | p.message {
62 | margin: 30px 0 0 0;
63 | white-space: pre-line;
64 | }
--------------------------------------------------------------------------------
/client/src/utils/MapContainer.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import {Map, InfoWindow, Marker, GoogleApiWrapper} from 'google-maps-react';
3 |
4 | export class MapContainer extends Component {
5 | state = {
6 | showingInfoWindow: false,
7 | activeMarker: {},
8 | selectedPlace: {},
9 | };
10 |
11 | onMarkerClick = (props, marker, e) =>
12 | this.setState({
13 | selectedPlace: props,
14 | activeMarker: marker,
15 | showingInfoWindow: true
16 | });
17 |
18 | onMapClicked = (props) => {
19 | if (this.state.showingInfoWindow) {
20 | this.setState({
21 | showingInfoWindow: false,
22 | activeMarker: null
23 | })
24 | }
25 | };
26 |
27 | render() {
28 | return (
29 |
50 | );
51 | }
52 | }
53 |
54 | export default GoogleApiWrapper({
55 | apiKey: ('AIzaSyBtz1k5ufj6N8SEokFGuB3aCyZLD24n5P4')
56 | })(MapContainer)
57 |
--------------------------------------------------------------------------------
/client/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
11 |
12 |
13 |
22 | Gili & Matan - The Wedding
23 |
24 |
25 |
28 |
29 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # flask and react deployed on heroku
2 | a onepage react app served by flask & sqlite/postgres db, deployed easily on heroku.
3 |
4 | [Production ready example](https://gili-matan.herokuapp.com/)
5 |
6 | # Usage
7 |
8 | ### Local Development
9 | ```
10 | $ git clone...
11 | $ cd <>
12 | ```
13 |
14 | ### DB
15 | ```
16 | sudo -u postgres psql postgres
17 | ```
18 | ### Server
19 |
20 | ```
21 | $ virtualenv -p python3 venv
22 | $ pip install -r requirements.txt
23 | $ gunicorn app:app
24 | ```
25 |
26 | ### Client
27 | ```
28 | $ cd client
29 | $ npm install
30 | $ chmod +x run_dev.sh
31 | $ ./run_dev.sh
32 | ```
33 | To build client app comment out `process.env.REACT_APP_USERS_SERVICE_URL` and run : `npm run build`
34 |
35 | To check the build directory on a static server :
36 | ```
37 | $ cd build
38 | $ python3 -m http.server
39 | ```
40 |
41 | ### Deployment on heroku
42 | Disable flask-CORS
43 | ```
44 | $ heroku login ...
45 | $ heroku create
46 | $ heroku addons:add heroku-postgresql:hobby-dev
47 | $ heroku run python
48 | >>> import os
49 | >>> os.environ.get('DATABASE_URL')
50 | ```
51 | copy db_url to your app_config, and then:
52 | ```
53 | $ heroku git:remote
54 | $ git push heroku master
55 | $ heroku run python
56 | >>> from app import db
57 | >>> db.create_all()
58 | >>> exit()
59 | ```
60 |
61 | ## Resources
62 |
63 | 1. [static files in flask](https://stackoverflow.com/questions/20646822/how-to-serve-static-files-in-flask)
64 |
65 | 1. [python3 virtualenv](https://stackoverflow.com/questions/23842713/using-python-3-in-virtualenv)
66 |
67 | 1. [react-bootstrap](https://react-bootstrap.github.io/)
68 |
69 | 1. [react-scrollable-anchor](https://github.com/gabergg/react-scrollable-anchor)
70 |
71 | 1. [google-maps-react](https://github.com/fullstackreact/google-maps-react)
72 |
73 | 1. [Sahil Diwan - flask and postgres on heroku](http://blog.sahildiwan.com/posts/flask-and-postgresql-app-deployed-on-heroku/)
74 |
75 | 1. [Setting up flask app in heroku with a database](https://gist.github.com/mayukh18/2223bc8fc152631205abd7cbf1efdd41/)
76 |
77 | 1. [Testeimonials Carousel](https://codepen.io/jamy/pen/gbdWGJ)
--------------------------------------------------------------------------------
/client/src/css/RSVP.css:
--------------------------------------------------------------------------------
1 |
2 | section#rsvp {
3 | margin-bottom: 70px;
4 | }
5 |
6 | section#rsvp input[type=text].form-control, section#rsvp select.form-control,
7 | section#rsvp input[type=email].form-control,
8 | section#rsvp textarea.form-control {
9 | border-color: #ced4da!important;
10 | border-radius: 2px;
11 | color: #495057;
12 | font-family: Montserrat,sans-serif;
13 | /* font-size: .6875rem!important;
14 | font-weight: 600;
15 | letter-spacing: .0625rem!important;
16 | padding: .875rem 1rem; */
17 | }
18 |
19 | section#rsvp h3 {
20 | position: relative;
21 | font-family: 'EB Garamond',serif;
22 | font-size: 48px;
23 | line-height: 20px;
24 | font-weight: 400;
25 | color: grey;
26 | text-align: center;
27 | /* text-transform: capitalize; */
28 | letter-spacing: 5px;
29 | text-shadow: 2px 1px 0 rgba(0,0,0,0.25);
30 | margin-top: 50px;
31 | margin-bottom: 50px;
32 | }
33 |
34 | section#rsvp h4 {
35 | text-align: center;
36 | }
37 |
38 | section#rsvp button {
39 | margin-top: 3.5rem;
40 | background-color: #fff;
41 | background-image: none;
42 | -webkit-background-size: initial;
43 | -moz-background-size: initial;
44 | -ms-background-size: initial;
45 | -o-background-size: initial;
46 | background-size: initial;
47 | background-position: initial;
48 | background-repeat: no-repeat;
49 | background-attachment: initial;
50 | color: #999;
51 | border: 1px solid #bbb;
52 | -webkit-border-radius: 1px;
53 | -moz-border-radius: 1px;
54 | -ms-border-radius: 1px;
55 | -o-border-radius: 1px;
56 | border-radius: 1px;
57 | -webkit-transition: all .3s ease-in-out;
58 | -moz-transition: all .3s ease-in-out;
59 | -ms-transition: all .3s ease-in-out;
60 | -o-transition: all .3s ease-in-out;
61 | transition: all .3s ease-in-out;
62 | }
63 |
64 | section#rsvp button:hover {
65 | background-color: #aacd62;
66 | background-image: none;
67 | -webkit-background-size: initial;
68 | -moz-background-size: initial;
69 | -ms-background-size: initial;
70 | -o-background-size: initial;
71 | background-size: initial;
72 | background-position: initial;
73 | background-repeat: no-repeat;
74 | background-attachment: initial;
75 | border: 1px solid #8cb339;
76 | color: #fff;
77 | text-shadow: 0 -1px 0 #999;
78 | -webkit-transition: all .3s ease-in-out;
79 | -moz-transition: all .3s ease-in-out;
80 | -ms-transition: all .3s ease-in-out;
81 | -o-transition: all .3s ease-in-out;
82 | transition: all .3s ease-in-out;
83 | }
84 |
--------------------------------------------------------------------------------
/client/src/logo.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/client/src/css/home.css:
--------------------------------------------------------------------------------
1 | #home {
2 | position: relative;
3 | width: 100%;
4 | padding-top: 120px;
5 | padding-right: 0;
6 | padding-bottom: 140px;
7 | padding-left: 0;
8 | background-color: transparent;
9 | background-image: url(../img/home.jpg);
10 | -webkit-background-size: cover;
11 | -moz-background-size: cover;
12 | -ms-background-size: cover;
13 | -o-background-size: cover;
14 | background-size: cover;
15 | background-position: top center;
16 | background-repeat: no-repeat;
17 | background-attachment: initial;
18 | }
19 |
20 | #home h1 {
21 | padding-bottom: 30px;
22 | font-size: 85px;
23 | line-height: 87px;
24 | font-weight: 700;
25 | color: #fff;
26 | text-shadow: 2px 1px 0 rgba(0,0,0,0.2);
27 | text-align: center;
28 | font-family: 'Dancing Script',cursive;
29 | }
30 |
31 | #home h3{
32 | position: relative;
33 | font-family: 'EB Garamond',serif;
34 | font-size: 18px;
35 | line-height: 20px;
36 | font-weight: 400;
37 | color: #fff;
38 | text-align: center;
39 | text-transform: capitalize;
40 | letter-spacing: 5px;
41 | text-shadow: 2px 1px 0 rgba(0,0,0,0.25);
42 | }
43 |
44 | #home h3:before {
45 | content: "";
46 | position: absolute;
47 | z-index: 3px;
48 | left: 20%;
49 | top: 50%;
50 | height: 2px;
51 | width: 20%;
52 | margin-top: 0;
53 | background-color: #fff;
54 | background-image: none;
55 | -webkit-background-size: initial;
56 | -moz-background-size: initial;
57 | -ms-background-size: initial;
58 | -o-background-size: initial;
59 | background-size: initial;
60 | background-position: top center;
61 | background-repeat: no-repeat;
62 | background-attachment: initial;
63 | }
64 |
65 | #home h3:after {
66 | content: "";
67 | position: absolute;
68 | z-index: 3px;
69 | right: 20%;
70 | top: 50%;
71 | height: 2px;
72 | width: 20%;
73 | margin-top: 0;
74 | background-color: #fff;
75 | background-image: none;
76 | -webkit-background-size: initial;
77 | -moz-background-size: initial;
78 | -ms-background-size: initial;
79 | -o-background-size: initial;
80 | background-size: initial;
81 | background-position: top center;
82 | background-repeat: no-repeat;
83 | background-attachment: initial;
84 | }
85 |
86 | #home h2 {
87 | padding-top: 20px;
88 | font-family: 'Raleway',sans-serif;
89 | font-size: 120px;
90 | line-height: 122px;
91 | font-weight: 900;
92 | color: #a4c956;
93 | text-shadow: 8px 7px 0 rgba(164,201,86,0.35);
94 | text-align: center;
95 | }
--------------------------------------------------------------------------------
/client/build/static/media/logo.5d5d9eef.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/client/src/ReactScrollableAnchor.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import 'bootstrap/dist/css/bootstrap.min.css'
3 | import './css/main.css'
4 | import { Jumbotron } from 'react-bootstrap'
5 | import HomeSection from './components/Home'
6 | import Location from './components/Location'
7 | import NavigationBar from './components/NavigationBar'
8 | import Ceremony from './components/Ceremony'
9 | import RSVP from './components/RSVP'
10 | import axios from 'axios'
11 | import { configureAnchors } from 'react-scrollable-anchor'
12 | import Greetings from './components/Greetings'
13 | export default class Page extends Component {
14 |
15 | constructor() {
16 | super();
17 | this.state = {
18 | rsvpForm: {
19 | fullName: '',
20 | email: '',
21 | additionalInformation: '',
22 | guests: '',
23 | events: '',
24 | isRsvpSent: false
25 | },
26 | greetings: [],
27 | };
28 | this.handleRsvp = this.handleRsvp.bind(this);
29 | this.handleChange = this.handleChange.bind(this);
30 | }
31 |
32 |
33 | handleChange(event) {
34 | const obj = {};
35 | obj['rsvpForm'] = {...this.state.rsvpForm}
36 | obj['rsvpForm'][event.target.name] = event.target.value;
37 | this.setState(obj);
38 | };
39 |
40 | handleRsvp = (event) => {
41 | event.preventDefault();
42 | const data = {...this.state.rsvpForm}
43 |
44 | axios.post(`rsvp`, data)
45 | // axios.post(`${process.env.REACT_APP_USERS_SERVICE_URL}/rsvp`, data)
46 | .then((res) => {
47 | this.setState({rsvpForm: {fullName: '', email: '', additionalInformation: '', greeting: '', guests: '', events: '', isRsvpSent: true}});
48 | })
49 | .catch((err) => {
50 | console.log(err);
51 | });
52 | }
53 |
54 | getGreetings = () => {
55 | // axios.get(`${process.env.REACT_APP_USERS_SERVICE_URL}/greetings`)
56 | axios.get(`greetings`)
57 | .then((res) => {
58 | this.setState({greetings: res.data.data.greetings});
59 | })
60 | .catch((err) => {
61 | console.log(err);
62 | });
63 | }
64 |
65 | componentDidMount() {
66 | this.getGreetings();
67 | }
68 |
69 | render() {
70 | configureAnchors({scrollDuration: 1200})
71 | return (
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 | )
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/client/src/css/ceremony.css:
--------------------------------------------------------------------------------
1 | section#ceremony {
2 | position: relative;
3 | width: 100%;
4 | padding-top: 120px;
5 | padding-right: 0;
6 | padding-bottom: 140px;
7 | padding-left: 0;
8 | background-color: transparent;
9 | /* background-image: url(../img/ceremony.jpg); */
10 | -webkit-background-size: cover;
11 | -moz-background-size: cover;
12 | -ms-background-size: cover;
13 | -o-background-size: cover;
14 | background-size: cover;
15 | background-position: top center;
16 | background-repeat: no-repeat;
17 | background-attachment: initial;
18 | }
19 |
20 | section#ceremony h1 {
21 | padding-bottom: 30px;
22 | font-family: 'Dancing Script',cursive;
23 | font-size: 85px;
24 | line-height: 87px;
25 | font-weight: 700;
26 | color: #9D9D9D;
27 | text-shadow: 2px 1px 0 rgba(0,0,0,0.2);
28 | text-align: center;
29 | }
30 |
31 | section#ceremony h3 {
32 | position: relative;
33 | font-family: 'EB Garamond',serif;
34 | font-size: 18px;
35 | line-height: 20px;
36 | font-weight: 400;
37 | color: grey;
38 | text-align: center;
39 | text-transform: capitalize;
40 | letter-spacing: 5px;
41 | text-shadow: 2px 1px 0 rgba(0,0,0,0.25);
42 | }
43 |
44 | section#ceremony h3:before {
45 | content: "";
46 | position: absolute;
47 | z-index: 3px;
48 | left: 20%;
49 | top: 50%;
50 | height: 2px;
51 | width: 20%;
52 | margin-top: 0;
53 | background-color: #9D9D9D;
54 | background-image: none;
55 | -webkit-background-size: initial;
56 | -moz-background-size: initial;
57 | -ms-background-size: initial;
58 | -o-background-size: initial;
59 | background-size: initial;
60 | background-position: top center;
61 | background-repeat: no-repeat;
62 | background-attachment: initial;
63 | }
64 |
65 | section#ceremony h3:after {
66 | content: "";
67 | position: absolute;
68 | z-index: 3px;
69 | right: 20%;
70 | top: 50%;
71 | height: 2px;
72 | width: 20%;
73 | margin-top: 0;
74 | background-color: #9D9D9D;
75 | background-image: none;
76 | -webkit-background-size: initial;
77 | -moz-background-size: initial;
78 | -ms-background-size: initial;
79 | -o-background-size: initial;
80 | background-size: initial;
81 | background-position: top center;
82 | background-repeat: no-repeat;
83 | background-attachment: initial;
84 | }
85 |
86 | section#ceremony h2 {
87 | padding-top: 20px;
88 | font-family: 'Raleway',sans-serif;
89 | font-size: 120px;
90 | line-height: 122px;
91 | font-weight: 900;
92 | color: #a4c956;
93 | text-shadow: 8px 7px 0 rgba(164,201,86,0.35);
94 | text-align: center;
95 | }
96 |
97 | section#ceremony h4 {
98 | font-family: 'EB Garamond',serif;
99 | font-size: 30px;
100 | line-height: 24px;
101 | font-weight: 400;
102 | color: #9d9d9d;
103 | text-align: center;
104 | text-transform: capitalize;
105 | letter-spacing: 8px;
106 | margin-top: 70px;
107 | /* text-shadow: 2px 1px 0 rgba(0,0,0,0.4); */
108 | }
--------------------------------------------------------------------------------
/app.py:
--------------------------------------------------------------------------------
1 | from flask import Flask, request, jsonify
2 | from flask_cors import CORS
3 | from flask_sqlalchemy import SQLAlchemy
4 |
5 | # set the project root directory as the static folder, you can set others.
6 | app = Flask(__name__,
7 | static_url_path='',
8 | static_folder='client/build')
9 |
10 | # CORS(app)
11 |
12 | app.config['SQLALCHEMY_DATABASE_URI'] = 'postgres://hlavaovemabkqo:fbbedd28e5a4edddd45977b9640344393f93c409c0425f687d43fd97c174cd5f@ec2-54-225-96-191.compute-1.amazonaws.com:5432/ddell78uvtts4r'
13 | #app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://postgres:postgres@localhost/gili_matan_rsvp'
14 | app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
15 | db = SQLAlchemy(app)
16 |
17 | # Create our database model
18 | class Rsvp(db.Model):
19 | __tablename__ = "rsvps"
20 | id = db.Column(db.Integer, primary_key=True)
21 | full_name = db.Column(db.String(120), unique=True)
22 | email = db.Column(db.String(120), unique=True)
23 | additional_information = db.Column(db.String(255))
24 | greeting = db.Column(db.String(255))
25 | events = db.Column(db.String(255))
26 | guests = db.Column(db.Integer)
27 |
28 | def __init__(self,full_name, email, additional_information, greeting, events, guests):
29 | self.full_name = full_name
30 | self.email = email
31 | self.additional_information = additional_information
32 | self.greeting = greeting
33 | self.events = events
34 | self.guests = guests
35 |
36 | # def __repr__(self):
37 | # return '' % self.email
38 |
39 | def to_json(self):
40 | return {
41 | 'fullName': self.full_name,
42 | 'email': self.email,
43 | 'additional_information': self.additional_information,
44 | 'greeting': self.greeting,
45 | 'events':self. events,
46 | 'guests': self.guests,
47 | }
48 |
49 | @app.route('/')
50 | def root():
51 | return app.send_static_file('index.html')
52 |
53 | @app.route('/users/ping')
54 | def ping_pong():
55 | return jsonify({
56 | 'status': 'success',
57 | 'message': 'pong!'
58 | })
59 |
60 | @app.route('/rsvp', methods=['POST'])
61 | def rsvp():
62 | post_data = request.get_json()
63 | response_object = {
64 | 'status': 'fail',
65 | 'message': 'Invalid payload.'
66 | }
67 |
68 | full_name = post_data['fullName']
69 | email = post_data['email']
70 | additional_information = post_data['additionalInformation']
71 | greeting = post_data['greeting']
72 | events = post_data['events']
73 | guests = post_data['guests']
74 |
75 | if not db.session.query(Rsvp).filter(Rsvp.email == email).count():
76 | rsvp = Rsvp(full_name, email, additional_information, greeting, events, guests)
77 | db.session.add(rsvp)
78 | db.session.commit()
79 |
80 | response_object = {
81 | 'status': 'success',
82 | 'message': 'RSVP has been added'
83 | }
84 |
85 | return jsonify(response_object), 201
86 |
87 | return jsonify(response_object), 400
88 |
89 | @app.route('/greetings', methods=['GET'])
90 | def greetings():
91 | all_greetings = Rsvp.query.with_entities(Rsvp.full_name, Rsvp.greeting).all()
92 | response_object = {
93 | 'status': 'Success',
94 | 'data': {
95 | 'greetings': [{'name' : greeting[0], 'content':greeting[1]} for greeting in all_greetings]
96 | }
97 | }
98 |
99 | return jsonify(response_object), 200
100 |
101 | if __name__ == '__main__':
102 | app.run()
103 |
--------------------------------------------------------------------------------
/client/build/service-worker.js:
--------------------------------------------------------------------------------
1 | "use strict";var precacheConfig=[["/index.html","97a772728188eb4438f9df1bce8ef9a2"],["/static/css/main.f84a3ebb.css","cadeed5e6bd514b47f841a0956d6068e"],["/static/js/main.b6a0aaa4.js","8e8eadfac469dc494b410c3cc36225b5"],["/static/media/glyphicons-halflings-regular.448c34a5.woff2","448c34a56d699c29117adc64c43affeb"],["/static/media/glyphicons-halflings-regular.89889688.svg","89889688147bd7575d6327160d64e760"],["/static/media/glyphicons-halflings-regular.e18bbf61.ttf","e18bbf611f2a2e43afc071aa2f4e1512"],["/static/media/glyphicons-halflings-regular.f4769f9b.eot","f4769f9bdb7466be65088239c12046d1"],["/static/media/glyphicons-halflings-regular.fa277232.woff","fa2772327f55d8198301fdb8bcfc8158"],["/static/media/greetings.bfd7a3df.jpg","bfd7a3df30dad2e76b00654cc477afa8"],["/static/media/home.1f400a9e.jpg","1f400a9e0c70a32b01025b272d9a3021"],["/static/media/logo.5d5d9eef.svg","5d5d9eefa31e5e13a6610d9fa7a283bb"]],cacheName="sw-precache-v3-sw-precache-webpack-plugin-"+(self.registration?self.registration.scope:""),ignoreUrlParametersMatching=[/^utm_/],addDirectoryIndex=function(e,t){var n=new URL(e);return"/"===n.pathname.slice(-1)&&(n.pathname+=t),n.toString()},cleanResponse=function(t){return t.redirected?("body"in t?Promise.resolve(t.body):t.blob()).then(function(e){return new Response(e,{headers:t.headers,status:t.status,statusText:t.statusText})}):Promise.resolve(t)},createCacheKey=function(e,t,n,a){var r=new URL(e);return a&&r.pathname.match(a)||(r.search+=(r.search?"&":"")+encodeURIComponent(t)+"="+encodeURIComponent(n)),r.toString()},isPathWhitelisted=function(e,t){if(0===e.length)return!0;var n=new URL(t).pathname;return e.some(function(e){return n.match(e)})},stripIgnoredUrlParameters=function(e,n){var t=new URL(e);return t.hash="",t.search=t.search.slice(1).split("&").map(function(e){return e.split("=")}).filter(function(t){return n.every(function(e){return!e.test(t[0])})}).map(function(e){return e.join("=")}).join("&"),t.toString()},hashParamName="_sw-precache",urlsToCacheKeys=new Map(precacheConfig.map(function(e){var t=e[0],n=e[1],a=new URL(t,self.location),r=createCacheKey(a,hashParamName,n,/\.\w{8}\./);return[a.toString(),r]}));function setOfCachedUrls(e){return e.keys().then(function(e){return e.map(function(e){return e.url})}).then(function(e){return new Set(e)})}self.addEventListener("install",function(e){e.waitUntil(caches.open(cacheName).then(function(a){return setOfCachedUrls(a).then(function(n){return Promise.all(Array.from(urlsToCacheKeys.values()).map(function(t){if(!n.has(t)){var e=new Request(t,{credentials:"same-origin"});return fetch(e).then(function(e){if(!e.ok)throw new Error("Request for "+t+" returned a response with status "+e.status);return cleanResponse(e).then(function(e){return a.put(t,e)})})}}))})}).then(function(){return self.skipWaiting()}))}),self.addEventListener("activate",function(e){var n=new Set(urlsToCacheKeys.values());e.waitUntil(caches.open(cacheName).then(function(t){return t.keys().then(function(e){return Promise.all(e.map(function(e){if(!n.has(e.url))return t.delete(e)}))})}).then(function(){return self.clients.claim()}))}),self.addEventListener("fetch",function(t){if("GET"===t.request.method){var e,n=stripIgnoredUrlParameters(t.request.url,ignoreUrlParametersMatching),a="index.html";(e=urlsToCacheKeys.has(n))||(n=addDirectoryIndex(n,a),e=urlsToCacheKeys.has(n));var r="/index.html";!e&&"navigate"===t.request.mode&&isPathWhitelisted(["^(?!\\/__).*"],t.request.url)&&(n=new URL(r,self.location).toString(),e=urlsToCacheKeys.has(n)),e&&t.respondWith(caches.open(cacheName).then(function(e){return e.match(urlsToCacheKeys.get(n)).then(function(e){if(e)return e;throw Error("The cached response that was expected is missing.")})}).catch(function(e){return console.warn('Couldn\'t serve response for "%s" from cache: %O',t.request.url,e),fetch(t.request)}))}});
--------------------------------------------------------------------------------
/client/src/registerServiceWorker.js:
--------------------------------------------------------------------------------
1 | // In production, we register a service worker to serve assets from local cache.
2 |
3 | // This lets the app load faster on subsequent visits in production, and gives
4 | // it offline capabilities. However, it also means that developers (and users)
5 | // will only see deployed updates on the "N+1" visit to a page, since previously
6 | // cached resources are updated in the background.
7 |
8 | // To learn more about the benefits of this model, read https://goo.gl/KwvDNy.
9 | // This link also includes instructions on opting out of this behavior.
10 |
11 | const isLocalhost = Boolean(
12 | window.location.hostname === 'localhost' ||
13 | // [::1] is the IPv6 localhost address.
14 | window.location.hostname === '[::1]' ||
15 | // 127.0.0.1/8 is considered localhost for IPv4.
16 | window.location.hostname.match(
17 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
18 | )
19 | );
20 |
21 | export default function register() {
22 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
23 | // The URL constructor is available in all browsers that support SW.
24 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location);
25 | if (publicUrl.origin !== window.location.origin) {
26 | // Our service worker won't work if PUBLIC_URL is on a different origin
27 | // from what our page is served on. This might happen if a CDN is used to
28 | // serve assets; see https://github.com/facebookincubator/create-react-app/issues/2374
29 | return;
30 | }
31 |
32 | window.addEventListener('load', () => {
33 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
34 |
35 | if (isLocalhost) {
36 | // This is running on localhost. Lets check if a service worker still exists or not.
37 | checkValidServiceWorker(swUrl);
38 |
39 | // Add some additional logging to localhost, pointing developers to the
40 | // service worker/PWA documentation.
41 | navigator.serviceWorker.ready.then(() => {
42 | console.log(
43 | 'This web app is being served cache-first by a service ' +
44 | 'worker. To learn more, visit https://goo.gl/SC7cgQ'
45 | );
46 | });
47 | } else {
48 | // Is not local host. Just register service worker
49 | registerValidSW(swUrl);
50 | }
51 | });
52 | }
53 | }
54 |
55 | function registerValidSW(swUrl) {
56 | navigator.serviceWorker
57 | .register(swUrl)
58 | .then(registration => {
59 | registration.onupdatefound = () => {
60 | const installingWorker = registration.installing;
61 | installingWorker.onstatechange = () => {
62 | if (installingWorker.state === 'installed') {
63 | if (navigator.serviceWorker.controller) {
64 | // At this point, the old content will have been purged and
65 | // the fresh content will have been added to the cache.
66 | // It's the perfect time to display a "New content is
67 | // available; please refresh." message in your web app.
68 | console.log('New content is available; please refresh.');
69 | } else {
70 | // At this point, everything has been precached.
71 | // It's the perfect time to display a
72 | // "Content is cached for offline use." message.
73 | console.log('Content is cached for offline use.');
74 | }
75 | }
76 | };
77 | };
78 | })
79 | .catch(error => {
80 | console.error('Error during service worker registration:', error);
81 | });
82 | }
83 |
84 | function checkValidServiceWorker(swUrl) {
85 | // Check if the service worker can be found. If it can't reload the page.
86 | fetch(swUrl)
87 | .then(response => {
88 | // Ensure service worker exists, and that we really are getting a JS file.
89 | if (
90 | response.status === 404 ||
91 | response.headers.get('content-type').indexOf('javascript') === -1
92 | ) {
93 | // No service worker found. Probably a different app. Reload the page.
94 | navigator.serviceWorker.ready.then(registration => {
95 | registration.unregister().then(() => {
96 | window.location.reload();
97 | });
98 | });
99 | } else {
100 | // Service worker found. Proceed as normal.
101 | registerValidSW(swUrl);
102 | }
103 | })
104 | .catch(() => {
105 | console.log(
106 | 'No internet connection found. App is running in offline mode.'
107 | );
108 | });
109 | }
110 |
111 | export function unregister() {
112 | if ('serviceWorker' in navigator) {
113 | navigator.serviceWorker.ready.then(registration => {
114 | registration.unregister();
115 | });
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/client/src/components/RSVP.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import '../css/RSVP.css'
3 | import ScrollableAnchor from 'react-scrollable-anchor'
4 |
5 | export default props => {
6 | const { id } = props;
7 | // const options = map(timezone,(val,key) => );
8 | return
9 |
10 |
11 |
12 |
13 | {!(props.isRsvpSent) &&
}
124 | {props.isRsvpSent &&
125 |
See you soon, Thanks!
126 | Gili & Matan
127 |
128 | }
129 |
130 |
131 |
132 |
133 |
134 | }
--------------------------------------------------------------------------------
/client/build/static/media/glyphicons-halflings-regular.89889688.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------