⚠️ This project has moved over to Beluga ⚠️
Beluga has all of the same functionality as this project, plus these features:
- Store backend UI to automate product creation and store theming
- Collections to organize products
- Paid shipping options
- About page
Check out belugajs.com for documentation, tutorials, and a gallery.
Artisanal hand-rolled e-commerce site.
Written in React, served up with Express, and integrated with Stripe Dashboard.
Uses Material-UI and styled-components for the design.
Site also includes a password-protected admin view, Nodemailer integration for sending order updates, and email templates built with Handlebars.
Demo of store - with some extra visualization magic on top :)
yarn install
yarn start
This will open a browser tab with the store running. The config file in /src/assets/
will be running the store, and at first you should see one product. The $Infinity - $-Infinity
price tag is notifying us that there is an error connecting to the Stripe account, which we hope would be true since we haven't set a stripe key or a stripe product ID yet!
Individual stores are created via a config file. There are three example configs in /src/assets/
. The config generally looks like:
{
"store_name": "The best little ecommerce site in Texas",
"store_slug": "react-stripe-store",
"api_key": {STRIPE_PUBLIC_KEY},
"colors": {
"primary": {
"main": "#FE8A00",
"dark": "#FD7300",
"contrastText": "#FFF"
},
"secondary": {
"main": "#00FFB4"
}
},
"products": [
{
"name": "Super Cool Product",
"url": "url-for-product",
"stripe_id": {STRIPE_PRODUCT_ID},
"description": "What a great product!",
"photos": ["photo1.jpg","photo2.jpg"],
"details": [
"These are details that get rendered as bullet points",
"Useful for short + sweet info"
]
},
...
]
}
Each product can also have an optional variants
key for additional metadata to be saved for each product, rendered as a dropdown. This is for saving options without having to create individual SKUs in Stripe.
"variants": {
"name": "metadata",
"options":[
{"label": "option 1"},
{"label": "option 2"}
]
}
Items in that config in all caps are sourced from Stripe. This project makes use of Stripe Dashboard to keep track of Product inventories, and SKUs (this allows Stripe to handle all payment info, reducing the risk of man-in-the-middle issues). On loading a product page, this site will ask Stripe for the SKUs associated with the given product ID.
Items added to the cart are saved via localStorage
, which namespaces them according to the store_slug
, such that you can run several stores at once and keep each purchase separate.
Images are expected to live in /public/photos/{product.url}/{product.photos.name}
. The site will also add a CSS class on the body that is the store slug, for store-specific CSS.
If you are developing multiple stores at once:
- Switch config files in
App.js
in lineimport config from './assets/{YOUR_CONFIG_FILE}'
- Also in
App.js
, change theLanding
componet to your particular file:./components/Landing-{STORE_SLUG}
- Change the Stripe Secret key in your
config.env
file
Orders can be tracked at /admin
, which is accessed via /login
. The admin password is saved as an env variable, and admin status is saved in a session cookie.
Secrets are stored via environment variables, which are created via dotenv. This process expects a file titled config.env
in your /root
folder, with the following items:
STRIPE_KEY={get this from stripe}
ADMIN_PW={your password to log in}
SESSION_SECRET={generate a random string here, make it hard to guess}
EMAIL_FROM=
EMAIL_CLIENT_ID=
EMAIL_CLIENT_SECRET=
EMAIL_REFRESH_TOKEN=
EMAIL_ACCESS_TOKEN=
EMAIL_EXPIRES=
All of the EMAIL_
items are generated by the following Gmail Oauth2 Setup.
The repo comes with multiple order templates, which are triggered by updating the order status on the /admin
page. Here's an example email, with all of the relevant personalizations (store name, banner color) coming from the config file.
YMMV but I used this tutorial for a deployment on DigitalOcean, up until the last half of the last step (AKA the default
file config). (Also yarn install)
Remember to set up the config.env
file!
Daeomonize step: pm2 start server/index.js
Next was setting up nginx according to this guide, ex:
server {
listen 80;
server_name myapp.domain.com;
location / {
proxy_pass http://localhost:5000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Then using this tutorial for setting up an SSL cert with Let's Encrypt. And then adding port 22 for ssh a la this fix.
Deploy script:
ssh {username}@{IP address}
cd {project}
git pull
yarn run build
pm2 restart all
Don't @ me :)