-
Notifications
You must be signed in to change notification settings - Fork 23
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
37 changed files
with
19,210 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,150 @@ | ||
simple-clothing-store | ||
# Simple Clothing Store | ||
|
||
![banner](https://i.imgur.com/fg8F52a.png) | ||
|
||
[![license](https://img.shields.io/github/license/kerkkoh/simple-clothing-store.svg)](LICENSE) | ||
|
||
This project is a simple **clothing store** implemented with **React** and **Node.js**, aiming for an *almost* databaseless design by utilizing a **Printful** integration. | ||
|
||
## Table of Contents | ||
|
||
- [Demo](#demo) | ||
- [Background](#background) | ||
- [Install](#install) | ||
- [Usage](#usage) | ||
- [Contributing](#contributing) | ||
- [License](#license) | ||
|
||
## Demo | ||
|
||
The demo has a few limitations for quite obvious reasons. | ||
1. You can't create new orders, some orders are included for you already to view | ||
2. You can't pay for your orders | ||
3. You can't buy anything, or receive products | ||
|
||
### > Available on [Glitch](https://simple-clothing-store.glitch.me) | ||
|
||
## Background | ||
|
||
|
||
### Utilized technologies | ||
* APIs | ||
* [Printful REST API](https://www.printful.com/docs) | ||
* [Paypal REST API](https://developer.paypal.com/docs/api/overview/) | ||
* Backend | ||
* [Node.js](https://nodejs.org/en/) | ||
* [Express](https://www.npmjs.com/package/express) | ||
* [currency.js](https://www.npmjs.com/package/currency.js) | ||
* [@paypal/checkout-server-sdk](https://www.npmjs.com/package/@paypal/checkout-server-sdk) | ||
* PrintfulClient utility class (No longer available through Printful) | ||
* Frontend | ||
* [React (with hooks, no classes)](https://reactjs.org/docs/hooks-intro.html) | ||
* [React router](https://www.npmjs.com/package/react-router) | ||
* [Bootstrap](https://getbootstrap.com/) | ||
* [SASS](https://sass-lang.com/) | ||
* [Moment](https://www.npmjs.com/package/moment) | ||
* [currency.js](https://www.npmjs.com/package/currency.js) | ||
* [react-paypal-button-v2](https://www.npmjs.com/package/react-paypal-button-v2) | ||
* [react-helmet](https://www.npmjs.com/package/react-helmet) | ||
|
||
### What's working | ||
* Most frontend features: | ||
* Routes implemented with **React router**, including seamlessly moving between pages | ||
* A responsive design implemented with **Bootstrap** and customized with **SASS** (SCSS) | ||
* Loading of products and store data from the server | ||
* Products with multiple images (If printful ever decides to give us a feature for that) and sizes (product variants) | ||
* Persistent shopping cart | ||
* Correct handling of currency as its own datatype via **currency.js** | ||
* Discount codes that are confirmed by the server, and correctly applying them to the cart total | ||
* Showing orders, their statuses & shipping information from **Printful** | ||
* Some backend features: | ||
* Loading products directly from the Printful API | ||
* A configuration file for setting file descriptions, discounts and VAT rates your store needs (This will be changed to be something less hardcoded in the future) | ||
|
||
### What's planned/missing | ||
* Frontend: | ||
* Admin panel with minimal controls for | ||
1. Setting product descriptions | ||
2. Creating discounts | ||
3. Monitoring orders | ||
4. Setting the VAT rate | ||
* Handling error cases and displaying messages | ||
* Cancelling of orders | ||
* Quantity for products in a basket | ||
* Backend: | ||
* Hiding information better (product information like printfiles & costs shouldn't be sent to the client) | ||
* Calculating shipping & VAT before confirming the order | ||
* Refactoring | ||
* Better handling of errors | ||
* Handling of missing products, faulty carts, etc. | ||
* Emails | ||
|
||
### Why? | ||
|
||
This project is a hobby project that I started sketching out back in 2017 and decided to go through with in 2019 after giving it some thought. For me, this was a learning opportunity to familiarize myself with new APIs and solving problems that one might face in an implementation of an ecommerce system with modern web technologies. | ||
|
||
Another reason was the lack of **open source** webstores implemented with a JS stack, similar to this project's stack. There are a few out there, but none of them are geared towards a clothing store that operates with Printful. One of this project's goals was also to be as **simple** as possible. This means keeping the stack very light with a focus on JS and popular libraries. This also means that payments are outsourced, production is outsourced, and orders are mostly outsourced. This should keep the maintenance of the system at minimum, while allowing the clothing store to operate smoothly. | ||
|
||
### Why should I use it? | ||
|
||
In most cases, you shouldn't. Not yet. It is at an early stage of development with most of the features being at most stubs of the eventual or necessary features. | ||
|
||
These are some problem areas as of now: | ||
* Lack of a solid user, order or payment database | ||
* Lack of good information hiding from the users of the API | ||
* Security: while I've kept security in mind while developing the system, it hasn't been penetration tested by professionals, and this poses a constant risk if used in productions | ||
* No input validitation/verification of any kind | ||
* No handling situations where the local cart is out of sync with the products in the store | ||
|
||
## Install | ||
|
||
First, clone the repository from github. | ||
|
||
|
||
Now you're going to need to setup some configuration files and environmental variables: | ||
1. Get your PayPal & Printful API keys | ||
2. Navigate to `simple-clothing-store/backend/`, and rename the file called `.env.template` to just `.env` | ||
3. Set the variables in the `.env` file without inserting any spaces anywhere in the file. The variable names and comments should explain where to put what adequately. Save the file. | ||
4. Navigate to `simple-clothing-store/frontend/src/` and open the file `config.js` | ||
5. In this file you should specify some information that is displayed on the site. You should also include the same PayPal API client id in this file as a string. | ||
6. Navigate to `simple-clothing-store/backend/lib/` and open the file `datab.js` | ||
7. In this file you can specify | ||
1. Product descriptions in the `items` array by specifying a product id (You can get the id by visiting the store frontend and going to the page of a product, and then viewing the url like `yoursite.com/product/5632658632` where `5632658632` would be the id) and then specifying a `description` string for it. | ||
2. Discount codes in the section `discounts` | ||
3. Your VAT (Value Added Tax) percent **as an integer**. | ||
|
||
Now you need to build the frontend and move the built folder into the backend and install everything. | ||
``` | ||
cd simple-clothing-store/frontend | ||
npm install && npm build | ||
``` | ||
Depending on the operating system, the command for moving the build folder varies, on Linux: | ||
``` | ||
mv build ../backend | ||
``` | ||
and on Windows: | ||
``` | ||
mv build ../backend | ||
``` | ||
And then to install the backend: | ||
``` | ||
cd ../backend | ||
npm install | ||
``` | ||
|
||
|
||
## Usage | ||
|
||
To run the server, make sure you're in the `simple-clothing-store/backend` folder, and run: | ||
``` | ||
npm start | ||
``` | ||
This will start the server, and host the production build frontend with the port `process.env.PORT` or 3001. You can set the PORT variable in the file `simple-clothing-store/backend/.env` by creating a new line with the port you want the system to run on. If you're using services like Heroku to host the system, they should set this variable for you. | ||
|
||
## Contributing | ||
|
||
PRs accepted. | ||
|
||
## License | ||
|
||
[MIT License](https://github.com/kerkkoh/simple-clothing-store/LICENSE.md) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
# Environment Config | ||
# DO NOT INCLUDE ANY SPACES BETWEEN THE = SIGNS OR ANYWHERE ELSE | ||
|
||
# Your Printful API secret should go here | ||
PRINTFUL_SECRET= | ||
# Your PayPal client id and secret should go here | ||
PAYPAL_CLIENT_ID= | ||
PAYPAL_CLIENT_SECRET= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
module.exports = { | ||
'env': { | ||
'commonjs': true, | ||
'es6': true, | ||
'node': true, | ||
}, | ||
'extends': [ | ||
'google', | ||
], | ||
'globals': { | ||
'Atomics': 'readonly', | ||
'SharedArrayBuffer': 'readonly', | ||
}, | ||
'parserOptions': { | ||
'ecmaVersion': 2018, | ||
}, | ||
'rules': { | ||
'indent': ['error', 2], | ||
'linebreak-style': ['error','unix'], | ||
'quotes': ['error','single'], | ||
'semi': ['error','never'], | ||
'no-trailing-spaces': 'error', | ||
'max-len': ['error', {'code': 120 }] | ||
}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
node_modules | ||
.env | ||
build | ||
examples.js |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
# Simple Clothing Store | ||
|
||
|
||
Hey ya! ╰( ̄ω ̄o) | ||
|
||
|
||
I am the backend that hosts the built for production frontend, and also acts as an api middleground to allow communication between the frontend and the various APIs we're using! I'm mostly made out of Node.js & Express. | ||
|
||
|
||
## I'm using | ||
* A few very nice APIs | ||
* [Printful REST API](https://www.printful.com/docs) | ||
* [Paypal REST API](https://developer.paypal.com/docs/api/overview/) | ||
* Some awesome libraries | ||
* [Node.js](https://nodejs.org/en/) | ||
* [Express](https://www.npmjs.com/package/express) | ||
* [currency.js](https://www.npmjs.com/package/currency.js) | ||
* [@paypal/checkout-server-sdk](https://www.npmjs.com/package/@paypal/checkout-server-sdk) | ||
* PrintfulClient utility class (No longer available through Printful) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
/* eslint-disable max-len */ | ||
/** | ||
* Temporary Database/Configuration file | ||
* | ||
* For the "items" array, you get the id from the page of the product, or via the printful API. | ||
* If you don't set a description, the system will automatically tell you what sort of object | ||
* you should enter here for the description to work. | ||
* | ||
* In the discounts object, you have key-value pairs where the key is the string discount, | ||
* and the following integer is 100-yourDiscount --> A 20% discount should be 100-20 = 80 | ||
* | ||
* The "vat" entry is simply the percentage amount that your customers need to pay in VAT/ | ||
* value added tax. | ||
*/ | ||
// TODO: should be changed to lowdb/nedb/mongodb in the future | ||
// Todo: Make the discount amount more logical | ||
const db = { | ||
items: [ | ||
{ | ||
'id': 5632658632, | ||
'description': 'This description would appear at yoursite.com/product/5632658632 if there was a product with this id.', | ||
}, | ||
], | ||
discounts: { | ||
'TEST': 80, | ||
}, | ||
vat: 24, | ||
} | ||
|
||
module.exports = db |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
/* eslint-disable valid-jsdoc */ | ||
/* eslint-disable require-jsdoc */ | ||
'use strict' | ||
|
||
/** | ||
* | ||
* PayPal Node JS SDK dependency | ||
*/ | ||
const checkoutNodeJssdk = require('@paypal/checkout-server-sdk') | ||
|
||
/** | ||
* | ||
* Returns PayPal HTTP client instance with environment that has access | ||
* credentials context. Use this instance to invoke PayPal APIs, provided the | ||
* credentials have access. | ||
*/ | ||
function client() { | ||
return new checkoutNodeJssdk.core.PayPalHttpClient(environment()) | ||
} | ||
|
||
/** | ||
* | ||
* Set up and return PayPal JavaScript SDK environment with PayPal access credentials. | ||
* This sample uses SandboxEnvironment. In production, use LiveEnvironment. | ||
* | ||
*/ | ||
function environment() { | ||
const clientId = process.env.PAYPAL_CLIENT_ID | ||
const clientSecret = process.env.PAYPAL_CLIENT_SECRET | ||
|
||
return new checkoutNodeJssdk.core.SandboxEnvironment( | ||
clientId, clientSecret, | ||
) | ||
} | ||
|
||
async function prettyPrint(jsonData, pre='') { | ||
let pretty = '' | ||
function capitalize(string) { | ||
return string.charAt(0).toUpperCase() + string.slice(1).toLowerCase() | ||
} | ||
for (const key in jsonData) { | ||
if (jsonData.hasOwnProperty(key)) { | ||
if (isNaN(key)) { | ||
pretty += pre + capitalize(key) + ': ' | ||
} else { | ||
pretty += pre + (parseInt(key) + 1) + ': ' | ||
} | ||
if (typeof jsonData[key] === 'object') { | ||
pretty += '\n' | ||
pretty += await prettyPrint(jsonData[key], pre + ' ') | ||
} else { | ||
pretty += jsonData[key] + '\n' | ||
} | ||
} | ||
} | ||
return pretty | ||
} | ||
|
||
module.exports = {client: client, prettyPrint: prettyPrint} |
Oops, something went wrong.