A responsive and interactive coffee shop website with integrated store and cart.
Explore the code »
View Demo
·
Report Bug
Table of Contents
Rustica Coffee Website is a website with an integrated store. The coffee shop is imaginary and the project was created for learning purposes. The website has a contact form integrated with formspree and formik, a random products section, a store subpage (among others), as well as an interactive shopping cart. In addition, the site is fully responsive and uses Next.js's integrated image optimization. The products' data is pulled from graphcms via their GraphQL API.
- TypeScript
- Next.js
- React.js
- Redux
- Redux Toolkit
- TailwindCSS
- headlessUI
- Formik
- Formspree
- GraphQL via graphcms
I present to you my first major project using Next.js and form integration.
In this section, I highlight a few code snippets that I find valuable. Please refer to the section below for more concepts and features I implemented.
Animating a component once based on a dependency, here amountCartItems
.
// ... //
const [animate, setAnimate] = useState(false);
useEffect(() => {
setAnimate(true);
// timing should be equivalent to animation timing
const timeout = setTimeout(() => setAnimate(false), 350);
return () => clearTimeout(timeout);
}, [amountCartItems]);
return (
<button
// ... //
className={` ${className} ${animate && 'animate-pop-once'}`}
>
{/* ... */}
</button>
);
Using discriminating unions to specify mandatory types based on the button type.
type PropsLink = {
label: string;
secondary?: boolean;
type: 'link';
href: string;
};
type PropsAnchor = {
label: string;
secondary?: boolean;
type: 'anchor';
anchorId: string;
};
type PropsButton = {
secondary?: boolean;
type: 'button';
btnType: 'button' | 'submit' | 'reset';
disabled?: boolean;
onClick?: () => void;
};
type Props = PropsLink | PropsAnchor | PropsButton;
- TypeScript
- Reusable types
- Generic types
- Discriminating unions
- Reusable components
- Dynamic routes
- API routes
- Animations
- Transitions
- Interactive cart
- Dynamic product amount
- Add items from shop subpage
- Add further items from within cart overlay (set to amount++)
- Remove items from within cart overlay (set to amount--)
- Remove complete product (set amount = 0)
- Show number of products added since last opened cart overlay
- Show product total
- Show cart total
- Shop subpage
- Add different variants of the product via a form
- Get product data dynamically
- Contact Form
- Error handling and frontend validation
- Hidden API Key via Next.js's API Route
- Fetch data from external DB with GraphQL
To get a local copy up and running follow these steps.
-
Get a free formspree API Key at https://formspree.io/
-
Setup a project for free at graphcms and create a schema according to the
shopItemDetailsType.ts
:type ShopItemDetailsType = { id: string; slug: string; title: string; allPrices: number[]; aroma: string; cookingUtilities: string[]; allVariants: string[]; allWeights: number[]; summary: string; description: string; readyForDelivery: boolean; image: { url: string }; }; export default ShopItemDetailsType;
Note that images provided by graphcms will automatically have a
url
field. Then generate a Permanent Auth Token. -
Clone the repo
```sh git clone https://github.com/vincentole/rustica_coffee_website.git ```
-
Install packages
npm
npm install
yarn
yarn
-
Enter your API keys in
.env.local
FORMSPREE_POST_API= Enter Your API KEY HERE GRAPHQL_CMS_ACCESS_TOKEN=FORMSPREE_POST_API = Enter Your API KEY HERE
You can run the project in a local environment as follows:
npm
npm run dev
yarn
yarn dev
Distributed under the MIT License. See github/LICENSE.md
for more information.
Ole Urfels (vincentole):
Project Link: https://github.com/vincentole/rustica_coffee_website