Skip to content
This repository has been archived by the owner on Mar 19, 2021. It is now read-only.

Commit

Permalink
feat: Add Printful shipping, tax calculations (#63)
Browse files Browse the repository at this point in the history
* chore: Bump to react-hook-form@4.x.x

* refactor: Use react-hook-form@4.x.x

* style: camelCase SVG attributes

* refactor: Usen gatsby-plugin-react-svg

* refactor: Split out CheckoutForm component

Use <FormContext />

* style: Remove unused import

* style: Remove unused desctructure

* feat: Add CheckoutProvider, CheckoutContext

* feat: Allow payment once progressing from shipping form

* feat: Add mutation, resolver to calculate shipping rates

* refactor: Prefer nested syntax for defaultValues

* fix: Correctl destructure first index of array in Printful payload

* fix: Import const

* fix: Actually return shipping data from Printful

* feat: Enable disabled state for <Checkbox />

* feat: Hook up mutation to calculate shipping to form

* feat: Add mutation, resolver to calculate tax rates

* fix: Better calculate shipping button state

* style: Remove unused desctructure

* refactor: Use /orders/estimate-cost endpoint to retrieve accurate shipping, TAX totals

* feat: Add shipping, tax totals from Printful to context

* feat: Update checkout totals to include shipping, taxes

* fix: Add note to hidden payment field to calculate shipping before proceeding

* feat: Add orderTotal to the checkout context

* feat: Use orderTotal when creating order, Stripe intent

* refactor: Remove unused Printful datasource functions

* refactor: Remove defaultValues

* fix: Correct border-color of Textarea
  • Loading branch information
Jonathan Steele committed Jan 22, 2020
1 parent 1a62618 commit be0e7c1
Show file tree
Hide file tree
Showing 24 changed files with 1,023 additions and 602 deletions.
13 changes: 13 additions & 0 deletions functions/graphql/datasources/printful.js
Expand Up @@ -26,6 +26,19 @@ class PrintfulAPI extends RESTDataSource {
console.error(err);
}
}

async estimateOrderCosts({ items, recipient }) {
try {
const { result: data } = await this.post(`orders/estimate-costs`, {
items,
recipient,
});

return data;
} catch (err) {
console.error(err);
}
}
}

module.exports = PrintfulAPI;
2 changes: 2 additions & 0 deletions functions/graphql/resolvers/index.js
@@ -1,5 +1,6 @@
const order = require('./query/order');

const estimateOrderCosts = require('./mutation/estimateOrderCosts');
const checkout = require('./mutation/checkout');
const createPaymentIntent = require('./mutation/createPaymentIntent');
const submitReview = require('./mutation/submitReview');
Expand All @@ -11,6 +12,7 @@ const resolvers = {
Mutation: {
checkout,
createPaymentIntent,
estimateOrderCosts,
submitReview,
},
PaymentIntentStatus: {
Expand Down
31 changes: 31 additions & 0 deletions functions/graphql/resolvers/mutation/estimateOrderCosts.js
@@ -0,0 +1,31 @@
const estimateOrderCosts = async (_, { input }, { dataSources }) => {
try {
const {
country: country_code,
state: state_code,
...rest
} = input.shippingAddress;

const {
costs: { currency, shipping: shippingRate, tax: taxRate, vat: vatRate },
} = await dataSources.PrintfulAPI.estimateOrderCosts({
recipient: {
country_code,
state_code,
...rest,
},
items: input.items.map(
({ quantity, variantId: external_variant_id }) => ({
external_variant_id,
quantity,
})
),
});

return { currency, shippingRate, taxRate, vatRate };
} catch (err) {
return err;
}
};

module.exports = estimateOrderCosts;
13 changes: 13 additions & 0 deletions functions/graphql/typeDefs.js
Expand Up @@ -6,11 +6,19 @@ const typeDefs = gql`
}
type Mutation {
estimateOrderCosts(input: EstimateOrderCostsInput!): OrderCosts
checkout(input: CheckoutInput!): Order
createPaymentIntent(input: PaymentIntentInput!): PaymentIntent
submitReview(input: SubmitReviewInput!): Review
}
type OrderCosts {
currency: String!
shippingRate: Float!
taxRate: Float!
vatRate: Float!
}
type Order {
graphCMSOrderId: ID!
printfulOrderId: ID!
Expand All @@ -36,6 +44,11 @@ const typeDefs = gql`
SUCCEEDED
}
input EstimateOrderCostsInput {
items: [CheckoutItemInput!]!
shippingAddress: CheckoutAddressInput!
}
input SubmitReviewInput {
name: String!
email: String!
Expand Down
8 changes: 8 additions & 0 deletions gatsby-config.js
Expand Up @@ -15,6 +15,14 @@ module.exports = {
purgeOnly: ['src/main.css'],
},
},
{
resolve: 'gatsby-plugin-react-svg',
options: {
rule: {
include: /svg/,
},
},
},
`gatsby-plugin-sharp`,
{
resolve: `gatsby-source-graphql`,
Expand Down
3 changes: 2 additions & 1 deletion package.json
Expand Up @@ -19,6 +19,7 @@
"gatsby-plugin-postcss": "2.1.13",
"gatsby-plugin-purgecss": "4.0.1",
"gatsby-plugin-react-helmet": "^3.1.18",
"gatsby-plugin-react-svg": "3.0.0",
"gatsby-plugin-sharp": "^2.3.3",
"gatsby-plugin-stripe": "1.2.3",
"gatsby-source-filesystem": "^2.1.42",
Expand All @@ -34,7 +35,7 @@
"react": "16.10.2",
"react-dom": "16.10.2",
"react-helmet": "^5.2.1",
"react-hook-form": "3.28.14",
"react-hook-form": "4.5.6",
"react-stripe-elements": "6.0.1",
"react-toastify": "^5.4.1",
"react-use-cart": "1.2.2",
Expand Down
17 changes: 14 additions & 3 deletions src/components/Checkbox.js
@@ -1,14 +1,25 @@
import React from 'react';
import classNames from 'classnames';

function Checkbox({ disabled, register, name, children, ...rest }) {
const labelClass = classNames('block', {
'cursor-not-allowed': disabled,
'cursor-pointed': !disabled,
});

const inputClass = classNames('mr-3 leading-tight', {
'cursor-not-allowed opacity-50': disabled,
});

function Checkbox({ register, name, children, ...rest }) {
return (
<label className="block cursor-pointer" htmlFor={name}>
<label className={labelClass} htmlFor={name}>
<input
id={name}
name={name}
type="checkbox"
ref={register}
className="mr-3 leading-tight"
className={inputClass}
disabled={disabled}
{...rest}
/>
<span className="text-sm text-slategray">{children}</span>
Expand Down
19 changes: 11 additions & 8 deletions src/components/Checkout.js
Expand Up @@ -3,6 +3,7 @@ import { useCart } from 'react-use-cart';
import { navigate } from 'gatsby';
import { Elements } from 'react-stripe-elements';

import { CheckoutProvider } from '../context/Checkout';
import CheckoutForm from '../components/CheckoutForm';
import CheckoutItemList from './CheckoutItemList';

Expand All @@ -23,16 +24,18 @@ function Checkout() {

return (
<Elements>
<div className="lg:flex -mx-4">
<div className="lg:w-1/2 lg:w-2/5 px-4 order-last">
<div className="lg:sticky lg:top-0">
<CheckoutItemList />
<CheckoutProvider>
<div className="lg:flex -mx-4">
<div className="lg:w-1/2 lg:w-2/5 px-4 order-last">
<div className="lg:sticky lg:top-0">
<CheckoutItemList />
</div>
</div>
<div className="lg:w-1/2 lg:w-3/5 px-4 order-first">
<CheckoutForm />
</div>
</div>
<div className="lg:w-1/2 lg:w-3/5 px-4 order-first">
<CheckoutForm />
</div>
</div>
</CheckoutProvider>
</Elements>
);
}
Expand Down

0 comments on commit be0e7c1

Please sign in to comment.