I Built An App for Artists/Creators in Costa Rica.
On this article I share the initial concept of the app and what was the most difficult of the process, and also what's coming in the following weeks.
The Idea:
The idea is simple: "allow artists to trade their products for money and let them keep 100% profits". First of all... is this even possible? While working my full-time job, I spent my free time developing this project. The application is in BETA now at www.creadores.shop.
What the hell is SINPE Móvil?
SINPE Móvil is a service provided by Costa Rica's Central Bank that allows Costa Rica's citizens to send money via SMS. And it works by linking your phone number with your bank account. Using the service is free of charge for transactions under 100.000 colones ($150 approx) but don't quote me on that, I'm not sure what the limit without fees is, but I know is around 100k colones. It is available for all major banks and it's a very well known service in the country. Since the pandemic hit, it has become even popular among shops.
Development
To starts off, firstly I would like to say that by no means I'm a javascript expert (as much as I would love to be one, I'm not... but I'm working and learning towards it). So forgive me here if I make wrong statements or assumptions.
The website itself is simple too. Basically you can create an account/store, upload a couple of products and start selling them via SINPE Móvil. It's a Fullstack Application under the MERN stack. The frontend is built on top of Next.js and the backend with Node+Express, although Next.js have a solution for API routes. For now, I just did implement a wrapper around the SINPE Móvil workflow to allow stores' customers to buy products via SMS. And being real, is the main channel in which artists get paid today in the country when selling their products on their instagram pages; that and cash.
The easy part
Next.js was a perfect fit for this project, firstly because is a great tool to develop React applications for the browser and also because its dynamic routing. This is my first solo "real" application, but I felt that routing this application dynamically would have been harder without Next.js. Mainly because I wanted routes to be simple, clean and reading-friendly. A store can be found under www.creadores.shop/store
and a product under www.creadores.shop/store/product-slug
and that is for all stores. So, fetching that data with Next.js was really easy.
The hard part(s)
I did struggle a lot believing in myself and finding motivation when feeling like I was not able to solve the problem I was facing at the time. So that's worth to mention.
Designing the look for it to not suck, for sure was a challenge. I'm not that good designing websites. I took a lot of inspiration from artists and other creators on the internet as well as leveraging websites like indiemakers.tools to make the website look good. I used ChakraUI for building the components and that helped me a lot too.
One of tricky parts of the application was the product creation/editing forms. Mainly because categories and options. Categories are self-explanatory. The options can be almost anything. An option could be the size or color of a product, or any other kind of feature that pertains to the product, each option should carry its own price. And at least one option price should match the product price.
Also, one of the toughest parts of the application was to make it work properly for the end user i.e: stores' customers. Manage the state of different stores for the same Cart was at the beginning a bit of a pain for various reasons. The Cart 🛒 is just a Zustand store-hook and it handles all the logic of adding, deleting and editing products for each shop present in the Cart:
import { ICartState, ICartStoreDetails } from 'src/types/cart'
import { createCartStore } from '@/lib/createCartStore'
import create from 'zustand'
export const useCartState = create<ICartState>(
stores: {}, // the key is the store name
ordering: [], // a list of store names present in cart
addProduct: (store, cartProduct) =>
set((state) => {
const { namespace } = store
const found = state.stores[namespace]
if (found) {
let total = 0
state.stores[namespace].products = [...found.products, cartProduct]
state.stores[namespace].products.map((p) => {
total += p.price * p.quantity
})
state.stores[namespace].total = total
return state
} else {
const newStore = createCartStore(store, cartProduct)
state.stores[namespace] = newStore
state.ordering = state.ordering.concat(newStore.namespace)
return state
}
}),
removeProduct: (store, prod) =>
set((state) => {
const { namespace } = store
const stateStore = state.stores[namespace]
state.stores[namespace].products = stateStore.products.filter(
(p) => p.purchase !== prod.purchase
)
if (stateStore.products.length === 0) {
delete state.stores[namespace]
state.ordering = state.ordering.filter((n) => n !== namespace)
}
return state
}),
setProductQuantity: (store, product, quantity) =>
set((state) => {
const { namespace } = store
const stateStore = state.stores[namespace]
state.stores[namespace].products = stateStore.products.map((p) => {
if (p.purchase === product.purchase) {
Number.isNaN(quantity)
? (p.quantity = 0)
: (p.quantity = quantity)
}
return p
})
}),
removeStore: (namespace) =>
set((state) => {
delete state.stores[namespace]
state.ordering = state.ordering.filter((s) => s !== namespace)
return state
}),
)
What's next?
Well, to be honest with you... there are a lot of bugs yet to be fixed. But there's a MVP in production already. I'll keep debugging the application while building some other small features before starting the marketing campaigns. Nothing crazy. Low budget self-funded ads on Instagram only. I'm not planning on spend money on any other social media. Or should I?