Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: storefront guide #44

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
File renamed without changes.
File renamed without changes.
Empty file.
Empty file.
File renamed without changes.
File renamed without changes.
File renamed without changes.
20 changes: 20 additions & 0 deletions guides/storefront-guide/storefront-account-management.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Storefront UI Development
## Build an account management page

### Index
This article is part of the [Storefront UI Development Guide](./storefront-intro.md).
delagroove marked this conversation as resolved.
Show resolved Hide resolved
- Previous Task: [Add ability to log in](./storefront-login.md)
- Next Task: [Show inventory status badges](./storefront-inventory-status-badges.md)

### Overview
After you've added the ability to log in, most storefronts also need an account management page, or multiple pages. Here your shoppers with accounts can update their profile information, their stored addresses, and their stored payment details, as well as view, track, and cancel their orders.

Here is a list of GraphQL queries you'll likely need:
- `viewer`
- `ordersByAccountId`

And mutations:
- `addAccountAddressBookEntry`
- `updateAccountAddressBookEntry`
- `removeAccountAddressBookEntry`

118 changes: 118 additions & 0 deletions guides/storefront-guide/storefront-add-to-cart.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
# Storefront UI Development
## Add a way to add an item to a cart

### Index
This article is part of the [Storefront UI Development Guide](./storefront-intro.md).
- Previous Task: [Build navigation menus](./storefront-nav-menus.md)
- Next Task: [Build a cart page](./storefront-cart-page.md)

### Overview
In Reaction, there are anonymous carts and account carts. For more information, refer to [Concepts: Carts](../developers-guide/concepts/carts.md). Since we haven't added a way to log in to the storefront yet, we're going to work only with anonymous carts in this section.

In your UI, on product list items, the product detail page, or both, you will add a button, which usually says something like "Add to Cart". This button must invoke logic that decides which GraphQL mutation to use:
- If you already have an anonymous cart ID and token in your application state, call the `addCartItems` mutation.
- If you do not have an anonymous cart ID and token in your application state, call the `createCart` mutation.

Defining these mutations looks something like this:

```graphql
mutation createCartMutation($input: CreateCartInput!) {
createCart(input: $input) {
cart {
...CartFragment
}
incorrectPriceFailures {
...IncorrectPriceFailuresFragment
}
minOrderQuantityFailures {
...MinOrderQuantityFailuresFragment
}
token
}
}

mutation addCartItemsMutation($input: AddCartItemsInput!) {
addCartItems(input: $input) {
cart {
...CartFragment
}
incorrectPriceFailures {
...IncorrectPriceFailuresFragment
}
minOrderQuantityFailures {
...MinOrderQuantityFailuresFragment
}
}
}

fragment CartFragment on Cart {
_id
email
items {
...CartItemConnectionFragment
}
totalItemQuantity
}

fragment CartItemConnectionFragment on CartItemConnection {
pageInfo {
hasNextPage
endCursor
}
edges {
node {
_id
productConfiguration {
productId
productVariantId
}
attributes {
label
value
}
createdAt
inventoryAvailableToSell
isBackorder
isLowQuantity
isSoldOut
imageURLs {
thumbnail
}
price {
displayAmount
}
priceWhenAdded {
displayAmount
}
quantity
subtotal {
displayAmount
}
title
productVendor
variantTitle
optionTitle
}
}
}

fragment IncorrectPriceFailuresFragment on IncorrectPriceFailureDetails {
currentPrice {
displayAmount
}
providedPrice {
displayAmount
}
}

fragment MinOrderQuantityFailuresFragment on MinOrderQuantityFailureDetails {
minOrderQuantity
quantity
}
```

If you call the `createCart` mutation and get a success response, store the `cart._id` and `token` from the response in persistent app state tied to the browser or device, for example, `localStorage` or a cookie. Then the next time "Add to Cart" is clicked, your logic will see the cart ID and token and choose to call the `addCartItems` mutation.

Regardless of whether you are creating a new cart with items or adding items to an existing cart, you must check for `incorrectPriceFailures` and `minOrderQuantityFailures` in the response. The server may have added only some items to the cart but been unable to add other items. If any items could not be added because you tried to add them at an incorrect price, there will be data in `incorrectPriceFailures` that you can use to show a message to the shopper. This can happen if a price changed after the page was loaded. If any items could not be added because you tried to add fewer than the minimum purchase quantity to the cart, there will be data in `minOrderQuantityFailures` that you can use to show a message to the shopper. They can then increment the quantity and attempt to add it again.

Next Task: [Build a cart page](./storefront-cart-page.md)
33 changes: 33 additions & 0 deletions guides/storefront-guide/storefront-apollo-client.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Storefront UI Development
## Add and configure Apollo Client

### Index
This article is part of the [Storefront UI Development Guide](./storefront-intro.md).
- Previous Task: *None*
- Next Task: [Build a product listing page](./storefront-product-listing-page.md)

### Overview
To add Apollo Client to your UI app, read the [excellent Apollo docs](https://www.apollographql.com/docs/react/essentials/get-started.html). For local development, the Reaction GraphQL endpoint `uri` is `http://localhost:3000/graphql`, but we recommend storing that value in app config where it can be set differently per environment.

For your test query, try this:

```js
import gql from "graphql-tag";

const testQuery = gql`{
primaryShop {
_id
name
}
}`;

client
.query({ query: testQuery })
.then(result => console.log(result));
```

> If it doesn't work in your storefront UI code, try it directly in the GraphQL Playground at http://localhost:3000/graphql. If it works there, then check over your Apollo Client setup code again and check for any errors.

Assuming your test query works, you're ready to start building your storefront UI. You will eventually need to configure authentication, but most of a storefront UI can be built without authenticating, so we'll do that later.

Next Task: [Build a product listing page](./storefront-product-listing-page.md)
66 changes: 66 additions & 0 deletions guides/storefront-guide/storefront-cart-modification.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Storefront UI Development
## Implement cart modification

### Index
This article is part of the [Storefront UI Development Guide](./storefront-intro.md).
- Previous Task: [Build a cart page](./storefront-cart-page.md)
- Next Task: [Build a checkout page](./storefront-checkout-page.md)

### Overview
Now that a shopper can view their cart, they'll likely want to change it. They already have the ability to add additional items to it, but at some point they'll want to change the quantity for an item or remove it entirely. We'll implement those actions in this task. There are additional cart mutations that will happen during a checkout flow, which we'll implement later.

### Change the quantity for a cart item

The quantity change mutation is usually invoked by clicking a quantity increment or decrement button or entering or clicking a specific quantity. Regardless of what you do for the UI, all you need to do is figure out what new quantity the shopper wants, and then pass it to the `updateCartItemsQuantity` mutation.

```graphql
mutation updateCartItemsQuantityMutation($input: UpdateCartItemsQuantityInput!) {
updateCartItemsQuantity(input: $input) {
cart {
...CartFragment
}
}
}
```

Where the `input` variable looks like this:

```js
{
cartId, // from application state
items: [
{ cartItemId, quantity }
],
token // from application state
}
```

`cartItemId` is the `item._id` and `quantity` is the new desired quantity, which must be an integer of 0 or greater. A quantity of `0` removes the item, but we recommend calling the `removeCartItems` mutation instead.

### Remove a cart item

Removing a cart item is usually done by clicking a "Remove" button on the cart item UI. This should invoke the `removeCartItems` mutation.

```graphql
mutation removeCartItemsMutation($input: RemoveCartItemsInput!) {
removeCartItems(input: $input) {
cart {
...CartFragment
}
}
}
```

Where the `input` variable looks like this:

```js
{
cartId, // from application state
cartItemIds: [],
token // from application state
}
```

`cartItemIds` is an array of IDs from `item._id`.

Next Task: [Build a checkout page](./storefront-checkout-page.md)
24 changes: 24 additions & 0 deletions guides/storefront-guide/storefront-cart-page.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Storefront UI Development
## Build a cart page

### Index
This article is part of the [Storefront UI Development Guide](./storefront-intro.md).
- Previous Task: [Add a way to add an item to a cart](./storefront-add-to-cart.md)
- Next Task: [Implement cart modification](./storefront-cart-modification.md)

### Overview
After a shopper has clicked "Add to Cart", they are going to want to now see their cart. This could be a sidebar component, a modal, or a full page. Either way, the data loading is similar. You will do one query for cart data, with pagination on the `cart.items` connection.

```graphql
query anonymousCartByCartIdQuery($cartId: ID!, $token: String!, $itemsAfterCursor: ConnectionCursor) {
cart: anonymousCartByCartId(cartId: $cartId, token: $token) {
items(first: 20, after: $itemsAfterCursor) {
...CartItemConnectionFragment
}
}
}
```

Typically we recommend an infinite scrolling style pagination for cart items. When the user is scrolling and nears the bottom of the list, refetch this query with `itemsAfterCursor` variable set to the `cursor` from the last item's edge.

Next Task: [Implement cart modification](./storefront-cart-modification.md)
Loading