@subiz/widget-v4 4.0.58 → 4.0.63

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.
Files changed (156) hide show
  1. package/assets/img/caret.svg +1 -0
  2. package/assets/img/done_green.svg +4 -0
  3. package/assets/img/empty_1.svg +11 -0
  4. package/assets/img/ghn.svg +17 -0
  5. package/assets/img/ghtk.svg +18 -0
  6. package/assets/img/home.svg +1 -0
  7. package/assets/img/info.svg +1 -0
  8. package/assets/img/loader.svg +1 -0
  9. package/assets/img/map-pin.svg +1 -0
  10. package/assets/img/not_found_search.png +0 -0
  11. package/assets/img/package.svg +5 -0
  12. package/assets/img/package_fade.svg +1 -0
  13. package/assets/img/phone.svg +1 -0
  14. package/assets/img/search.svg +1 -0
  15. package/assets/img/shop.svg +1 -0
  16. package/assets/img/shop_faded.svg +1 -0
  17. package/assets/img/user.svg +1 -0
  18. package/assets/img/x.svg +5 -0
  19. package/assets/less/chatbox.less +35 -0
  20. package/assets/less/dropdown_select.less +130 -0
  21. package/assets/less/form.less +7 -20
  22. package/assets/less/order.less +489 -0
  23. package/assets/less/rating.less +3 -8
  24. package/compiled_src/call/call.js +12 -15
  25. package/compiled_src/chatbox/DropdownSelect.js +239 -0
  26. package/compiled_src/chatbox/Event.js +4 -2
  27. package/compiled_src/chatbox/Events.js +1 -0
  28. package/compiled_src/chatbox/MessageInput.js +4 -7
  29. package/compiled_src/chatbox/Order.js +281 -0
  30. package/compiled_src/chatbox/OrderAttachments.js +2 -1
  31. package/compiled_src/chatbox/Rating.js +7 -10
  32. package/compiled_src/chatbox/TextMessage.js +9 -2
  33. package/compiled_src/chatbox/Widget.js +40 -3
  34. package/compiled_src/chatbox/main.js +2 -1
  35. package/compiled_src/chatbox/spinner.js +1 -1
  36. package/compiled_src/chatbox/time.js +3 -1
  37. package/compiled_src/common.js +40 -1
  38. package/compiled_src/contact/contact.js +7 -12
  39. package/compiled_src/lib.js +9 -14
  40. package/compiled_src/notif/notif.js +12 -15
  41. package/compiled_src/order/address_picker.js +241 -0
  42. package/compiled_src/order/icon.js +62 -0
  43. package/compiled_src/order/index.js +113 -0
  44. package/compiled_src/order/order.js +1220 -0
  45. package/compiled_src/plugin.js +9 -42
  46. package/compiled_src/popup/countdown.js +4 -7
  47. package/compiled_src/popup/popup.js +40 -13
  48. package/compiled_src/store/api.js +80 -90
  49. package/compiled_src/store/api_fake.js +55 -82
  50. package/compiled_src/store/store.js +163 -158
  51. package/compiled_src/util/common.js +40 -4
  52. package/dist/0b82fa7e5c3b07b40a44.png +1 -0
  53. package/dist/0f4af006e38ee8b93633.png +1 -0
  54. package/dist/{74.js → 132.js} +2234 -236
  55. package/dist/178.js +341 -174
  56. package/dist/17e757ccadd.132.js +1 -0
  57. package/dist/17e757ccadd.178.js +1 -0
  58. package/dist/17e757ccadd.213.js +1 -0
  59. package/dist/17e757ccadd.335.js +1 -0
  60. package/dist/17e757ccadd.362.js +1 -0
  61. package/dist/17e757ccadd.441.js +1 -0
  62. package/dist/17e757ccadd.605.js +1 -0
  63. package/dist/17e757ccadd.678.js +1 -0
  64. package/dist/17e757ccadd.782.js +1 -0
  65. package/dist/17e757ccadd.app.js +1 -0
  66. package/dist/{17d938a5acb.index.html → 17e757ccadd.index.html} +3 -18
  67. package/dist/{17d938a5acb.library.html → 17e757ccadd.library.html} +3 -18
  68. package/dist/17e757ccadd.library.js +1 -0
  69. package/dist/{17d938a5acb.preview.html → 17e757ccadd.preview.html} +1 -1
  70. package/dist/17e757ccadd.preview.js +1 -0
  71. package/dist/17e757ccadd.screenshoot.js +1 -0
  72. package/dist/1ea1c6cd21d25176810c.png +1 -0
  73. package/dist/213.js +46 -87
  74. package/dist/292d42404e1b03398f61.png +1 -0
  75. package/dist/312d376370831b7bea83.png +1 -0
  76. package/dist/313d1bfc1cf776d1aefe.png +1 -0
  77. package/dist/335.js +408 -0
  78. package/dist/362.js +71 -21
  79. package/dist/441.js +69 -43
  80. package/dist/4aa58bb7a66bb44975aa.png +1 -0
  81. package/dist/56ce063bc6c81adb7322.png +1 -0
  82. package/dist/605.js +13 -79
  83. package/dist/678.js +70 -20
  84. package/dist/6a411166ef5cc79e0714.png +1 -0
  85. package/dist/6faf403782fefacc1649.png +1 -0
  86. package/dist/782.js +118 -21
  87. package/dist/79dca33c68fab79c067f.png +1 -0
  88. package/dist/82da1578fa84f9debaeb.png +1 -0
  89. package/dist/8b8e0f0824743974b282.png +1 -0
  90. package/dist/8d551390d81e39130a3c.png +1 -0
  91. package/dist/9fc61b9479877ebdb6c7.png +1 -0
  92. package/dist/HASH +1 -1
  93. package/dist/a165d31dcb3dc90f1057.png +1 -0
  94. package/dist/a98d4a5698812c4426b3.png +1 -0
  95. package/dist/assets/img/caret.998eb8f.svg +1 -0
  96. package/dist/assets/img/done_green.b817fd4.svg +4 -0
  97. package/dist/assets/img/empty_1.0b98af0.svg +11 -0
  98. package/dist/assets/img/ghn.070f8e3.svg +17 -0
  99. package/dist/assets/img/ghtk.326eac1.svg +18 -0
  100. package/dist/assets/img/info.ebce7ea.svg +1 -0
  101. package/dist/assets/img/loader.37000a7.svg +1 -0
  102. package/dist/assets/img/not_found_search.2ddb8d1.png +0 -0
  103. package/dist/assets/img/package.8d37d0f.svg +5 -0
  104. package/dist/assets/img/package_fade.763c001.svg +1 -0
  105. package/dist/assets/img/search.f9705ff.svg +1 -0
  106. package/dist/assets/img/shop.f7dc7d8.svg +1 -0
  107. package/dist/assets/img/shop_faded.df7845a.svg +1 -0
  108. package/dist/assets/img/x.26fdfa3.svg +5 -0
  109. package/dist/c41606bf9d1b604e46d5.png +1 -0
  110. package/dist/ce1f7450ce6c1aacd330.png +1 -0
  111. package/dist/cf8c01e88f4770a6e3e5.png +1 -0
  112. package/dist/dfbcfeab1d5622a737e2.png +1 -0
  113. package/dist/e4893ed8c2f7b8329919.png +1 -0
  114. package/dist/ec2ab4eb4ef73d186186.png +1 -0
  115. package/dist/screenshoot.html +1 -1
  116. package/dist/screenshoot.js +452 -389
  117. package/index.html +3 -18
  118. package/order.html +32 -0
  119. package/package.json +13 -14
  120. package/src/chatbox/DropdownSelect.js +229 -0
  121. package/src/chatbox/Event.js +2 -2
  122. package/src/chatbox/Events.js +43 -42
  123. package/src/chatbox/Order.js +232 -0
  124. package/src/chatbox/OrderAttachments.js +2 -1
  125. package/src/chatbox/TextMessage.js +21 -12
  126. package/src/chatbox/Widget.js +34 -4
  127. package/src/chatbox/main.js +2 -2
  128. package/src/chatbox/spinner.js +1 -1
  129. package/src/chatbox/time.js +1 -1
  130. package/src/common.js +52 -8
  131. package/src/contact/contact.js +1 -1
  132. package/src/order/address_picker.js +235 -0
  133. package/src/order/icon.js +32 -0
  134. package/src/order/index.js +86 -0
  135. package/src/order/order.js +1157 -0
  136. package/src/order/scratch +211 -0
  137. package/src/plugin.js +7 -52
  138. package/src/popup/popup.js +27 -2
  139. package/src/store/api.js +26 -1
  140. package/src/store/store.js +46 -9
  141. package/src/util/common.js +52 -4
  142. package/webpack.dev.js +2 -0
  143. package/dist/17d938a5acb.178.js +0 -1
  144. package/dist/17d938a5acb.213.js +0 -1
  145. package/dist/17d938a5acb.362.js +0 -1
  146. package/dist/17d938a5acb.441.js +0 -1
  147. package/dist/17d938a5acb.605.js +0 -1
  148. package/dist/17d938a5acb.619.js +0 -1
  149. package/dist/17d938a5acb.678.js +0 -1
  150. package/dist/17d938a5acb.74.js +0 -1
  151. package/dist/17d938a5acb.782.js +0 -1
  152. package/dist/17d938a5acb.app.js +0 -1
  153. package/dist/17d938a5acb.library.js +0 -1
  154. package/dist/17d938a5acb.preview.js +0 -1
  155. package/dist/17d938a5acb.screenshoot.js +0 -1
  156. package/dist/619.js +0 -777
@@ -0,0 +1,1157 @@
1
+ import sb from '../util/index.js'
2
+ import Time from '../chatbox/time.js'
3
+ import * as common from '../common.js'
4
+ import DropdownSelect from '../chatbox/DropdownSelect.js'
5
+ import AddressPicker from './address_picker.js'
6
+ import {h, createRef, render, Fragment} from 'preact'
7
+ import Icon from './icon.js'
8
+ import Spinner from '../chatbox/spinner.js'
9
+
10
+ var checkedimg = require('../../assets/img/done_green.svg')
11
+ var ximg = require('../../assets/img/x.svg')
12
+
13
+ export default class Order extends common.Com {
14
+ state = {
15
+ loadProvince: true,
16
+
17
+ g_err: '',
18
+ fullname: '',
19
+ email: '',
20
+ phone: '',
21
+ loading: true,
22
+ order: {},
23
+ err: {},
24
+
25
+ selectedProvince: null,
26
+ selectedDistrict: null,
27
+ selectedWard: null,
28
+ street: '',
29
+ address: '',
30
+
31
+ sending: false,
32
+
33
+ step: '',
34
+ }
35
+
36
+ constructor(props) {
37
+ super(props)
38
+ this.load()
39
+ }
40
+
41
+ async load() {
42
+ if (!this.props.order_id) return
43
+ let orderout = await this.props.store.fetchOrder(this.props.order_id)
44
+ this.setState({loading: false})
45
+ if (!orderout.error) {
46
+ this.setState({order: orderout.body})
47
+ } else {
48
+ this.setState({error: orderout.error})
49
+ }
50
+
51
+ let user = this.props.store.matchUser()
52
+ let attributes = sb.get(this.props.store.matchUser(), 'attributes', [])
53
+ let fullname = sb.get(
54
+ sb.find(attributes, (att) => att.key === 'fullname'),
55
+ 'text',
56
+ )
57
+ let email = sb.get(
58
+ sb.find(attributes, (att) => att.key === 'emails'),
59
+ 'text',
60
+ )
61
+ let phone = sb.get(
62
+ sb.find(attributes, (att) => att.key === 'phones'),
63
+ 'text',
64
+ )
65
+ this.setState({fullname, email, phone})
66
+
67
+ await this.props.store.fetchShippingAddresses()
68
+
69
+ let out = await this.props.store.list_provinces()
70
+ this.setState({loadProvince: false})
71
+ if (!out.error) this.setState({provinces: sb.get(out, 'body.addresses')})
72
+ }
73
+
74
+ isMobile() {
75
+ if (this.props.cid) return true
76
+ if (this.props.isMobile) return true
77
+ return this.props.store.isMobile()
78
+ }
79
+
80
+ onChangeShippingAddress(id) {
81
+ this.setState({shipping_address: id, err: {}, g_err: ''})
82
+ }
83
+
84
+ renderMobileSuccess = (order) => {
85
+ return (
86
+ <div class='order' style='height: 100% !important'>
87
+ <div style='display: flex !important; align-items: center !important; padding-top: 40px !important; padding-bottom: 20px !important; flex-direction: column !important; height: 100% !important'>
88
+ <img style='width: 60px !important; height: 60px !important;' width='60' height='60' src={checkedimg} />
89
+ <div style='margin-top: 20px !important; margin-bottom: 10px !important'>
90
+ <b style='font-size: 18px !important;'>Đơn hàng của bạn đã được ghi nhận</b>
91
+ </div>
92
+ <div class='muted'>Tôi sẽ liên hệ lại với bạn khi đơn hàng được xử lý</div>
93
+ <div style='flex:1 !important'></div>
94
+ <div style='margin-top: 20px !important; padding: 0px 20px 0 20px !important; width: 100% !important'>
95
+ <div class='order_btn order__btn__light' onClick={this.close}>
96
+ {this.props.t('close')}
97
+ </div>
98
+ </div>
99
+ </div>
100
+ </div>
101
+ )
102
+ }
103
+
104
+ onChangeShipping(id) {
105
+ this.setState({shipping: id, err: {}, g_err: ''})
106
+ }
107
+
108
+ onSelectProvince = async (item) => {
109
+ this.setState({selectedProvince: item, err: {}, g_err: ''})
110
+ this.setState({loadDistrict: true})
111
+ let out = await this.props.store.list_districts({id: item.id})
112
+ this.setState({loadDistrict: false})
113
+ if (!out.error) this.setState({districts: sb.get(out, 'body.addresses')})
114
+ }
115
+
116
+ onSelectDistrict = async (item) => {
117
+ this.setState({selectedDistrict: item, err: {}, g_err: ''})
118
+ this.setState({loadWard: true})
119
+ let out = await this.props.store.list_wards({id: item.id})
120
+ this.setState({loadWard: false})
121
+ if (!out.error) this.setState({wards: sb.get(out, 'body.addresses')})
122
+ }
123
+
124
+ onSelectWard = (item) => this.setState({selectedWard: item, err: {}, g_err: ''})
125
+ onChangeFullname = (e) => this.setState({fullname: e.target.value, err: {}, g_err: ''})
126
+ onChangeAddress = (e) => this.setState({address: e, err: {}, g_err: ''})
127
+ onSelectAddress = (addr) => {
128
+ if (!addr) return
129
+ this.setState({
130
+ address: [sb.trim(addr.address), sb.trim(addr.street)].join(' ').trim(),
131
+ street: addr.street,
132
+ err: {},
133
+ g_err: '',
134
+ })
135
+
136
+ this.onSelectWard({id: addr.ward_id, name: addr.ward})
137
+ this.onSelectDistrict({id: addr.district_id, name: addr.district})
138
+ this.onSelectProvince({id: addr.province_id, name: addr.province})
139
+ }
140
+ onChangeEmail = (e) => this.setState({email: e.target.value, err: {}, g_err: ''})
141
+ onChangePhone = (e) => this.setState({phone: e.target.value, err: {}, g_err: ''})
142
+ onChangePaymentMethod = (id) => this.setState({pm: id})
143
+
144
+ renderDesktopPaymentMethod(order) {
145
+ return null
146
+ let editmode = false
147
+ if (!order.status || order.status == 'new') {
148
+ editmode = !order.user_confirmation
149
+ }
150
+
151
+ if (editmode) {
152
+ let pms = this.props.store.matchPaymentMethods()
153
+
154
+ let $pms = sb.map(pms, (pm) => {
155
+ let $name = pm.description
156
+ if (pm.method == 'bank_transfer') {
157
+ $name = pm.description + ' ' + pm.bank_name + ' ' + pm.bank_branch
158
+ }
159
+ let cls = 'order__card'
160
+ let $desc = null
161
+ if (this.state.pm === pm.id) {
162
+ cls += ' order__card__active'
163
+
164
+ $desc = (
165
+ <div class='muted mt-1' style='margin-left: 26px !important;'>
166
+ Trả tiền mặt khi bạn nhận hàng
167
+ </div>
168
+ )
169
+
170
+ if (pm.method == 'bank_transfer') {
171
+ $desc = (
172
+ <div class='muted mt-1' style='margin-left: 26px !important;'>
173
+ <div>STK: {pm.bank_number}</div>
174
+ <div>Chủ tài khoản: {pm.bank_owner}</div>
175
+ </div>
176
+ )
177
+ }
178
+ }
179
+
180
+ return (
181
+ <div style='width: 100% !important; margin-top: 10px !important;'>
182
+ <div class='radio'>
183
+ <input
184
+ type='radio'
185
+ id={'pm.' + pm.id}
186
+ onInput={(e) => this.onChangePaymentMethod(pm.id)}
187
+ name='pm'
188
+ checked={this.state.pm === pm.id}
189
+ />
190
+ <label
191
+ class='radio--label'
192
+ style={`margin-left: 4px !important; font-weight: ${this.state.pm === pm.id ? 500 : 400} !important;`}
193
+ for={'pm.' + pm.id}>
194
+ {$name}
195
+ </label>
196
+ <div class='radio--check'>
197
+ <div class='inside'></div>
198
+ </div>
199
+ {$desc}
200
+ </div>
201
+ </div>
202
+ )
203
+ })
204
+
205
+ let seccls = 'card_section'
206
+ if (this.isMobile()) seccls = 'order_section'
207
+
208
+ return (
209
+ <Fragment>
210
+ <div class='order_section__line'></div>
211
+ <div class={seccls}>
212
+ <div class='order_label'>{this.props.t('payment')}</div>
213
+ <div class='form' style='justify-content: space-between !important;'>
214
+ {$pms}
215
+ </div>
216
+ </div>
217
+ </Fragment>
218
+ )
219
+ }
220
+
221
+ let pm = order.payment_method || {method: 'cod'}
222
+
223
+ let $body = null
224
+ if (pm.method === 'cash') $body = <div>{this.props.t('pm_cash')}</div>
225
+ if (pm.method === 'cod') $body = <div>{this.props.t('pm_cod')}</div>
226
+ if (pm.method === 'bank_transfer') {
227
+ let name = pm.bank_name
228
+ if (pm.bank_branch) name += ' - ' + pm.bank_branch
229
+ $body = (
230
+ <div>
231
+ <div>Ngân hàng: {name}</div>
232
+ <div class='mt-1'>Chủ tài khoản: {pm.bank_owner}</div>
233
+ <div class='mt-1'>Số tài khoản: {pm.bank_number}</div>
234
+ </div>
235
+ )
236
+ }
237
+ if (!$body) return null
238
+
239
+ return (
240
+ <Fragment>
241
+ <div class='order_label'>{this.props.t('payment')}</div>
242
+ {$body}
243
+ </Fragment>
244
+ )
245
+ }
246
+
247
+ renderDesktopShipping(order) {
248
+ let editmode = false
249
+ if (!order.status || order.status == 'new') {
250
+ editmode = !order.user_confirmation
251
+ }
252
+
253
+ let user = this.props.store.matchUser()
254
+ if (editmode) {
255
+ let addresses = this.props.store.matchShippingAddresses()
256
+
257
+ let provinces = sb.map(this.state.provinces, (province) => ({id: province.id, name: province.province}))
258
+ let districts = sb.map(this.state.districts, (district) => ({id: district.id, name: district.district}))
259
+ let wards = sb.map(this.state.wards, (ward) => ({id: ward.id, name: ward.ward}))
260
+ let cls = 'ship_card'
261
+ let $body = null
262
+ let ship_icon_active = false
263
+
264
+ if (this.state.shipping === 'ship') {
265
+ ship_icon_active = true
266
+ let $preaddrs = sb.map(addresses, (addr) => {
267
+ let fulladdr = [addr.street, addr.ward, addr.district, addr.region, addr.country].filter((a) => a).join(', ')
268
+ let $phone = null
269
+ if (addr.phone) {
270
+ $phone = (
271
+ <Fragment>
272
+ &nbsp;·&nbsp;{this.props.t('phn')} {addr.phone}
273
+ </Fragment>
274
+ )
275
+ }
276
+ return (
277
+ <div style='margin-bottom: 15px !important'>
278
+ <div class='radio d-flex '>
279
+ <input
280
+ type='radio'
281
+ id={'shipping_addr.' + addr.id}
282
+ onInput={(e) => this.onChangeShippingAddress(addr.id)}
283
+ name='shipping_address'
284
+ checked={this.state.shipping_address === addr.id}
285
+ />
286
+ <label
287
+ class='radio--label'
288
+ for={'shipping_addr.' + addr.id}
289
+ style={`font-weight: ${this.state.shipping_address === addr.id ? 500 : 400} !important`}>
290
+ {addr.fullname}
291
+ {$phone}
292
+ <div class='mt-1 muted'>DC {fulladdr}</div>
293
+ </label>
294
+ <div class='radio--check'>
295
+ <div class='inside'></div>
296
+ </div>
297
+ </div>
298
+ </div>
299
+ )
300
+ })
301
+
302
+ $preaddrs.push(
303
+ <div style=''>
304
+ <div class='radio d-flex '>
305
+ <input
306
+ type='radio'
307
+ id={'shipping_addr.new'}
308
+ onInput={(e) => this.onChangeShippingAddress('new')}
309
+ name='shipping_address'
310
+ checked={this.state.shipping_address === 'new'}
311
+ />
312
+ <label class='radio--label' for={'shipping_addr.new'}>
313
+ {this.state.shipping_address === 'new' ? <b>Tới địa chỉ khác</b> : 'Tới địa chỉ khác'}
314
+ </label>
315
+ <div class='radio--check'>
316
+ <div class='inside'></div>
317
+ </div>
318
+ </div>
319
+ </div>,
320
+ )
321
+
322
+ let $new = (
323
+ <div style='padding-left: 22px !important;'>
324
+ <div class='d-flex'>
325
+ <div class='mr-2' style='flex: 1 !important;'>
326
+ <div class='order_form_label'>{this.props.t('fullname')}</div>
327
+ <input
328
+ type='text'
329
+ class={'form-control ' + (this.state.err.name && 'err')}
330
+ onInput={this.onChangeFullname}
331
+ value={this.state.fullname}
332
+ />
333
+ </div>
334
+ <div class='ml-2' style='flex: 1 !important;'>
335
+ <div class='order_form_label'>{this.props.t('phones')}</div>
336
+ <input
337
+ type='text'
338
+ class={'form-control ' + (this.state.err.phone && 'err')}
339
+ onInput={this.onChangePhone}
340
+ value={this.state.phone}
341
+ />
342
+ </div>
343
+ </div>
344
+
345
+ <div class='' style='width: 100% !important'>
346
+ <div class='order_form_label'>{this.props.t('address')}</div>
347
+ <AddressPicker
348
+ initAddress={this.state.address}
349
+ store={this.props.store}
350
+ width='100%'
351
+ onChangeAddress={this.onChangeAddress}
352
+ full={this.isMobile()}
353
+ onSelect={this.onSelectAddress}
354
+ extra_cls={this.state.err.address && 'err'}
355
+ />
356
+ </div>
357
+
358
+ <div class='d-flex' style='justify-content: space-between !important;'>
359
+ <div style='flex: 1 !important; overflow:hidden !important; margin-right: 7px !important;'>
360
+ <div class='order_form_label'>{this.props.t('province')}</div>
361
+ <DropdownSelect
362
+ width='194'
363
+ full={this.isMobile()}
364
+ has_search
365
+ loading={this.state.loadProvince}
366
+ items={provinces}
367
+ selected={this.state.selectedProvince}
368
+ onSelect={this.onSelectProvince}
369
+ extra_cls={this.state.err.province && 'err'}
370
+ />
371
+ </div>
372
+ <div style='flex: 1 !important; overflow:hidden !important; margin-left: 7px !important;'>
373
+ <div class='order_form_label'>{this.props.t('district')}</div>
374
+ <DropdownSelect
375
+ width='194'
376
+ full={this.isMobile()}
377
+ selected={this.state.selectedDistrict}
378
+ has_search
379
+ onSelect={this.onSelectDistrict}
380
+ loading={this.state.loadDistrict}
381
+ extra_cls={this.state.err.district && 'err'}
382
+ items={districts}
383
+ />
384
+ </div>
385
+ </div>
386
+ <div class='d-flex' style='justify-content: space-between !important;'>
387
+ <div style='flex: 1 !important; overflow:hidden !important; margin-right: 7px !important;'>
388
+ <div class='order_form_label'>{this.props.t('ward')}</div>
389
+ <DropdownSelect
390
+ width='194'
391
+ selected={this.state.selectedWard}
392
+ full={this.isMobile()}
393
+ has_search
394
+ onSelect={this.onSelectWard}
395
+ extra_cls={this.state.err.ward && 'err'}
396
+ loading={this.state.loadWard}
397
+ items={wards}
398
+ />
399
+ </div>
400
+ <div style='flex: 1 !important; margin-left: 7px !important;'></div>
401
+ </div>
402
+ </div>
403
+ )
404
+ cls += ' ship_card__active'
405
+ if (sb.size(addresses) == 0) {
406
+ $body = (
407
+ <div>
408
+ <div class={'mt-3 mb-2 '}>{this.props.t('input_shipping_info')}</div>
409
+ {$new}
410
+ </div>
411
+ )
412
+ } else {
413
+ if (this.state.shipping_address !== 'new') $new = null
414
+
415
+ $body = (
416
+ <div>
417
+ <div class='mt-3 mb-2' style='margin-bottom: 10px !important;'>
418
+ Vui lòng chọn địa chỉ giao hàng
419
+ </div>
420
+ <div class='form'>{$preaddrs}</div>
421
+ {$new}
422
+ </div>
423
+ )
424
+ }
425
+ }
426
+
427
+ let shopcls = 'ship_card'
428
+ let shop_icon_active = false
429
+ if (this.state.shipping === 'shop') {
430
+ shop_icon_active = true
431
+ shopcls += ' ship_card__active'
432
+ $body = (
433
+ <div>
434
+ <div class='d-flex'>
435
+ <div class='mr-2' style='flex: 3 !important;'>
436
+ <div class='order_form_label'>{this.props.t('fullname')}</div>
437
+ <input
438
+ type='text'
439
+ class={'form-control ' + (this.state.err.name && 'err')}
440
+ onInput={this.onChangeFullname}
441
+ value={this.state.fullname}
442
+ />
443
+ </div>
444
+ <div class='ml-2' style='flex: 2 !important;'>
445
+ <div class='order_form_label'>{this.props.t('phones')}</div>
446
+ <input
447
+ type='text'
448
+ class={'form-control ' + (this.state.err.phone && 'err')}
449
+ onInput={this.onChangePhone}
450
+ value={this.state.phone}
451
+ />
452
+ </div>
453
+ </div>
454
+ <div>
455
+ <div class='order_form_label'>{this.props.t('email')}</div>
456
+ <input
457
+ type='text'
458
+ class={'form-control ' + (this.state.err.email && 'err')}
459
+ onInput={this.onChangeEmail}
460
+ value={this.state.email}
461
+ />
462
+ </div>
463
+ </div>
464
+ )
465
+ }
466
+
467
+ // let $oldaddress = sb.map()
468
+
469
+ let seccls = 'card_section'
470
+ if (this.isMobile()) seccls = 'order_section'
471
+
472
+ return (
473
+ <Fragment>
474
+ <div class='order_section__line'></div>
475
+
476
+ <div class={seccls}>
477
+ <div class='order_label'>{this.props.t('ship_to')}</div>
478
+ <div class='d-flex'>
479
+ <div class={shopcls + ' mr-3'} onClick={(e) => this.onChangeShipping('shop')}>
480
+ <Icon name='shop' active={shop_icon_active} /> <b class='ml-2'>Nhận hàng tại shop</b>
481
+ </div>
482
+ <div class={cls} onClick={(e) => this.onChangeShipping('ship')}>
483
+ <Icon name='package' active={ship_icon_active} /> <b class='ml-2'>Giao hàng cho tôi</b>
484
+ </div>
485
+ </div>
486
+ {$body}
487
+ </div>
488
+ </Fragment>
489
+ )
490
+ }
491
+
492
+ let addr = sb.get(order, 'shipping.address') || {}
493
+ let fulladdr = [addr.address, addr.ward, addr.district, addr.region, addr.country].filter((a) => a).join(', ')
494
+ let $phone = null
495
+ if (addr.phone)
496
+ $phone = (
497
+ <div class='mt-1 muted'>
498
+ {this.props.t('phn')}:&nbsp;{addr.phone}
499
+ </div>
500
+ )
501
+
502
+ if (sb.get(order, 'shipping.pickup_at_shop')) {
503
+ fulladdr = 'Nhận hàng tại cửa hàng'
504
+ }
505
+ // if (!fulladdr) return null
506
+ let $addr = fulladdr ? <div>{fulladdr}</div> : <i class='i muted'>Chưa có địa chỉ giao hàng</i>
507
+
508
+ let seccls = 'card_section'
509
+ if (this.isMobile()) seccls = 'order_section'
510
+ return (
511
+ <div class={seccls}>
512
+ <div class='order_label '>{this.props.t('ship_to')}</div>
513
+ {$addr}
514
+ {$phone}
515
+ </div>
516
+ )
517
+ }
518
+
519
+ renderDesktopSummary(order) {
520
+ let $deposit = null
521
+ if (order.deposit > 0) {
522
+ $deposit = <span class='muted'>(cọc {sb.formatCurrency(order.deposit)})</span>
523
+ }
524
+
525
+ let $discount = null
526
+ if (order.total_discount > 0) {
527
+ $discount = (
528
+ <div class='order_summary_line'>
529
+ <div>Giảm giá</div>
530
+ <div>{sb.formatCurrency(order.total_discount)}</div>
531
+ </div>
532
+ )
533
+ }
534
+
535
+ let $pay = null
536
+
537
+ if ($deposit || order.payment_made) {
538
+ $pay = (
539
+ <Fragment>
540
+ <div class='order_summary_line'>
541
+ <div>Bạn đã trả</div>
542
+ <div>
543
+ {$deposit} {sb.formatCurrency(order.payment_made)}
544
+ </div>
545
+ </div>
546
+ <div class='order_summary_line'>
547
+ <div>Bạn chưa trả</div>
548
+ <div>{sb.formatCurrency((order.total || 0) - (order.payment_made || 0))}</div>
549
+ </div>
550
+ </Fragment>
551
+ )
552
+ }
553
+
554
+ let $tax = (
555
+ <div class='order_summary_line'>
556
+ <div>Tiền thuế</div>
557
+ <div>{sb.formatCurrency(order.total_tax)}</div>
558
+ </div>
559
+ )
560
+
561
+ let $ship = (
562
+ <div class='order_summary_line'>
563
+ <div>Phí vận chuyển</div>
564
+ <div>{sb.get(order, 'shipping.fee', 0)} d</div>
565
+ </div>
566
+ )
567
+
568
+ let editmode = false
569
+ if (!order.status || order.status == 'new') {
570
+ editmode = !order.user_confirmation
571
+ }
572
+ let $note = null
573
+ if (editmode) {
574
+ $ship = null
575
+ $tax = null
576
+ $note = (
577
+ <div class='muted'>
578
+ <img class='order_ship_icon' src={require('../../assets/img/info.svg')} />
579
+ &nbsp; Chưa bao gồm thuế và phí vận chuyển
580
+ </div>
581
+ )
582
+ }
583
+
584
+ let seccls = ''
585
+ if (this.isMobile()) seccls = 'order_section'
586
+
587
+ return (
588
+ <Fragment>
589
+ <div class='order_section__line'></div>
590
+ <div class={seccls}>
591
+ <div class='order_label'>Tóm tắt</div>
592
+ <div class='order_summary_line'>
593
+ <div>Tổng tiền hàng</div>
594
+ <div>{sb.formatCurrency(order.subtotal)}</div>
595
+ </div>
596
+ {$tax}
597
+ {$discount}
598
+ {$ship}
599
+ {$note}
600
+
601
+ <div
602
+ class='order_summary_line'
603
+ style='margin-top: 10px !important; padding-top: 15px !important; border-top: 1px solid #eee !important'>
604
+ <div>Bạn phải trả</div>
605
+ <div class='order__total'>{sb.formatCurrency(order.total)}</div>
606
+ </div>
607
+ {$pay}
608
+ </div>
609
+ </Fragment>
610
+ )
611
+ }
612
+
613
+ renderStatusBadge(order) {
614
+ let status = order.status || 'new'
615
+ return (
616
+ <div style='float: right !important;' class={'order_status order_status__' + status}>
617
+ {status}
618
+ </div>
619
+ )
620
+ }
621
+
622
+ renderShippingInfo(order) {
623
+ if (order.status != 'new' || order.user_confirmation) {
624
+ // read only
625
+ }
626
+
627
+ // let fulladdr = sb.get(order, 'shipping.address.full_address')
628
+ // if (!fulladdr) return null
629
+ let shipping_provider = sb.get(order, 'shipping.shipping_provider')
630
+ if (!shipping_provider) return null
631
+
632
+ let shipping_code = sb.get(order, 'shipping.shipping_code')
633
+ let $tracking_code = null
634
+ if (shipping_code)
635
+ $tracking_code = (
636
+ <div class='muted' style='margin-top: 3px !important'>
637
+ Vận đơn&nbsp;
638
+ <a
639
+ class='order_tracking_link'
640
+ target='_blank'
641
+ href={'https://giaohangtietkiem.vn/tra-cuu-van-don/' + shipping_code}>
642
+ {shipping_code}
643
+ &nbsp;
644
+ <img class='order_tracking_link_icon' src={require('../../assets/img/external-link.svg')} />
645
+ </a>
646
+ </div>
647
+ )
648
+
649
+ if (shipping_provider == 'ghtk') {
650
+ return (
651
+ <div class='order_section'>
652
+ <div class='order_section_label'>Đơn vị vận chuyển</div>
653
+ <div class='d-flex align-items-center'>
654
+ <img class='order_shipping_provider_logo' src={ShippingProvider.ghtk.logo} />
655
+ <div>
656
+ {ShippingProvider.ghtk.name}
657
+ {$tracking_code}
658
+ </div>
659
+ </div>
660
+ </div>
661
+ )
662
+ }
663
+ return null
664
+ }
665
+
666
+ renderDesktopShippingInfo(order) {
667
+ // let fulladdr = sb.get(order, 'shipping.address.full_address')
668
+ // if (!fulladdr) return null
669
+ let shipping_provider = sb.get(order, 'shipping.shipping_provider')
670
+ if (!shipping_provider) return null
671
+
672
+ let shipping_code = sb.get(order, 'shipping.shipping_code')
673
+ let $tracking_code = null
674
+ if (shipping_code)
675
+ $tracking_code = (
676
+ <div class='muted' style='margin-top: 3px !important'>
677
+ Vận đơn&nbsp;
678
+ <a
679
+ class='order_tracking_link'
680
+ target='_blank'
681
+ href={'https://giaohangtietkiem.vn/tra-cuu-van-don/' + shipping_code}>
682
+ {shipping_code}
683
+ &nbsp;
684
+ <img class='order_tracking_link_icon' src={require('../../assets/img/external-link.svg')} />
685
+ </a>
686
+ </div>
687
+ )
688
+
689
+ if (shipping_provider == 'ghtk') {
690
+ return (
691
+ <Fragment>
692
+ <div class='order_label'>Đơn vị vận chuyển</div>
693
+ <div class='d-flex align-items-center'>
694
+ <img class='order_shipping_provider_logo' src={ShippingProvider.ghtk.logo} />
695
+ <div>
696
+ {ShippingProvider.ghtk.name}
697
+ {$tracking_code}
698
+ </div>
699
+ </div>
700
+ </Fragment>
701
+ )
702
+ }
703
+ return null
704
+ }
705
+
706
+ renderProducts(order) {
707
+ let $products = null
708
+ $products = sb.map(order.items, (item) => {
709
+ if (!item || !item.product) return null
710
+ let product = item.product
711
+ return (
712
+ <div class='order_attachment__product'>
713
+ <img
714
+ class='order_attachment__product_img'
715
+ alt={'' + product.id}
716
+ src={sb.get(product, 'images.0') || require('../../assets/img/default.jpg')}
717
+ />
718
+
719
+ <div style='overflow: hidden !important;'>
720
+ <div class='order_attachment__product_name'>{product.name}</div>
721
+ <div class='order_attachment__product_desc'>{product.description || product.long_description}</div>
722
+ <div class='order_attachment__product_desc'>
723
+ {this.props.t('qty')} {item.quantity}&nbsp;·&nbsp;{sb.formatCurrency(product.price)}
724
+ </div>
725
+ </div>
726
+ </div>
727
+ )
728
+ })
729
+
730
+ if (!this.isMobile())
731
+ return (
732
+ <div>
733
+ <div class='order_label'>{this.props.t('product')}</div>
734
+ {$products}
735
+ </div>
736
+ )
737
+
738
+ return (
739
+ <div class='order_section'>
740
+ <div class='order_section_label'>{this.props.t('product')}</div>
741
+ {$products}
742
+ </div>
743
+ )
744
+ }
745
+
746
+ onChangeQuantity = (item, text) => {
747
+ let qty = parseInt(text) || 1
748
+ item.quantity = qty
749
+ this.forceUpdate()
750
+ }
751
+
752
+ renderDesktopProducts(order) {
753
+ let $products = null
754
+ let editmode = false
755
+ if (!order.status || order.status == 'new') {
756
+ editmode = !order.user_confirmation
757
+ }
758
+
759
+ if (editmode) {
760
+ $products = sb.map(order.items, (item) => {
761
+ if (!item || !item.product) return null
762
+ let product = item.product
763
+ return (
764
+ <div class='order_attachment__product'>
765
+ <img
766
+ class='order_attachment__product_img'
767
+ alt={'' + product.id}
768
+ src={sb.get(product, 'images.0') || require('../../assets/img/default.jpg')}
769
+ />
770
+
771
+ <div style='overflow: hidden !important; flex: 1 !important'>
772
+ <div class='order_attachment__product_name'>{product.name}</div>
773
+ <div class='order_attachment__product_desc'>{product.description || product.long_description}</div>
774
+ <div class='order_attachment__product_desc'>{sb.formatCurrency(product.price)}</div>
775
+ </div>
776
+ <input
777
+ class='form-control'
778
+ style='text-align: center !important; font-weight: 400 !important; width: 50px !important'
779
+ value={item.quantity}
780
+ onInput={(e) => this.onChangeQuantity(item, e.target.value)}
781
+ type='text'
782
+ />
783
+ <div style='width: 80px !important; text-align: right !important; '>
784
+ <b>{sb.formatCurrency(item.quantity * product.price)}</b>
785
+ </div>
786
+ </div>
787
+ )
788
+ })
789
+ } else {
790
+ $products = sb.map(order.items, (item) => {
791
+ if (!item || !item.product) return null
792
+ let product = item.product
793
+ return (
794
+ <div class='order_attachment__product'>
795
+ <img
796
+ class='order_attachment__product_img'
797
+ alt={'' + product.id}
798
+ src={sb.get(product, 'images.0') || require('../../assets/img/default.jpg')}
799
+ />
800
+
801
+ <div style='overflow: hidden !important; flex: 1 !important'>
802
+ <div class='order_attachment__product_name'>{product.name}</div>
803
+ <div class='order_attachment__product_desc'>{product.description || product.long_description}</div>
804
+ <div class='order_attachment__product_desc'>{sb.formatCurrency(product.price)}</div>
805
+ </div>
806
+ <div style='text-align: center !important; font-weight: 400 !important; width: 50px !important'>
807
+ {item.quantity}
808
+ </div>
809
+ <div style='width: 80px !important; text-align: right !important; '>
810
+ <b>{sb.formatCurrency(item.total)}</b>
811
+ </div>
812
+ </div>
813
+ )
814
+ })
815
+ }
816
+
817
+ return (
818
+ <div class='card_section'>
819
+ <div class='desktop_order__heading'>
820
+ {this.renderStatusBadge(order)}
821
+ <b style='font-size: 18px !important;'>
822
+ {this.props.t('order')} #{order.order_number || order.id}
823
+ </b>
824
+ <div class='muted'>
825
+ <Time style='font-size: 13px !important;' time={order.issue_date || order.created} />
826
+ </div>
827
+ </div>
828
+
829
+ <div
830
+ class='order_label d-flex'
831
+ style='margin-top: 20px !important;justify-content: space-between !important; align-items: flex-end !important;'>
832
+ <div style='flex: 1 !important;'>{this.props.t('product')}</div>
833
+ <div style='font-weight: 400 !important; text-align:center !important; width: 50px !important'>
834
+ {this.props.t('qty')}
835
+ </div>
836
+ <div style='font-weight: 400 !important; text-align: right !important; width: 80px !important;'>
837
+ {this.props.t('total')}
838
+ </div>
839
+ </div>
840
+ {$products}
841
+ </div>
842
+ )
843
+ }
844
+
845
+ renderMobile(order) {
846
+ if (this.state.step === 'success') return this.renderMobileSuccess(order)
847
+ let $error = null
848
+ if (this.state.g_err) {
849
+ $error = (
850
+ <div class='mb-2 text__danger'>
851
+ <img style='margin-top: -4px !important; height: 15px !important;' src={ximg} />
852
+ &nbsp;<b>{this.state.g_err}</b>
853
+ </div>
854
+ )
855
+ }
856
+ let $status = (
857
+ <div>
858
+ {$error}
859
+ <div class='btn-confirm-order' style='margin-top: 0 !important;' onClick={this.confirm}>
860
+ {this.props.t('confirm_order')}
861
+ </div>
862
+ </div>
863
+ )
864
+
865
+ let $close = (
866
+ <div class='order_btn order__btn__light mt-3' onClick={this.onCancel}>
867
+ {this.props.t('cancel_order')}
868
+ </div>
869
+ )
870
+
871
+
872
+
873
+
874
+ if (order.user_confirmation || order.status != 'new') {
875
+ $status = null
876
+ if (this.props.cid)
877
+ $close = (
878
+ <div class='order_btn order__btn__light mt-3' onClick={this.close}>
879
+ {this.props.t('close')}
880
+ </div>
881
+ )
882
+ }
883
+
884
+
885
+
886
+ return (
887
+ <div class='order' style='height: 100% !important'>
888
+ <div class='order--content'>
889
+ <div class='order--heading'>
890
+ {this.renderStatusBadge(order)}
891
+ <b style='font-size: 16px !important;'>
892
+ {this.props.t('order')} #{order.order_number || order.id}
893
+ </b>
894
+ <div class='muted'>
895
+ <Time style='font-size: 13px !important;' time={order.issue_date || order.created} />
896
+ </div>
897
+ </div>
898
+ {this.renderProducts(order)}
899
+ {this.renderDesktopShipping(order)}
900
+ {this.renderShippingInfo(order)}
901
+ {this.renderDesktopPaymentMethod(order)}
902
+ {this.renderDesktopSummary(order)}
903
+ <div class='order_section pb-3' style='padding-top: 0 !important;'>
904
+ {$status}
905
+ {$close}
906
+ </div>
907
+ </div>
908
+ </div>
909
+ )
910
+ }
911
+
912
+ renderActions(order) {
913
+ let $actions = null
914
+ let editmode = false
915
+ if (!order.status || order.status == 'new') {
916
+ editmode = !order.user_confirmation
917
+ }
918
+
919
+ if (this.state.step === 'success')
920
+ return (
921
+ <div class='d-flex' style='align-items: center !important; justify-content: flex-end !important'>
922
+ <div>Ghi nhận thành công</div>&nbsp;
923
+ <img style='width: 16px !important; height: 16px !important;' width='16' height='16' src={checkedimg} />
924
+ </div>
925
+ )
926
+
927
+ if (editmode) {
928
+ let $error = null
929
+ if (this.state.g_err) {
930
+ $error = (
931
+ <div class='mb-2 text__danger'>
932
+ <img style='margin-top: -4px !important; height: 15px !important;' src={ximg} />
933
+ &nbsp;<b>{this.state.g_err}</b>
934
+ </div>
935
+ )
936
+ }
937
+
938
+ $actions = (
939
+ <div>
940
+ {$error}
941
+ <div class='btn-confirm-order' onClick={this.confirm}>
942
+ {this.props.t('confirm_order')}
943
+ </div>
944
+ <div class='btn-cancel-order' onClick={this.onCancel}>
945
+ {this.props.t('cancel_order')}
946
+ </div>
947
+ </div>
948
+ )
949
+ }
950
+ return $actions
951
+ }
952
+
953
+ renderDesktop(order) {
954
+ let acc = this.props.store.matchAccount()
955
+ var uri = acc.logo_url || require('../../assets/img/image_default.png')
956
+
957
+ return (
958
+ <div class='desktop order'>
959
+ <div class='order_acc_header'>
960
+ <img class='order_acc_logo' src={uri} />
961
+ <div class='order_acc_name'>{acc.name}</div>
962
+ </div>
963
+ <div class='desktop_order__content'>
964
+ <div style='flex: 1 !important; padding-right: 20px !important;'>
965
+ {this.renderDesktopProducts(order)}
966
+ {this.renderDesktopShipping(order)}
967
+ {this.renderDesktopShippingInfo(order)}
968
+ {this.renderDesktopPaymentMethod(order)}
969
+
970
+ <div class='order__footer'>
971
+ <a target='_blank' href='https://subiz.com.vn' class='order__footer_link'>
972
+ Cung cấp bởi <b>Subiz</b>
973
+ </a>
974
+ <div class='order__footer_delimiter'></div>
975
+ <a target='_blank' href='https://subiz.com.vn/vi/terms-of-service.html' class='order__footer_link'>
976
+ Điều khoản
977
+ </a>
978
+ <a target='_blank' href='https://subiz.com.vn/vi/privacy-policy.html' class='order__footer_link'>
979
+ Quyền riêng tư
980
+ </a>
981
+ </div>
982
+ </div>
983
+ <div>
984
+ <div class='order_recap'>
985
+ {this.renderDesktopSummary(order)}
986
+ {this.renderActions(order)}
987
+ </div>
988
+ </div>
989
+ </div>
990
+ </div>
991
+ )
992
+ }
993
+
994
+ render() {
995
+ if (this.state.loading)
996
+ return (
997
+ <div class='order_error'>
998
+ <Spinner class='mt-4' size='60' static />
999
+ </div>
1000
+ )
1001
+ if (this.state.error)
1002
+ return (
1003
+ <div class='order_error'>
1004
+ <img class='mt-3' src={require('../../assets/img/empty_1.svg')} />
1005
+ <div class='mt-3'>{this.props.t('order_load_error')}</div>
1006
+ </div>
1007
+ )
1008
+ let order = this.state.order
1009
+ if (this.isMobile()) return this.renderMobile(order)
1010
+ return this.renderDesktop(order)
1011
+ }
1012
+
1013
+ confirm = async () => {
1014
+ this.setState({g_err: ''})
1015
+ // validate
1016
+ let err = {}
1017
+ if (!this.state.shipping) {
1018
+ this.setState({g_err: 'Mời bạn chọn địa chỉ giao hàng trước khi xác nhận'})
1019
+ }
1020
+ if (this.state.shipping === 'shop') {
1021
+ if (!sb.isPhone(this.state.phone)) {
1022
+ err.phone = true
1023
+ }
1024
+
1025
+ if (!sb.trim(this.state.fullname)) {
1026
+ err.name = true
1027
+ }
1028
+ if (!sb.trim(this.state.email)) {
1029
+ err.email = true
1030
+ }
1031
+ } else if (this.state.shipping_address == 'new') {
1032
+ if (!sb.isPhone(this.state.phone)) {
1033
+ err.phone = true
1034
+ }
1035
+
1036
+ if (!sb.trim(this.state.fullname)) {
1037
+ err.name = true
1038
+ }
1039
+ if (!sb.trim(this.state.address)) {
1040
+ err.address = true
1041
+ }
1042
+
1043
+ if (sb.size(this.state.selectedWard) == 0) {
1044
+ err.ward = true
1045
+ }
1046
+
1047
+ if (sb.size(this.state.selectedDistrict) == 0) {
1048
+ err.district = true
1049
+ }
1050
+
1051
+ if (sb.size(this.state.selectedProvince) == 0) {
1052
+ err.province = true
1053
+ }
1054
+ }
1055
+
1056
+ if (sb.size(err) > 0) {
1057
+ this.setState({err, g_err: this.props.t('input_shipping_info_err')})
1058
+ return
1059
+ }
1060
+
1061
+ // save
1062
+ let user = this.props.store.matchUser()
1063
+ let ufullname = sb.getUserAttr(user, 'fullname', 'text')
1064
+ let uemail = sb.getUserAttr(user, 'emails', 'text')
1065
+ let uphone = sb.getUserAttr(user, 'phones', 'text')
1066
+
1067
+ let order = sb.cloneDeep(this.state.order)
1068
+ if (this.state.shipping === 'shop') {
1069
+ sb.set(order, 'shipping.pickup_at_shop', true)
1070
+ sb.set(order, 'shipping.address.phone', this.state.phone)
1071
+ sb.set(order, 'shipping.address.fullname', this.state.fullname)
1072
+ sb.set(order, 'shipping.address.email', this.state.email)
1073
+ } else {
1074
+ if (this.state.shipping_address == 'new') {
1075
+ let out = await this.props.store.createShippingAddress({
1076
+ address: this.state.address,
1077
+ country: 'Việt Nam',
1078
+ fullname: this.state.fullname,
1079
+ email: this.state.email,
1080
+ phone: this.state.phone,
1081
+ district: this.state.selectedDistrict.name,
1082
+ district_id: this.state.selectedDistrict.id,
1083
+ province: this.state.selectedProvince.name,
1084
+ province_id: this.state.selectedProvince.id,
1085
+ ward: this.state.selectedWard.name,
1086
+ street: this.state.street,
1087
+ ward_id: this.state.selectedWard.id,
1088
+ })
1089
+
1090
+ if (out.error) return this.setState({g_err: this.props.t('update_failed')})
1091
+ sb.set(order, 'shipping.address', out.body)
1092
+ } else {
1093
+ let addresses = this.props.store.matchShippingAddresses()
1094
+ let sa = sb.find(addresses, (addr) => addr.id === this.state.shipping_address)
1095
+ if (!sa) {
1096
+ return this.setState({err, g_err: this.props.t('input_shipping_info_err')})
1097
+ }
1098
+ sb.set(order, 'shipping.address', sa)
1099
+ }
1100
+ }
1101
+
1102
+ let changeduser = false
1103
+ if (!ufullname && this.state.fullname) {
1104
+ changeduser = true
1105
+ sb.setUserAttr(user, {key: 'fullname', text: this.state.fullname})
1106
+ }
1107
+
1108
+ if (!uemail && this.state.email) {
1109
+ changeduser = true
1110
+ sb.setUserAttr(user, {key: 'emails', text: this.state.email})
1111
+ }
1112
+
1113
+ if (!uphone && this.state.phone) {
1114
+ changeduser = true
1115
+ sb.setUserAttr(user, {key: 'phones', text: this.state.phone})
1116
+ }
1117
+
1118
+ // quick update user
1119
+ if (changeduser) this.props.store.setUser(user)
1120
+
1121
+ this.setState({sending: true})
1122
+ order.user_confirmation = 'confirmed'
1123
+ let out = await this.props.store.updateOrder(order)
1124
+ this.setState({sending: false})
1125
+ if (out.error) {
1126
+ return this.setState({g_err: this.props.t('update_failed')})
1127
+ }
1128
+
1129
+ this.setState({step: 'success'})
1130
+ if (this.props.onResponse) this.props.onResponse('confirmed')
1131
+ }
1132
+
1133
+ onCancel = () => {
1134
+ if (this.props.onResponse) this.props.onResponse('rejected')
1135
+ this.close()
1136
+ }
1137
+
1138
+ close = () => {
1139
+ if (this.props.cid && !this.state.order.user_confirmation) {
1140
+ let order = sb.cloneDeep(this.state.order)
1141
+ order.user_confirmation = 'rejected'
1142
+ this.props.store.updateOrder(order)
1143
+ }
1144
+ if (this.props.onClose) this.props.onClose()
1145
+ }
1146
+ }
1147
+
1148
+ let ShippingProvider = {
1149
+ ghtk: {
1150
+ name: 'Giao hàng tiết kiệm',
1151
+ logo: require('../../assets/img/ghtk.svg'),
1152
+ },
1153
+ ghn: {
1154
+ name: 'Giao hàng nhanh',
1155
+ logo: require('../../assets/img/ghn.svg'),
1156
+ },
1157
+ }