Skip to content

Shopify Headless CMS with React, Node, Typescript, Fastify... Its time to sell premium Coffee.

License

Notifications You must be signed in to change notification settings

AlfonsoValle/CafesElSibarita

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

73 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

β˜• CAFΓ‰S EL SIBARITA β˜•

logoSibarita.png

πŸ”₯πŸ‘οΈ Click on the image to see the video explanation of this project on Youtube πŸ‘οΈπŸ”₯

IMAGE ALT TEXT HERE

Technologies Used


Esta es una imagen Esta es una imagen

Esta es una imagen Esta es una imagen Esta es una imagen Esta es una imagen Esta es una imagen

Esta es una imagen Esta es una imagen Esta es una imagen

Esta es una imagen Esta es una imagen Esta es una imagen Esta es una imagen Esta es una imagen Esta es una imagen Esta es una imagen

Esta es una imagen

- ### **Motivation to choose a Coffee Store as Project?**

After having worked creating two stores with Prestashop and Wordpress without programming. This project seemed practical, useful and an interesting experience for a junior developer.

  • A subscription model store.

The real interest of my project was not to have a large list of products that would require me a lot of time just to be able to describe and complete them. The idea of this business is simple, collect coffees from small businesses and turn it into a subscription model that allows me to make them known to them, and generate a business of discovery of new gourmet products.

  • The main challenge of making a Headless CMS store with Shopify.

Without a doubt the worst thing has been to start knowing the connection processes with πŸ”₯GraphQL, the conventional queries that we had seen did not work here.

The lack of "simple" documentation put me in some trouble to deal with the connection between our Backend and Shopify's StorefrontApi.

  • Installation and deployment Guide.

Installation and deployment Guide. To install the project you only have to go to the repository https://github.com/AlfonsoValle/CafesElSibarita , clone it and run a yarn run dev.

  • Acknowledgments.

This project would not have worked without the mentorship of @Boyander as the head of Core Code School's FullStack Bootcamp and my colleague @Systrent, without him and the endless hours of trial and error this website would work much worse.

  • Blipp Dependency Backend Endpoints.

�️  Routes:
OPTIONS *
GET     /especialidades/readSpecialities
HEAD    /especialidades/readSpecialities
POST    /especialidades/createSpecialities
DELETE  /especialidades/deleteSpecialities/:_id
GET     /sub
HEAD    /sub
HEAD    /sub/
GET     /sub/single
HEAD    /sub/single
GET     /sub/checkout01
HEAD    /sub/checkout01
GET     /sub/checkout02
HEAD    /sub/checkout02
  • Backend Schema.

β”œβ”€β”€β”€πŸ“ src/
β”‚   β”œβ”€β”€β”€πŸ“ routes/
β”‚   β”‚   β”œβ”€β”€β”€πŸ“ GraphQLApi/
β”‚   β”‚   β”‚   β”œβ”€β”€β”€πŸ“„ AllProducts.ts
β”‚   β”‚   β”‚   β”œβ”€β”€β”€πŸ“„ CheckoutMutationPrime.ts
β”‚   β”‚   β”‚   β”œβ”€β”€β”€πŸ“„ CheckoutMutationSibarita.ts
β”‚   β”‚   β”‚   β”œβ”€β”€β”€πŸ“„ ShopifyApp.ts
β”‚   β”‚   β”‚   β””β”€β”€β”€πŸ“„ SingleProduct.ts
β”‚   β”‚   β””β”€β”€β”€πŸ“ Specialities/
β”‚   β”‚       β”œβ”€β”€β”€πŸ“„ createSpecialities.ts
β”‚   β”‚       β”œβ”€β”€β”€πŸ“„ deleteSpecialities.ts
β”‚   β”‚       β”œβ”€β”€β”€πŸ“„ specialities.ts
β”‚   β”‚       β”œβ”€β”€β”€πŸ“„ specialitiesApp.ts
β”‚   β”‚       β””β”€β”€β”€πŸ“„ speciality.model.ts
β”‚   β”œβ”€β”€β”€πŸ“„ app.ts
β”‚   β”œβ”€β”€β”€πŸ“„ config.ts
β”‚   β”œβ”€β”€β”€πŸ“„ db.ts
β”‚   β””β”€β”€β”€πŸ“„ server.ts
β”œβ”€β”€β”€πŸ“„ package.json
β”œβ”€β”€β”€πŸ“„ tsconfig.json
β””β”€β”€β”€πŸ“„ yarn.lock
  • Backend ShopifyApp.

import { FastifyPluginAsync } from "fastify";
import { AllProducts } from "./AllProducts";
import { CheckoutMutationPrime } from "./CheckoutMutationPrime";
import { CheckoutMutationSibarita } from "./CheckoutMutationSibarita";
import { SingleProductQuery } from "./SingleProduct";

export const ShopifyApp: FastifyPluginAsync = async (app) => {
    app.register(AllProducts);
    app.register(SingleProductQuery);
    app.register(CheckoutMutationSibarita);
    app.register(CheckoutMutationPrime);
};
  • Backend Single Product GraphQL Query.

import Shopify from "@shopify/shopify-api";
import { FastifyPluginAsync } from "fastify";
import { SHOPIFY_SHOP, STOREFRONT } from "../../config";

export const SingleProductQuery: FastifyPluginAsync = async (app) => {
    // app.get('/products', {preValidation: app.authenticate}, async (req, res) => {
    app.get<{ Querystring: { handle: string } }>("/single", async (req, res) => {
        //Req
        // req.body;
        const { handle } = req.query;

        // Load the access token as per instructions above
        const Storefront: string = STOREFRONT;

        // Shop from which we're fetching data
        const shop: string = SHOPIFY_SHOP;

        // StorefrontClient takes in the shop url and the Storefront Access Token for that shop.
        const storefrontClient: any = new Shopify.Clients.Storefront(shop, Storefront);
        try {
            const product: any = await storefrontClient.query({
                data: {
                    query: `query singleProductQuery($handle: String!) {
                     productByHandle(handle: $handle) {
                         title
                         description
                         updatedAt
                         priceRange {
                             minVariantPrice {
                                 amount
                             }
                         }
                         images(first: 1) {
                             edges {
                                 node {
                                     transformedSrc
                                     altText
                                 }
                             }
                         }
                         variants(first: 1) {
                             edges {
                                 node {
                                     id
                                 }
                             }
                         }
                     }
                 }`,
                    variables: {
                        handle,
                    },
                },
            });
            console.log(product.body);
            return product.body;
        } catch (error) {
            console.log(error);
        }
    });
};
  • Frontend Schema.

β”œβ”€β”€β”€πŸ“ components/
β”‚   β”œβ”€β”€β”€πŸ“ Admin/
β”‚   β”‚   β”œβ”€β”€β”€πŸ“„ Botondeformulario.tsx
β”‚   β”‚   β”œβ”€β”€β”€πŸ“„ CreateSpeciality.tsx
β”‚   β”‚   β”œβ”€β”€β”€πŸ“„ DeleteSpeciality.tsx
β”‚   β”‚   β”œβ”€β”€β”€πŸ“„ EspecialidadCard.tsx
β”‚   β”‚   β””β”€β”€β”€πŸ“„ ListaEspecialidades.tsx
β”‚   β”œβ”€β”€β”€πŸ“ home/
β”‚   β”‚   β”œβ”€β”€β”€πŸ“ Footer/
β”‚   β”‚   β”‚   β””β”€β”€β”€πŸ“„ Socials.tsx
β”‚   β”‚   β”œβ”€β”€β”€πŸ“ Main Banner/
β”‚   β”‚   β”‚   β”œβ”€β”€β”€πŸ“„ MainBanner.tsx
β”‚   β”‚   β”‚   β”œβ”€β”€β”€πŸ“„ Prime.tsx
β”‚   β”‚   β”‚   β””β”€β”€β”€πŸ“„ Sibarita.tsx
β”‚   β”‚   β”œβ”€β”€β”€πŸ“ Shopify/
β”‚   β”‚   β”‚   β”œβ”€β”€β”€πŸ“„ ShopyCafeCard.tsx
β”‚   β”‚   β”‚   β”œβ”€β”€β”€πŸ“„ ShopySubPrime.tsx
β”‚   β”‚   β”‚   β””β”€β”€β”€πŸ“„ ShopySubSibarita.tsx
β”‚   β”‚   β”œβ”€β”€β”€πŸ“ Slider/
β”‚   β”‚   β”‚   β””β”€β”€β”€πŸ“„ BannerSlider.tsx
β”‚   β”‚   β”œβ”€β”€β”€πŸ“„ About.tsx
β”‚   β”‚   β”œβ”€β”€β”€πŸ“„ MainHeadText.tsx
β”‚   β”‚   β””β”€β”€β”€πŸ“„ Section.tsx
β”‚   β”œβ”€β”€β”€πŸ“ layout/
β”‚   β”‚   β”œβ”€β”€β”€πŸ“„ Footer.tsx
β”‚   β”‚   β”œβ”€β”€β”€πŸ“„ Header.tsx
β”‚   β”‚   β”œβ”€β”€β”€πŸ“„ LateralMenu.tsx
β”‚   β”‚   β”œβ”€β”€β”€πŸ“„ Layout.tsx
β”‚   β”‚   β”œβ”€β”€β”€πŸ“„ Login.tsx
β”‚   β”‚   β”œβ”€β”€β”€πŸ“„ Logo.tsx
β”‚   β”‚   β””β”€β”€β”€πŸ“„ MainMenu.tsx
β”‚   β”œβ”€β”€β”€πŸ“ profile/
β”‚   β”‚   β”œβ”€β”€β”€πŸ“„ ButtonForm.tsx
β”‚   β”‚   β”œβ”€β”€β”€πŸ“„ CardProfile.tsx
β”‚   β”‚   β””β”€β”€β”€πŸ“„ CrudProfile.tsx
β”‚   β”œβ”€β”€β”€πŸ“ Shared/
β”‚   β”‚   β”œβ”€β”€β”€πŸ“„ AuthenticatedApp.tsx
β”‚   β”‚   β”œβ”€β”€β”€πŸ“„ BotonHeader.tsx
β”‚   β”‚   β”œβ”€β”€β”€πŸ“„ Spinner.tsx
β”‚   β”‚   β””β”€β”€β”€πŸ“„ TokenApp.tsx
β”‚   β”œβ”€β”€β”€πŸ“ Subscriptions/
β”‚   β”‚   β”œβ”€β”€β”€πŸ“„ CheckoutPrime.tsx
β”‚   β”‚   β””β”€β”€β”€πŸ“„ CheckoutSibarita.tsx
β”‚   β””β”€β”€β”€πŸ“ Texts/
β”‚       β””β”€β”€β”€πŸ“„ AboutUsText.tsx
β”œβ”€β”€β”€πŸ“ lib/
β”‚   β”œβ”€β”€β”€πŸ“„ APIshopify.ts
β”‚   β”œβ”€β”€β”€πŸ“„ AuthenticatedFetcher.ts
β”‚   β”œβ”€β”€β”€πŸ“„ CurrencyFormat.ts
β”‚   β”œβ”€β”€β”€πŸ“„ GetSingleProduct.ts
β”‚   β”œβ”€β”€β”€πŸ“„ ProfileApi.ts
β”‚   β”œβ”€β”€β”€πŸ“„ ProfileRepo.ts
β”‚   β”œβ”€β”€β”€πŸ“„ PublicFetcher.ts
β”‚   β”œβ”€β”€β”€πŸ“„ SpecialityRepo.ts
β”‚   β”œβ”€β”€β”€πŸ“„ SpecialityToBackend.ts
β”‚   β””β”€β”€β”€πŸ“„ Tokencontext.ts
β”œβ”€β”€β”€πŸ“ pages/
β”‚   β”œβ”€β”€β”€πŸ“ editarespecialidades/
β”‚   β”‚   β””β”€β”€β”€πŸ“„ index.tsx
β”‚   β”œβ”€β”€β”€πŸ“ perfil/
β”‚   β”‚   β”œβ”€β”€β”€πŸ“„ consultarPerfil.tsx
β”‚   β”‚   β”œβ”€β”€β”€πŸ“„ editarPerfil.tsx
β”‚   β”‚   β””β”€β”€β”€πŸ“„ index.tsx
β”‚   β”œβ”€β”€β”€πŸ“ sobrenosotros/
β”‚   β”‚   β””β”€β”€β”€πŸ“„ index.tsx
β”‚   β”œβ”€β”€β”€πŸ“ subs/
β”‚   β”‚   β”œβ”€β”€β”€πŸ“„ prime.tsx
β”‚   β”‚   β””β”€β”€β”€πŸ“„ sibarita.tsx
β”‚   β”œβ”€β”€β”€πŸ“„ index.tsx
β”‚   β”œβ”€β”€β”€πŸ“„ _app.tsx
β”‚   β””β”€β”€β”€πŸ“„ _document.tsx
β”œβ”€β”€β”€πŸ“ public/
β”‚   β””β”€β”€β”€πŸ“ images/
β”‚       β”œβ”€β”€β”€πŸ“„ Fondo23.jpg
β”‚       β”œβ”€β”€β”€πŸ“„ Fondo24.jpg
β”‚       β”œβ”€β”€β”€πŸ“„ Fondo33.png
β”‚       β”œβ”€β”€β”€πŸ“„ Fondo34.png
β”‚       β”œβ”€β”€β”€πŸ“„ cafetera.jpg
β”‚       β”œβ”€β”€β”€πŸ“„ coffee-bag-svgrepo-com.svg
β”‚       β”œβ”€β”€β”€πŸ“„ decorativo.png
β”‚       β”œβ”€β”€β”€πŸ“„ facebook.svg
β”‚       β”œβ”€β”€β”€πŸ“„ favicon.png
β”‚       β”œβ”€β”€β”€πŸ“„ fondocafe.jpg
β”‚       β”œβ”€β”€β”€πŸ“„ fondocafebueno.jpg
β”‚       β”œβ”€β”€β”€πŸ“„ instagram.svg
β”‚       β”œβ”€β”€β”€πŸ“„ logoSibarita.png
β”‚       β”œβ”€β”€β”€πŸ“„ twitter.svg
β”‚       β””β”€β”€β”€πŸ“„ vasosibarita.png
β”œβ”€β”€β”€πŸ“ types/
β”‚   β””β”€β”€β”€πŸ“„ emotion.d.ts
β”œβ”€β”€β”€πŸ“„ .babelrc
β”œβ”€β”€β”€πŸ“„ .env
β”œβ”€β”€β”€πŸ“„ .gitignore
β”œβ”€β”€β”€πŸ“„ next-env.d.ts
β”œβ”€β”€β”€πŸ“„ next.config.js
β”œβ”€β”€β”€πŸ“„ package.json
β”œβ”€β”€β”€πŸ“„ postcss.config.js
β”œβ”€β”€β”€πŸ“„ tailwind.config.js
β”œβ”€β”€β”€πŸ“„ tsconfig.json
β””β”€β”€β”€πŸ“„ yarn.lock
  • Frontend Delete Speciality Crud.

import { css } from "@emotion/react";
import useSWR from "swr";
import { DeleteSpeciality } from "../../lib/SpecialityRepo";
import { Spinner } from "../Shared/Spinner";
import { EspecialidadCard } from "./EspecialidadCard";

export const ListaEspecialidades: React.FC = () => {
    const { data, mutate } = useSWR("/especialidades/readSpecialities", {
        refreshInterval: 800,
    });

    return (
        <div className="images-list">
            <div
                css={css`
                    display: flex;
                    flex-direction: column;
                    align-items: center;
                    width: 100%;
                    height: 100%;
                    max-height: 300px;
                    padding: 0px 60px;
                    gap: 5px;
                    color: white;
                    border-radius: 10px;
                `}
            >
                {data?.length > 0 ? (
                    data.map((item, i) => (
                        <EspecialidadCard
                            item={item}
                            onDelete={async () => {
                                await DeleteSpeciality(item._id);
                                mutate();
                            }}
                        />
                    ))
                ) : (
                    <Spinner />
                )}
            </div>
        </div>
    );
};

About

Shopify Headless CMS with React, Node, Typescript, Fastify... Its time to sell premium Coffee.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages