@hanzo/commerce 1.1.0 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  'use client'
2
- import React, { type PropsWithChildren, useState } from 'react'
2
+ import React, { type PropsWithChildren } from 'react'
3
3
  import { useRouter } from 'next/navigation'
4
4
  import { observer } from 'mobx-react-lite'
5
5
 
@@ -23,18 +23,9 @@ const Cart: React.FC<PropsWithChildren & {
23
23
  isMobile=false,
24
24
  hideCheckout=false
25
25
  }) => {
26
- const [loadingCheckout, setLoadingCheckout] = useState(false)
27
26
  const cmmc = useCommerce()
28
27
  const router = useRouter()
29
28
  const auth = useAuth()
30
-
31
- const checkout = async () => {
32
- setLoadingCheckout(true)
33
- if (auth.user) {
34
- await cmmc.createOrder(auth.user.email)
35
- }
36
- router.push('/checkout')
37
- }
38
29
 
39
30
  return (
40
31
  <div className={cn('border p-6 rounded-lg', className)}>
@@ -50,10 +41,10 @@ const Cart: React.FC<PropsWithChildren & {
50
41
  </div>
51
42
  {cmmc.cartItems.length > 0 && !hideCheckout && (
52
43
  <>
53
- {!auth.loggedIn ? (
44
+ {!(auth && auth.loggedIn) ? (
54
45
  <Button size='sm' variant='secondary' rounded='lg' className='mt-12 mx-auto' onClick={() => router.push('/login?redirectUrl=checkout')}>Login to checkout</Button>
55
46
  ) : (
56
- <Button size='lg' variant='secondary' rounded='lg' className='mt-12 mx-auto' onClick={checkout} disabled={loadingCheckout}>Checkout</Button>
47
+ <Button size='lg' variant='secondary' rounded='lg' className='mt-12 mx-auto' onClick={() => router.push('/checkout')}>Checkout</Button>
57
48
  )}
58
49
  </>
59
50
  )}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hanzo/commerce",
3
- "version": "1.1.0",
3
+ "version": "1.1.1",
4
4
  "description": "Library with shopping cart components.",
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org/",
@@ -23,12 +23,52 @@ const getDBInstance = (name: string): Firestore => {
23
23
 
24
24
  interface SavedOrder {
25
25
  email: string
26
+ paymentMethod: string
27
+ status: string
26
28
  timestamp: FieldValue
27
29
  items: ActualLineItemSnapshot[]
28
30
  }
29
31
 
30
32
  const createOrder = async (
31
33
  email: string,
34
+ paymentMethod: string,
35
+ items: ActualLineItemSnapshot[],
36
+ options: {
37
+ dbName: string
38
+ ordersTable: string
39
+ }
40
+ ): Promise<{
41
+ success: boolean,
42
+ error: any,
43
+ id?: string
44
+ }> => {
45
+
46
+ let error: any | null = null
47
+ const ordersRef = collection(getDBInstance(options.dbName), options.ordersTable)
48
+ const orderId = `${email}-${new Date().toISOString()}`
49
+
50
+ try {
51
+ await setDoc(doc(ordersRef, orderId), {
52
+ email,
53
+ paymentMethod,
54
+ status: 'open',
55
+ timestamp: serverTimestamp(),
56
+ items,
57
+ } satisfies SavedOrder)
58
+ return { success: !error, error, id: orderId }
59
+ }
60
+ catch (e) {
61
+ console.error('Error writing item document: ', e)
62
+ error = e
63
+ }
64
+
65
+ return { success: !error, error }
66
+ }
67
+
68
+ const updateOrder = async (
69
+ orderId: string,
70
+ email: string,
71
+ paymentMethod: string,
32
72
  items: ActualLineItemSnapshot[],
33
73
  options: {
34
74
  dbName: string
@@ -43,8 +83,10 @@ const createOrder = async (
43
83
  const ordersRef = collection(getDBInstance(options.dbName), options.ordersTable)
44
84
 
45
85
  try {
46
- await setDoc(doc(ordersRef, `${email}-${new Date().toISOString()}`), {
86
+ await setDoc(doc(ordersRef, orderId), {
47
87
  email,
88
+ paymentMethod,
89
+ status: 'open',
48
90
  timestamp: serverTimestamp(),
49
91
  items,
50
92
  } satisfies SavedOrder)
@@ -57,4 +99,4 @@ const createOrder = async (
57
99
  return { success: !error, error }
58
100
  }
59
101
 
60
- export { createOrder }
102
+ export { createOrder, updateOrder }
@@ -15,7 +15,10 @@ import type {
15
15
  FacetsDesc
16
16
  } from '../../../types'
17
17
 
18
- import { createOrder as createOrderHelper } from './orders'
18
+ import {
19
+ createOrder as createOrderHelper,
20
+ updateOrder as updateOrderHelper
21
+ } from './orders'
19
22
 
20
23
  import ActualLineItem, { type ActualLineItemSnapshot } from './actual-line-item'
21
24
 
@@ -84,9 +87,15 @@ class StandaloneService
84
87
  })
85
88
  }
86
89
 
87
- async createOrder(email: string): Promise<void> {
90
+ async createOrder(email: string, paymentMethod: string): Promise<string | undefined> {
88
91
  const snapshot = this.takeSnapshot()
89
- createOrderHelper(email, snapshot.items, this._options) // didn't want to have two levels of 'items'
92
+ const order = await createOrderHelper(email, paymentMethod, snapshot.items, this._options) // didn't want to have two levels of 'items'
93
+ return order.id
94
+ }
95
+
96
+ async updateOrder(orderId: string, email: string, paymentMethod: string): Promise<void> {
97
+ const snapshot = this.takeSnapshot()
98
+ updateOrderHelper(orderId, email, paymentMethod, snapshot.items, this._options) // didn't want to have two levels of 'items'
90
99
  }
91
100
 
92
101
  takeSnapshot = (): StandaloneServiceSnapshot => ({
@@ -127,13 +136,14 @@ class StandaloneService
127
136
  }
128
137
  }
129
138
  }
130
-
131
- let foundItem: ActualLineItem | undefined = undefined
132
- this._categoryMap.forEach((category, categoryId) => {
133
- if (foundItem) return
134
- if (categoriesTried.includes(categoryId)) return
135
- foundItem = category.products.find((p) => (p.sku === skuToFind)) as ActualLineItem | undefined
136
- })
139
+ for( const [categoryId, category] of this._categoryMap.entries()) {
140
+ if (categoriesTried.includes(categoryId)) continue
141
+ const foundItem = category.products.find((p) => (p.sku === skuToFind)) as ActualLineItem | undefined
142
+ if (foundItem) {
143
+ return foundItem as ActualLineItem
144
+ }
145
+ }
146
+ return undefined
137
147
  })();
138
148
 
139
149
  return !!this._currentItem
@@ -8,7 +8,8 @@ interface CommerceService extends ObsLineItemRef {
8
8
  get cartTotal(): number
9
9
  getCartCategorySubtotal(categoryId: string): number
10
10
 
11
- createOrder(email: string): Promise<void>
11
+ createOrder(email: string, paymentMethod: string): Promise<string | undefined>
12
+ updateOrder(orderId: string, email: string, paymentMethod: string): Promise<void>
12
13
 
13
14
  /**
14
15
  * Sets the tokens at each level supplied.
@@ -29,7 +30,7 @@ interface CommerceService extends ObsLineItemRef {
29
30
  * "current" is unrelated to what is "specified",
30
31
  * ie, facets' values
31
32
  * */
32
- setCurrentItem(sku: string | undefined): boolean // was valid sku and was set.
33
+ setCurrentItem(sku: string | undefined): boolean // valid sku and was set.
33
34
  /**
34
35
  * For convenience, so widgets can share state.
35
36
  * "current" is unrelated to what is "specified",
@@ -22,6 +22,7 @@ interface GetMutator {
22
22
  }
23
23
 
24
24
  const useSkuAndFacetParams = (
25
+ setMessage: (m: string | undefined) => void,
25
26
  setLoading?: (l: boolean) => void
26
27
  ) => {
27
28
 
@@ -50,8 +51,6 @@ const useSkuAndFacetParams = (
50
51
  parseAsBoolean.withDefault(false).withOptions({ clearOnDefault: true })
51
52
  )
52
53
 
53
- const [message, setMessage] = useState<string | undefined>(undefined)
54
-
55
54
  const directMutator: GetMutator = (level: 1 | 2): StringMutator => {
56
55
 
57
56
  const setLevel = (value: string, level: 1 | 2 ): void => {
@@ -84,6 +83,8 @@ const useSkuAndFacetParams = (
84
83
  }
85
84
  }
86
85
 
86
+ let message: string | undefined = undefined
87
+
87
88
  useEffect(() => {
88
89
 
89
90
  const setCurrentCategoryFromSku = (sku: string) => {
@@ -111,14 +112,14 @@ const useSkuAndFacetParams = (
111
112
  }
112
113
  })
113
114
  }
114
- setMessage(undefined)
115
115
  encRef.current.usingSkuMode = true
116
116
  }
117
117
  else {
118
+
118
119
  setSkuParam('')
119
120
  // if sent here w an invalid sku,
120
121
  // it will effectively put us in facet params mode
121
- setMessage('Invalid sku. ' + PLEASE_SELECT_FACETS)
122
+ message = 'Invalid sku. ' + PLEASE_SELECT_FACETS
122
123
  }
123
124
  }
124
125
 
@@ -148,7 +149,6 @@ const useSkuAndFacetParams = (
148
149
  const categories = cmmc.setFacets(facets)
149
150
  if (categories && categories.length > 0) {
150
151
  cmmc.setCurrentItem(categories[0].products[0].sku)
151
- setMessage(undefined)
152
152
  }
153
153
  else {
154
154
  cmmc.setCurrentItem(undefined)
@@ -156,17 +156,15 @@ const useSkuAndFacetParams = (
156
156
  }
157
157
  }
158
158
  else {
159
- setMessage(PLEASE_SELECT_FACETS)
159
+ setMessage(message ?? PLEASE_SELECT_FACETS)
160
160
  }
161
161
  setLoading && setLoading(false)
162
162
  }, [level1 , level2])
163
163
 
164
164
  return {
165
- message,
166
165
  getMutator: encRef.current.usingSkuMode ?
167
166
  directMutator : paramsMutator
168
167
  }
169
-
170
168
  }
171
169
 
172
170
  export default useSkuAndFacetParams