With improvements in the technologies and financial institutions governing buying and selling, we have evolved from traditional buying and selling markets to e-commerce websites.
Remix is a full-stack React framework for building web applications. It provides several helpful features such as server-side rendering, file system–based routing, TypeScript support, built-in support for cookies and sessions, and more.
What we will be building
This post discusses building an e-commerce application that allows us to create, delete and display our products in a Remix application. A custom backend server is not required.
Repository
The source code can be found here
Prerequisites
To get the most out of this project, the following are required:
- A basic understanding of CSS, JavaScript, and React.js
- A Docker Desktop installation. Run the
docker -v
command to verify whether Docker Desktop is installed. If not, install it from here - An Appwrite instance running on our computer. Check out this documentation to create a local Appwrite instance. We will use Appwrite’s powerful database service and experience to manage our catalog
Setting up our Remix app
First, we need to run the command below in the terminal to set up a new Remix application.
npx create-remix@latest
The command above triggers a command-line interface (CLI) where we can configure the application. The images below show the configuration options the CLI provides:
After creating our app, change the directory to the project and start a development server with the following command:
cd <name of our project>
npm run dev
Remix will start a development environment accessible by default at http://localhost:3000.
Installing Tailwind CSS
Tailwind CSS is a "utility-first" CSS framework that allows us to rapidly create user interfaces for web applications.
To install Tailwind CSS in our project, run these terminal commands.
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
These commands create two files in the root directory of our project, tailwind.config.js
, and postcss.config.js
.
In our tailwind.config.js
, we add the paths to all our template files with the code below.
module.exports = {
content: [
"./app/**/*.{js,ts,jsx,tsx}",
],
theme: {
extend: {},
},
plugins: [],
}
Next, update the scripts in our package.json
file to build our development and production CSS.
{
"scripts": {
"build": "npm run build:css && remix build",
"build:css": "tailwindcss -m -i ./styles/app.css -o app/styles/app.css",
"dev": "concurrently \"npm run dev:css\" \"remix dev\"",
"dev:css": "tailwindcss -w -i ./styles/app.css -o app/styles/app.css"
}
}
Next, we create a ./styles/app.css
file and add the @tailwind
directives for each of Tailwind’s layers.
@tailwind base;
@tailwind components;
@tailwind utilities;
Lastly, we import the compiled ./app/styles/app.css
file in our ./app/root.jsx
file.
import styles from "./styles/app.css"
export function links() {
return [{ rel: "stylesheet", href: styles }]
}
Installing Appwrite
Appwrite is an open-source, end-to-end, backend server solution that allows developers to build applications faster.
To use Appwrite in our Remix application, install the Appwrite client-side SDK for web applications.
npm install appwrite
Creating a new Appwrite project
We go to localhost and create a new account to see our console.
On our console, click on the Create Project button to start a new project.
After creating a project, scroll down within the Appwrite console and select Add platform.
Select Web App
and Register the Name and Hostname. Complete the registration for the Web App platform.
In our case, we are using localhost, so we insert
*localhost
Our project dashboard appears once we have created the project. At the top of the page, click the settings bar to access the Project ID.
Now, copy the Project ID, which we need to initialize the Appwrite Web SDK.
Creating the collection and attributes
In the Appwrite Web Console, click on Database, located on the left side of the dashboard.
We create a collection in our database tab by clicking the Create Collection button. This action redirects us to a Permissions page.
We'll also assign Read and Write Access to the collection.
Next, go to the attributes tab to create the properties we want a document to have.
Create a string attribute of productName, an integer attribute of productPrice, an integer attribute of productQuantity, and a string attribute of productImage. We'll use these base attributes and can add more in the future.
Setting up the E-commerce application
To set up our application, we’ll clone this repository and run the command below in the project directory:
$ cd remix
$ npm install
This repository contains all the initial setups we'll need for our app, helping us focus on our app's main functionality.
Once the development server is running, we can view it on our browser at http://localhost:3000.
Note: We will run into some errors if we ran the app as is.
The E-commerce app homepage should look like this:
Making the e-commerce interact with our database
Creating an anonymous user session
Appwrite requires a user to sign in before reading or writing to a database to enable safety in our application. However, they allow us to create an anonymous session that we'll use in this project.
Open .routes/index.tsx
, located in the app folder. Paste the code below to initialize the Appwrite
modules:
import { Client, Account, Databases, Query } from 'appwrite';
const client = new Client();
client
.setEndpoint('http://localhost/v1') // Your Appwrite Endpoint
.setProject('[PROJECT-ID]');
const account = new Account(client);
const database = new Databases(client);
account.createAnonymousSession().then(
(response) => {
console.log(response);
},
(error) => {
console.log(error);
}
);
Only signed-in users can interact with the Appwrite database, so we created an anonymous session as a workaround.
Note: The
PROJECT_ID
resides in the Appwrite console.
Creating database documents
In the app/routes/cart.tsx
file, let’s write a handleOrders
function to create documents in our collection.
const handleOrders = () => {
let promise = database.createDocument(
'[DATABASE-ID]',
'[PRODUCT-COLLECTION-ID]',
"unique()",
{
productName: basket.cart.name,
productPrice: basket.cart.price,
productQuantity: basket.cart.quantity,
productImage: basket.cart.image
}
);
promise.then(
function (response) {
console.log(response); // Success
alert('order has been successfully saved');
},
function (error) {
console.log(error); // Failure
}
);
}
This handleOrders
function above does the following:
- Uses the Appwrite
createDocument()
method, which creates a document using the collection ID and data fields to be stored. This collection ID is the same ID we copied earlier. - Alerts us when we have successfully saved our document, then clears the information in our local state variables.
Next, we pass our handleOrders()
function into an onClick
event-listener on our Link
element.
<Link
to="/checkout"
className="bg-text text-primary py-3 mt-10 rounded font-semibold text-center"
onClick ={handleSubmit}
>
Checkout
</Link>
Click on the Checkout
button and go to the Documents tab on Appwrite's project dashboard to see the saved documents.
Listing documents
To see all we've done, we need to create a function that would fetch all the orders.
In the app/routes/cart.tsx
file, we write a getOrders
function to list documents in our collection.
const getOrders = () => {
let promise = database.listDocuments(
'[DATABASE-ID]',
'[PRODUCT-COLLECTION-ID]',
);
promise.then(
function (response) {
console.log(response); // Success
alert("orders list");
},
function (error) {
console.log(error); // Failure
}
);
};
useEffect(() => {
getOrders();
}, []);
In the code snippet above, we create a getOrders()
function to display our bookmarks. We use Appwrite's listDocuments()
method to do this.
We pass the DocumentID and collection ID parameter to the getOrders()
method to specify what collection we want to access.
Our useEffect()
hook runs the getOrders()
function.
Deleting documents
In the app/routes/cart.tsx
file, let’s create a handleDelete()
function to delete documents we no longer want in our collection.
const handleDelete = () => {
let promise = database.deleteDocument(
'[COLLECTION_ID]',
'[DOCUMENT_ID]'
);
promise.then(
function (response) {
console.log(response); // Success
alert("order have been deleted successfully");
},
function (error) {
console.log(error); // Failure
}
);
};
The handleDelete()
function above does the following:
- Finds a document using its collection ID, and the document ID gets passed into the function.
- Deletes that document using Appwrite’s
deleteDocument()
method. - Alerts us if we delete an item.
Finally, the production-ready E-commerce application looks like this:
Conclusion
This article taught us how to leverage Appwrite's database features to store, list, and delete orders from an E-commerce application. This app can be the basis for a full-fledged inventory creation system for a store. Modify the documents to include handling a proper checkout flow with payment and shipping.