├── .gitignore ├── Procfile ├── README.md ├── app.db ├── app.py ├── app.test.db ├── client ├── .gitignore ├── README.md ├── build │ ├── asset-manifest.json │ ├── favicon.ico │ ├── home.jpg │ ├── index.html │ ├── manifest.json │ ├── service-worker.js │ └── static │ │ ├── css │ │ ├── main.f84a3ebb.css │ │ └── main.f84a3ebb.css.map │ │ ├── js │ │ ├── main.b6a0aaa4.js │ │ └── main.b6a0aaa4.js.map │ │ └── media │ │ ├── glyphicons-halflings-regular.448c34a5.woff2 │ │ ├── glyphicons-halflings-regular.89889688.svg │ │ ├── glyphicons-halflings-regular.e18bbf61.ttf │ │ ├── glyphicons-halflings-regular.f4769f9b.eot │ │ ├── glyphicons-halflings-regular.fa277232.woff │ │ ├── greetings.bfd7a3df.jpg │ │ ├── home.1f400a9e.jpg │ │ └── logo.5d5d9eef.svg ├── package-lock.json ├── package.json ├── public │ ├── favicon.ico │ ├── home.jpg │ ├── index.html │ └── manifest.json ├── run_dev.sh └── src │ ├── App.css │ ├── App.js │ ├── App.test.js │ ├── ReactScrollableAnchor.js │ ├── components │ ├── Ceremony.jsx │ ├── Greetings.jsx │ ├── Home.jsx │ ├── Location.jsx │ ├── NavigationBar.jsx │ └── RSVP.jsx │ ├── css │ ├── RSVP.css │ ├── ceremony.css │ ├── greetings.css │ ├── home.css │ ├── main.css │ └── navigationBar.css │ ├── img │ ├── carousel.png │ ├── ceremony.jpg │ ├── greetings.jpg │ ├── home.jpg │ └── testimonial.jpg │ ├── index.css │ ├── index.js │ ├── logo.svg │ ├── registerServiceWorker.js │ └── utils │ ├── MapContainer.js │ ├── data.jsx │ └── restClient.js ├── requirements.txt └── test.py /.gitignore: -------------------------------------------------------------------------------- 1 | /venv 2 | /__pycache__ 3 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | 2 | web: gunicorn app:app 3 | -------------------------------------------------------------------------------- /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) -------------------------------------------------------------------------------- /app.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liranfar/flask-react-on-heroku/ceefdd1bd5e83ed16cf1c8b0f0d4e3c91f638fdf/app.db -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /app.test.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liranfar/flask-react-on-heroku/ceefdd1bd5e83ed16cf1c8b0f0d4e3c91f638fdf/app.test.db -------------------------------------------------------------------------------- /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/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/build/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liranfar/flask-react-on-heroku/ceefdd1bd5e83ed16cf1c8b0f0d4e3c91f638fdf/client/build/favicon.ico -------------------------------------------------------------------------------- /client/build/home.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liranfar/flask-react-on-heroku/ceefdd1bd5e83ed16cf1c8b0f0d4e3c91f638fdf/client/build/home.jpg -------------------------------------------------------------------------------- /client/build/index.html: -------------------------------------------------------------------------------- 1 | Gili & Matan - The Wedding
-------------------------------------------------------------------------------- /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/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/build/static/media/glyphicons-halflings-regular.448c34a5.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liranfar/flask-react-on-heroku/ceefdd1bd5e83ed16cf1c8b0f0d4e3c91f638fdf/client/build/static/media/glyphicons-halflings-regular.448c34a5.woff2 -------------------------------------------------------------------------------- /client/build/static/media/glyphicons-halflings-regular.89889688.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | -------------------------------------------------------------------------------- /client/build/static/media/glyphicons-halflings-regular.e18bbf61.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liranfar/flask-react-on-heroku/ceefdd1bd5e83ed16cf1c8b0f0d4e3c91f638fdf/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/ceefdd1bd5e83ed16cf1c8b0f0d4e3c91f638fdf/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/ceefdd1bd5e83ed16cf1c8b0f0d4e3c91f638fdf/client/build/static/media/glyphicons-halflings-regular.fa277232.woff -------------------------------------------------------------------------------- /client/build/static/media/greetings.bfd7a3df.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liranfar/flask-react-on-heroku/ceefdd1bd5e83ed16cf1c8b0f0d4e3c91f638fdf/client/build/static/media/greetings.bfd7a3df.jpg -------------------------------------------------------------------------------- /client/build/static/media/home.1f400a9e.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liranfar/flask-react-on-heroku/ceefdd1bd5e83ed16cf1c8b0f0d4e3c91f638fdf/client/build/static/media/home.1f400a9e.jpg -------------------------------------------------------------------------------- /client/build/static/media/logo.5d5d9eef.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /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/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liranfar/flask-react-on-heroku/ceefdd1bd5e83ed16cf1c8b0f0d4e3c91f638fdf/client/public/favicon.ico -------------------------------------------------------------------------------- /client/public/home.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liranfar/flask-react-on-heroku/ceefdd1bd5e83ed16cf1c8b0f0d4e3c91f638fdf/client/public/home.jpg -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/run_dev.sh: -------------------------------------------------------------------------------- 1 | export REACT_APP_USERS_SERVICE_URL=http://localhost:8000 2 | npm start 3 | -------------------------------------------------------------------------------- /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/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 | logo 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/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/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/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/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 | {/* 900x500 */} 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 | } -------------------------------------------------------------------------------- /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/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/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/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) &&
props.handleRsvp(event)} id="form-rsvp"> 14 |
15 |
16 |

RSVP

17 | 18 |
19 |
20 | 21 |
22 |
23 |
24 | 25 | 35 |
36 |
37 | 38 | 39 |
40 |
41 | 42 | 52 |
53 | 54 |
55 | 56 |
57 | 58 | 59 |
60 |
61 |
62 | 63 | 70 |
71 |
72 | 73 |
74 |
75 | 76 | 83 |
84 |
85 |
86 | 87 |
88 |
89 |
90 | 91 |