From 53517925b989b9aa821800ccec77bd7217862703 Mon Sep 17 00:00:00 2001 From: Bayram Muhiyev Date: Mon, 26 Jul 2021 13:03:51 +0500 Subject: [PATCH] Order checkout process implemented without validations --- components/common/Layout/Layout.tsx | 4 +- framework/commerce/utils/request.ts | 20 +++ .../add-payment-to-order-mutation.ts | 31 ++++ .../set-customer-for-order-mutation.ts | 34 ++++ .../set-order-shipping-address-mutation.ts | 22 +++ .../transition-order-to-state-mutation.ts | 29 ++++ package.json | 45 ++--- .../CheckoutSidebarView.module.css | 7 + .../CheckoutSidebarView.tsx | 124 ++++++++++++++ .../dap/checkout/CheckoutSidebarView/index.ts | 1 + .../ShippingView/ShippingView.module.css | 21 +++ .../checkout/ShippingView/ShippingView.tsx | 155 ++++++++++++++++++ theme/dap/checkout/ShippingView/index.ts | 1 + yarn.lock | 2 +- 14 files changed, 471 insertions(+), 25 deletions(-) create mode 100644 framework/commerce/utils/request.ts create mode 100644 framework/vendure/utils/mutations/add-payment-to-order-mutation.ts create mode 100644 framework/vendure/utils/mutations/set-customer-for-order-mutation.ts create mode 100644 framework/vendure/utils/mutations/set-order-shipping-address-mutation.ts create mode 100644 framework/vendure/utils/mutations/transition-order-to-state-mutation.ts create mode 100644 theme/dap/checkout/CheckoutSidebarView/CheckoutSidebarView.module.css create mode 100644 theme/dap/checkout/CheckoutSidebarView/CheckoutSidebarView.tsx create mode 100644 theme/dap/checkout/CheckoutSidebarView/index.ts create mode 100644 theme/dap/checkout/ShippingView/ShippingView.module.css create mode 100644 theme/dap/checkout/ShippingView/ShippingView.tsx create mode 100644 theme/dap/checkout/ShippingView/index.ts diff --git a/components/common/Layout/Layout.tsx b/components/common/Layout/Layout.tsx index ff6d72aaf..5d1ef13a6 100644 --- a/components/common/Layout/Layout.tsx +++ b/components/common/Layout/Layout.tsx @@ -7,12 +7,12 @@ import { useUI } from '@components/ui/context' import type { Page } from '@commerce/types/page' import { Navbar, Footer } from '@components/common' import type { Category } from '@commerce/types/site' -import ShippingView from '@components/checkout/ShippingView' +import ShippingView from '@theme/checkout/ShippingView' import CartSidebarView from '@components/cart/CartSidebarView' import { useAcceptCookies } from '@lib/hooks/useAcceptCookies' import { Sidebar, Button, Modal, LoadingDots } from '@components/ui' import PaymentMethodView from '@components/checkout/PaymentMethodView' -import CheckoutSidebarView from '@components/checkout/CheckoutSidebarView' +import CheckoutSidebarView from '@theme/checkout/CheckoutSidebarView' import LoginView from '@components/auth/LoginView' import s from './Layout.module.css' diff --git a/framework/commerce/utils/request.ts b/framework/commerce/utils/request.ts new file mode 100644 index 000000000..296aa7944 --- /dev/null +++ b/framework/commerce/utils/request.ts @@ -0,0 +1,20 @@ +const request = async ({query, variables}) => { + + const data = await fetch('http://localhost:5000/shop-api', { + method: "POST", + headers: { "Content-Type": "application/json" }, + credentials: 'include', + body: JSON.stringify({ query: query, variables: variables }) + }) + + if (data.status === 200) { + const response = await data.json() + return response + } + + return { + error: true + } +} + +export default request \ No newline at end of file diff --git a/framework/vendure/utils/mutations/add-payment-to-order-mutation.ts b/framework/vendure/utils/mutations/add-payment-to-order-mutation.ts new file mode 100644 index 000000000..39d38167d --- /dev/null +++ b/framework/vendure/utils/mutations/add-payment-to-order-mutation.ts @@ -0,0 +1,31 @@ +export const addPaymentToOrderMutation = /***/` + mutation addPaymentToOrder($input: PaymentInput!) { + addPaymentToOrder(input: $input) { + __typename + ...on Order { + id + state + customer { + id + } + totalQuantity + lines { + id + } + } + ...on OrderPaymentStateError { + errorCode + message + } + ...on IneligiblePaymentMethodError { + errorCode + message + eligibilityCheckerMessage + } + ...on ErrorResult { + errorCode + message + } + } + } +` \ No newline at end of file diff --git a/framework/vendure/utils/mutations/set-customer-for-order-mutation.ts b/framework/vendure/utils/mutations/set-customer-for-order-mutation.ts new file mode 100644 index 000000000..0a7918b9b --- /dev/null +++ b/framework/vendure/utils/mutations/set-customer-for-order-mutation.ts @@ -0,0 +1,34 @@ +// { +// title: "John Adams" +// firstName: "John" +// lastName: "Adams" +// phoneNumber: "+99312345678" +// emailAddress: "john@example.com" +// } + +export const setCustomerForOrderMutation = /* GraphQL*/ ` + mutation setCustomerForOrder($input: CreateCustomerInput!) { + setCustomerForOrder(input: $input){ + __typename + ...on Order { + id + state + customer { + id + } + totalQuantity + lines { + id + } + } + ...on AlreadyLoggedInError { + errorCode + message + } + ...on NoActiveOrderError { + errorCode + message + } + } + } +` \ No newline at end of file diff --git a/framework/vendure/utils/mutations/set-order-shipping-address-mutation.ts b/framework/vendure/utils/mutations/set-order-shipping-address-mutation.ts new file mode 100644 index 000000000..1fa8ee4f0 --- /dev/null +++ b/framework/vendure/utils/mutations/set-order-shipping-address-mutation.ts @@ -0,0 +1,22 @@ +export const setOrderShippingAddressMutation = /* GraphQL */ ` + mutation setOrderShippingAddress($input: CreateAddressInput!) { + setOrderShippingAddress(input: $input) { + __typename + ...on Order { + id + state + customer { + id + } + totalQuantity + lines { + id + } + } + ...on ErrorResult { + errorCode + message + } + } + } +` \ No newline at end of file diff --git a/framework/vendure/utils/mutations/transition-order-to-state-mutation.ts b/framework/vendure/utils/mutations/transition-order-to-state-mutation.ts new file mode 100644 index 000000000..8033ea33a --- /dev/null +++ b/framework/vendure/utils/mutations/transition-order-to-state-mutation.ts @@ -0,0 +1,29 @@ +export const transitionOrderToStateMutation = /* GraphQL */ ` + mutation transitionOrderToState($state: String!) { + transitionOrderToState(state: $state) { + __typename + ...on Order { + id + state + customer { + id + } + totalQuantity + lines { + id + } + } + ...on ErrorResult { + errorCode + message + } + ...on OrderStateTransitionError { + errorCode + message + transitionError + fromState + toState + } + } + } +` \ No newline at end of file diff --git a/package.json b/package.json index 227d20764..7fba99e3d 100644 --- a/package.json +++ b/package.json @@ -19,16 +19,33 @@ "node": ">=14.x" }, "dependencies": { + "@graphql-codegen/cli": "^1.21.5", + "@graphql-codegen/schema-ast": "^1.18.3", + "@graphql-codegen/typescript": "^1.22.2", + "@graphql-codegen/typescript-operations": "^1.18.1", + "@next/bundle-analyzer": "^10.2.3", "@react-spring/web": "^9.2.1", + "@types/body-scroll-lock": "^2.6.1", + "@types/cookie": "^0.4.0", + "@types/js-cookie": "^2.2.6", + "@types/lodash.debounce": "^4.0.6", + "@types/lodash.random": "^3.2.6", + "@types/lodash.throttle": "^4.1.6", + "@types/node": "^15.12.4", + "@types/react": "^17.0.8", "@vercel/fetch": "^6.1.0", "autoprefixer": "^10.2.6", "body-scroll-lock": "^3.1.5", "classnames": "^2.3.1", "cookie": "^0.4.1", + "deepmerge": "^4.2.2", "email-validator": "^2.0.4", + "graphql": "^15.5.1", + "husky": "^6.0.0", "immutability-helper": "^3.1.1", "js-cookie": "^2.2.1", "keen-slider": "^5.5.1", + "lint-staged": "^11.0.0", "lodash.debounce": "^4.0.8", "lodash.random": "^3.2.0", "lodash.throttle": "^4.1.1", @@ -36,7 +53,10 @@ "next-seo": "^4.26.0", "next-themes": "^0.0.14", "postcss": "^8.3.5", + "postcss-flexbugs-fixes": "^5.0.2", "postcss-nesting": "^8.0.1", + "postcss-preset-env": "^6.7.0", + "prettier": "^2.3.0", "react": "^17.0.2", "react-dom": "^17.0.2", "react-fast-marquee": "^1.1.4", @@ -46,28 +66,9 @@ "swr": "^0.5.6", "tabbable": "^5.2.0", "tailwindcss": "^2.2.2", - "uuidv4": "^6.2.10", - "@graphql-codegen/cli": "^1.21.5", - "@graphql-codegen/schema-ast": "^1.18.3", - "@graphql-codegen/typescript": "^1.22.2", - "@graphql-codegen/typescript-operations": "^1.18.1", - "@next/bundle-analyzer": "^10.2.3", - "@types/body-scroll-lock": "^2.6.1", - "@types/cookie": "^0.4.0", - "@types/js-cookie": "^2.2.6", - "@types/lodash.debounce": "^4.0.6", - "@types/lodash.random": "^3.2.6", - "@types/lodash.throttle": "^4.1.6", - "@types/node": "^15.12.4", - "@types/react": "^17.0.8", - "deepmerge": "^4.2.2", - "graphql": "^15.5.1", - "husky": "^6.0.0", - "lint-staged": "^11.0.0", - "postcss-flexbugs-fixes": "^5.0.2", - "postcss-preset-env": "^6.7.0", - "prettier": "^2.3.0", - "typescript": "4.3.4" + "typescript": "4.3.4", + "uuid": "^8.3.2", + "uuidv4": "^6.2.10" }, "devDependencies": {}, "husky": { diff --git a/theme/dap/checkout/CheckoutSidebarView/CheckoutSidebarView.module.css b/theme/dap/checkout/CheckoutSidebarView/CheckoutSidebarView.module.css new file mode 100644 index 000000000..34c1b487c --- /dev/null +++ b/theme/dap/checkout/CheckoutSidebarView/CheckoutSidebarView.module.css @@ -0,0 +1,7 @@ +.root { + min-height: calc(100vh - 322px); +} + +.lineItemsList { + @apply py-4 space-y-6 sm:py-0 sm:space-y-0 sm:divide-y sm:divide-accent-2 border-accent-2; +} diff --git a/theme/dap/checkout/CheckoutSidebarView/CheckoutSidebarView.tsx b/theme/dap/checkout/CheckoutSidebarView/CheckoutSidebarView.tsx new file mode 100644 index 000000000..9a87159dd --- /dev/null +++ b/theme/dap/checkout/CheckoutSidebarView/CheckoutSidebarView.tsx @@ -0,0 +1,124 @@ +import cn from 'classnames' +import Link from 'next/link' +import { FC } from 'react' +import CartItem from '@components/cart/CartItem' +import { Button, Text } from '@components/ui' +import { useUI } from '@components/ui/context' +import useCart from '@framework/cart/use-cart' +import usePrice from '@framework/product/use-price' +import ShippingWidget from '@components/checkout/ShippingWidget' +import PaymentWidget from '@components/checkout/PaymentWidget' +import SidebarLayout from '@components/common/SidebarLayout' +import s from './CheckoutSidebarView.module.css' +import { transitionOrderToStateMutation } from '@framework/utils/mutations/transition-order-to-state-mutation' +import { addPaymentToOrderMutation } from '@framework/utils/mutations/add-payment-to-order-mutation' +import request from '@commerce/utils/request' + +const CheckoutSidebarView: FC = () => { + const { setSidebarView, closeSidebarIfPresent } = useUI() + const { data } = useCart() + + const { price: subTotal } = usePrice( + data && { + amount: Number(data.subtotalPrice), + currencyCode: data.currency.code, + } + ) + const { price: total } = usePrice( + data && { + amount: Number(data.totalPrice), + currencyCode: data.currency.code, + } + ) + + const transitionOrderToState = async () => { + const data = await request({ + query: transitionOrderToStateMutation, + variables: { + state: 'ArrangingPayment' + } + }) + console.log(data, 777) + } + const addPaymentToOrder = async () => { + const data = await request({ + query: addPaymentToOrderMutation, + variables: { + input: { + "method": "cash", + "metadata": "{id:'nagyt pull'}" + } + } + }) + } + const handleConfirmPurchase = async (e: React.SyntheticEvent) => { + e.preventDefault() + + try { + await transitionOrderToState() + await addPaymentToOrder() + closeSidebarIfPresent() + console.log('Purchased') + } catch ({ errors }) { + console.log(errors, 444) + } + } + return ( + setSidebarView('CART_VIEW')} + > +
+ + Checkout + + + {/* setSidebarView('PAYMENT_VIEW')} /> */} + setSidebarView('SHIPPING_VIEW')} /> + +
    + {data!.lineItems.map((item: any) => ( + + ))} +
+
+ +
+
    +
  • + Subtotal + {subTotal} +
  • +
  • + Taxes + Calculated at checkout +
  • +
  • + Shipping + FREE +
  • +
+
+ Total + {total} +
+
+ {/* Once data is correcly filled */} + + {/* */} +
+
+
+ ) +} + +export default CheckoutSidebarView diff --git a/theme/dap/checkout/CheckoutSidebarView/index.ts b/theme/dap/checkout/CheckoutSidebarView/index.ts new file mode 100644 index 000000000..168bc58f4 --- /dev/null +++ b/theme/dap/checkout/CheckoutSidebarView/index.ts @@ -0,0 +1 @@ +export { default } from './CheckoutSidebarView' diff --git a/theme/dap/checkout/ShippingView/ShippingView.module.css b/theme/dap/checkout/ShippingView/ShippingView.module.css new file mode 100644 index 000000000..157d3174e --- /dev/null +++ b/theme/dap/checkout/ShippingView/ShippingView.module.css @@ -0,0 +1,21 @@ +.fieldset { + @apply flex flex-col my-3; +} + +.fieldset .label { + @apply text-accent-7 uppercase text-xs font-medium mb-2; +} + +.fieldset .input, +.fieldset .select { + @apply p-2 border border-accent-2 w-full text-sm font-normal; +} + +.fieldset .input:focus, +.fieldset .select:focus { + @apply outline-none shadow-outline-normal; +} + +.radio { + @apply bg-black; +} diff --git a/theme/dap/checkout/ShippingView/ShippingView.tsx b/theme/dap/checkout/ShippingView/ShippingView.tsx new file mode 100644 index 000000000..0afa82a89 --- /dev/null +++ b/theme/dap/checkout/ShippingView/ShippingView.tsx @@ -0,0 +1,155 @@ +import { FC, useState } from 'react' +import cn from 'classnames' +import s from './ShippingView.module.css' +import { Button, Input } from '@components/ui' +import { useUI } from '@components/ui/context' +import SidebarLayout from '@components/common/SidebarLayout' + +import { v4 as uuid } from 'uuid' +import { setCustomerForOrderMutation } from '@framework/utils/mutations/set-customer-for-order-mutation' +import { setOrderShippingAddressMutation } from '@framework/utils/mutations/set-order-shipping-address-mutation' +import request from '@commerce/utils/request' + +const PaymentMethodView: FC = () => { + // Form State + const [firstName, setFirstName] = useState('') + const [lastName, setLastName] = useState('') + const [phoneNumber, setPhoneNumber] = useState('') + const [email, setEmail] = useState('') + const [streetDetails, setStreetDetails] = useState('') + const [apartmentDetails, setApartmentDetails] = useState('') + const [loading, setLoading] = useState(false) + + const { setSidebarView } = useUI() + + const setCustomerForOrder = async () => { + console.log('Setting customer') + const data = await request({ + query: setCustomerForOrderMutation, + variables: { + input: { + title: `${firstName} ${lastName}`, + firstName: firstName, + lastName: lastName, + phoneNumber: phoneNumber, + emailAddress: `${email}+${uuid().split('-')[0]}` + } + } + }) + console.log(data, 111) + } + const addShippingAddress = async () => { + console.log('Add shipping address') + const data = await request({ + query: setOrderShippingAddressMutation, + variables: { + input: { + fullName: `${firstName} ${lastName}`, + phoneNumber: phoneNumber, + streetLine1: streetDetails, + streetLine2: apartmentDetails, + countryCode: "TM" + } + } + }) + console.log(data, 222) + } + + const handleAddShippingAddress = async (e: React.SyntheticEvent) => { + e.preventDefault() + + console.log('Handle Add Shipping Address') + + try { + setLoading(true) + await setCustomerForOrder() + await addShippingAddress() + setLoading(false) + setSidebarView('CHECKOUT_VIEW') + } catch ({ errors }) { + console.log(errors, 333) + } + + } + return ( + setSidebarView('CHECKOUT_VIEW')}> +
+
+

+ Shipping +

+ +
+ {/*
+ + Same as billing address +
+
+ + + Use a different shipping address + +
+
*/} +
+
+ + +
+
+ + +
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+ {/*
+
+ + +
+
+ + +
+
*/} + {/*
+ + +
*/} +
+
+
+ +
+
+
+ ) +} + +export default PaymentMethodView diff --git a/theme/dap/checkout/ShippingView/index.ts b/theme/dap/checkout/ShippingView/index.ts new file mode 100644 index 000000000..428e7e4fe --- /dev/null +++ b/theme/dap/checkout/ShippingView/index.ts @@ -0,0 +1 @@ +export { default } from './ShippingView' diff --git a/yarn.lock b/yarn.lock index 62b7698cd..1ee38843f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6049,7 +6049,7 @@ util@^0.12.0: safe-buffer "^5.1.2" which-typed-array "^1.1.2" -uuid@8.3.2: +uuid@8.3.2, uuid@^8.3.2: version "8.3.2" resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==