@lancom/shared 0.0.369 → 0.0.371

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.
@@ -350,6 +350,27 @@ export default {
350
350
  removeSubscribe(id) {
351
351
  return _delete(`admin/subscribe/${id}`);
352
352
  },
353
+ fetchContacts() {
354
+ return _get('admin/contact');
355
+ },
356
+ fetchContactById(id) {
357
+ return _get(`admin/contact/${id}`);
358
+ },
359
+ saveContact(contact) {
360
+ return contact._id ? _put(`admin/contact/${contact._id}`, contact) : _post('admin/contact', contact);
361
+ },
362
+ removeContact(id) {
363
+ return _delete(`admin/contact/${id}`);
364
+ },
365
+ fetchLeadById(id) {
366
+ return _get(`admin/lead/${id}`);
367
+ },
368
+ saveLead(lead) {
369
+ return lead._id ? _put(`admin/lead/${lead._id}`, lead) : _post('admin/lead', lead);
370
+ },
371
+ removeLead(id) {
372
+ return _delete(`admin/lead/${id}`);
373
+ },
353
374
  fetchCoupons() {
354
375
  return _get('admin/coupons');
355
376
  },
@@ -27,6 +27,8 @@ export function convertQuoteToOrder(quote, option) {
27
27
  suppliersWithRates: option.suppliersWithRates,
28
28
  adminShippingTotal: option.adminShippingTotal,
29
29
  quote: quote._id,
30
+ contact: quote.contact,
31
+ googleClickId: quote.googleClickId,
30
32
  resources: files.map(f => ({
31
33
  status: 'pending approval',
32
34
  prints: [],
@@ -193,7 +193,7 @@ export default {
193
193
  };
194
194
  },
195
195
  computed: {
196
- ...mapGetters(['contacts', 'shop']),
196
+ ...mapGetters(['contacts', 'shop', 'googleClickId']),
197
197
  phoneRules() {
198
198
  return this.requiredPhone ? 'required|phone' : 'phone';
199
199
  }
@@ -208,6 +208,7 @@ export default {
208
208
  const recaptchaToken = await this.getRecaptcha('contact_us');
209
209
  const body = {
210
210
  recaptchaToken,
211
+ googleClickId: this.googleClickId,
211
212
  ...this.form
212
213
  };
213
214
  const response = await api.contactUs(body, this.shop._id);
@@ -155,7 +155,7 @@ export default {
155
155
  };
156
156
  },
157
157
  computed: {
158
- ...mapGetters(['contacts', 'shop']),
158
+ ...mapGetters(['contacts', 'shop', 'googleClickId']),
159
159
  ...mapGetters('layers', [
160
160
  'layerThumbnails'
161
161
  ]),
@@ -190,6 +190,7 @@ export default {
190
190
  address: this.form,
191
191
  ...this.form,
192
192
  options: [{ products, index: 0 }],
193
+ googleClickId: this.googleClickId,
193
194
  shop: this.shop._id
194
195
  };
195
196
  await api.saveQuoteRequest(body, this.shop._id);
@@ -125,7 +125,7 @@ export default {
125
125
  },
126
126
  computed: {
127
127
  ...mapGetters(['MESSAGES']),
128
- ...mapGetters(['country', 'currency', 'app']),
128
+ ...mapGetters(['country', 'currency', 'app', 'googleClickId']),
129
129
  ...mapGetters(['orderSettings']),
130
130
  ...mapGetters('order', ['card']),
131
131
  ...mapGetters('cart', ['entities', 'notEmptySimpleProducts', 'cartPricing'])
@@ -163,6 +163,7 @@ export default {
163
163
  paymentStatus: paymentStatus || 'abandoned',
164
164
  recaptchaToken,
165
165
  products: this.entities,
166
+ googleClickId: this.googleClickId,
166
167
  pricing: this.cartPricing,
167
168
  shop: this.shop._id,
168
169
  currency: this.currency?._id,
@@ -74,7 +74,7 @@ export default {
74
74
  };
75
75
  },
76
76
  computed: {
77
- ...mapGetters(['country','currency']),
77
+ ...mapGetters(['shop', 'country','currency', 'googleClickId']),
78
78
  ...mapGetters('cart', ['entities', 'notEmptySimpleProducts', 'cartPricing']),
79
79
  isPaymentOrder() {
80
80
  return this.order.paymentMethod === ORDER_PAYMENT_METHOD.CARD;
@@ -99,6 +99,7 @@ export default {
99
99
  products: this.entities,
100
100
  pricing: this.cartPricing,
101
101
  shop: this.shop._id,
102
+ googleClickId: this.googleClickId,
102
103
  currency: this.currency?._id,
103
104
  country: this.country?._id
104
105
  });
@@ -292,7 +292,7 @@ export default {
292
292
  };
293
293
  },
294
294
  computed: {
295
- ...mapGetters(['shop', 'country', 'currency']),
295
+ ...mapGetters(['shop', 'country', 'currency', 'googleClickId']),
296
296
  ...mapGetters('order', ['orderData']),
297
297
  ...mapGetters('cart', [
298
298
  'entities',
@@ -360,6 +360,7 @@ export default {
360
360
  await this.createOrder({
361
361
  recaptchaToken,
362
362
  currency: this.currency?._id,
363
+ googleClickId: this.googleClickId,
363
364
  country: this.country?._id,
364
365
  billingAddress: JSON.parse(JSON.stringify(this.form)),
365
366
  shippingAddress: this.form,
@@ -77,7 +77,7 @@ export default {
77
77
  };
78
78
  },
79
79
  computed: {
80
- ...mapGetters(['shop', 'country', 'currency', 'payment']),
80
+ ...mapGetters(['shop', 'country', 'currency', 'payment', 'googleClickId']),
81
81
  model() {
82
82
  return this.invoice || this.order;
83
83
  }
@@ -107,6 +107,7 @@ export default {
107
107
  shop: this.shop._id,
108
108
  country: this.country?._id,
109
109
  payment: this.payment,
110
+ googleClickId: this.googleClickId,
110
111
  currency: this.currency?.isoCode,
111
112
  recaptchaToken,
112
113
  path: window.location.pathname
@@ -280,7 +280,7 @@ export default {
280
280
  };
281
281
  },
282
282
  computed: {
283
- ...mapGetters(['shop'])
283
+ ...mapGetters(['shop', 'googleClickId'])
284
284
  },
285
285
  methods: {
286
286
  handleUploaded(file) {
@@ -302,7 +302,8 @@ export default {
302
302
  recaptchaToken,
303
303
  ...this.form,
304
304
  product: this.product._id,
305
- targetShop: this.shop._id
305
+ targetShop: this.shop._id,
306
+ googleClickId: this.googleClickId
306
307
  };
307
308
  const review = await api.addReview(body, this.shop._id);
308
309
  this.$toastr.s('Your review will be processed within 24-48 hours. Thank You.');
@@ -391,7 +391,7 @@ export default {
391
391
  }
392
392
  },
393
393
  computed: {
394
- ...mapGetters(['shop', 'currency']),
394
+ ...mapGetters(['shop', 'currency', 'googleClickId']),
395
395
  ...mapGetters('cart', ['entities']),
396
396
  },
397
397
  methods: {
@@ -429,6 +429,7 @@ export default {
429
429
  ...this.quote,
430
430
  quoteTypes: Object.keys(this.selectedQuoteTypes),
431
431
  shop: this.shop._id,
432
+ googleClickId: this.googleClickId,
432
433
  referer: window.location.href,
433
434
  cartInfo: {
434
435
  entities: (this.entities || [])
@@ -1,6 +1,5 @@
1
1
  import { mapGetters, mapActions, mapMutations } from 'vuex';
2
2
  import api from '@lancom/shared/assets/js/api';
3
- import gtm from '@lancom/shared/assets/js/utils/gtm';
4
3
  import gapis from '@lancom/shared/assets/js/utils/gapis';
5
4
  import { price, shortDate, tax } from '@lancom/shared/assets/js/utils/filters';
6
5
  import { convertQuoteToOrder } from '@lancom/shared/assets/js/utils/quote';
@@ -30,7 +29,7 @@ export default {
30
29
  computed: {
31
30
  ...mapGetters(['MESSAGES']),
32
31
  ...mapGetters('quote', ['quote', 'option', 'proceedOption', 'selectedOption', 'depositInfo', 'shopContacts', 'quoteAddress', 'quoteId', 'options', 'gstTax']),
33
- ...mapGetters(['shop', 'country', 'currency'])
32
+ ...mapGetters(['shop', 'country', 'currency', 'googleClickId'])
34
33
  },
35
34
  methods: {
36
35
  ...mapActions('quote', ['selectOption', 'clear']),
@@ -43,7 +42,7 @@ export default {
43
42
  this.processing = true;
44
43
  this.order = await this.createOrder({ ...option });
45
44
  this.setOrder(this.order);
46
- gtm.purchase(this.order, this.currency);
45
+ // gtm.purchase(this.order, this.currency);
47
46
  gapis.surveyOptin(this.order, this.shop);
48
47
  this.clear();
49
48
  } catch (e) {
@@ -57,6 +56,7 @@ export default {
57
56
  const recaptchaToken = await this.getRecaptcha('create_order');
58
57
  const orderData = {
59
58
  shop: this.shop._id,
59
+ googleClickId: this.googleClickId,
60
60
  country: this.country?._id,
61
61
  currency: this.currency?._id,
62
62
  ...convertQuoteToOrder(this.quote, option),
@@ -103,7 +103,7 @@ export default {
103
103
  };
104
104
  },
105
105
  computed: {
106
- ...mapGetters(['shop'])
106
+ ...mapGetters(['shop', 'googleClickId'])
107
107
  },
108
108
  // mounted() {
109
109
  // this.preloadReCaptcha();
@@ -121,6 +121,7 @@ export default {
121
121
  const body = {
122
122
  recaptchaToken,
123
123
  shop: this.shop._id,
124
+ googleClickId: this.googleClickId,
124
125
  ...this.subscriber
125
126
  };
126
127
  await api.subscribe(body, this.shop._id);
package/layouts/error.vue CHANGED
@@ -7,7 +7,7 @@
7
7
  </template>
8
8
 
9
9
  <script>
10
- import { mapGetters } from 'vuex';
10
+ import { mapGetters, mapActions } from 'vuex';
11
11
  import Error404 from '@lancom/shared/components/errors/404.vue';
12
12
  import Error500 from '@lancom/shared/components/errors/500.vue';
13
13
  import { generateShopHeadScripts } from '@lancom/shared/utils/head';
@@ -34,6 +34,14 @@ export default {
34
34
  }
35
35
  return Error500;
36
36
  }
37
+ },
38
+ mounted() {
39
+ this.loadState(this.$route.query);
40
+ },
41
+ methods: {
42
+ ...mapActions([
43
+ 'loadState'
44
+ ]),
37
45
  }
38
46
  };
39
47
  </script>
@@ -214,7 +214,7 @@
214
214
  }
215
215
  },
216
216
  mounted() {
217
- this.loadState();
217
+ this.loadState(this.$route.query);
218
218
  this.logGtm();
219
219
  // setTimeout(() => this.loadProducts(), 3000);
220
220
  },
@@ -9,7 +9,7 @@ export default {
9
9
  };
10
10
  },
11
11
  computed: {
12
- ...mapGetters(['shop', 'country', 'currency']),
12
+ ...mapGetters(['shop', 'country', 'currency', 'googleClickId']),
13
13
  ...mapGetters('product', [
14
14
  'product',
15
15
  'usedSimpleProducts',
@@ -61,7 +61,8 @@ export default {
61
61
  shop: this.shop,
62
62
  pricing: this.productPricing,
63
63
  country: this.country,
64
- currency: this.currency
64
+ currency: this.currency,
65
+ googleClickId: this.googleClickId
65
66
  });
66
67
  this.$toastr.s('Products successfully added to cart');
67
68
 
package/nuxt.config.js CHANGED
@@ -68,7 +68,8 @@ module.exports = (config, axios, { raygunClient, publicPath, productUrlToEditor
68
68
  ],
69
69
  serverMiddleware: [
70
70
  '@/node_modules/@lancom/shared/plugins/headers',
71
- '@/node_modules/@lancom/shared/server-middleware/robots'
71
+ '@/node_modules/@lancom/shared/server-middleware/robots',
72
+ '@/node_modules/@lancom/shared/server-middleware/leads'
72
73
  ],
73
74
  modules: [
74
75
  'nuxt-helmet',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lancom/shared",
3
- "version": "0.0.369",
3
+ "version": "0.0.371",
4
4
  "description": "lancom common scripts",
5
5
  "author": "e.tokovenko <e.tokovenko@gmail.com>",
6
6
  "repository": {
@@ -10,6 +10,7 @@
10
10
  "license": "ISC",
11
11
  "homepage": "https://bitbucket.org/simpletee/lancom-shared#readme",
12
12
  "dependencies": {
13
+ "basic-auth": "^2.0.1",
13
14
  "lodash.get": "^4.4.2",
14
15
  "vue2-hammer": "^2.1.2"
15
16
  },
@@ -2,6 +2,7 @@ import debounce from 'lodash.debounce';
2
2
 
3
3
  const STATE_STORAGE_KEY = 'lancom-state-2.1';
4
4
  const SAVE_STATE_MODULES = new Map([
5
+ ['setGoogleClickId', 'googleClickId'],
5
6
  ['cart/setId', 'cart.id'],
6
7
  ['cart/clearCart', 'cart.id'],
7
8
  ['cart/setCoupon', 'cart.coupon'],
@@ -33,7 +34,11 @@ export function saveState(store) {
33
34
  if (!stateToSave[key]) {
34
35
  stateToSave[key] = {};
35
36
  }
36
- stateToSave[key][prop] = store.state[key] && store.state[key][prop];
37
+ if (prop) {
38
+ stateToSave[key][prop] = store.state[key] && store.state[key][prop];
39
+ } else {
40
+ stateToSave[key] = store.state[key];
41
+ }
37
42
  }
38
43
  });
39
44
  localStorage.setItem(STATE_STORAGE_KEY, JSON.stringify(stateToSave));
@@ -0,0 +1,69 @@
1
+ const axios = require('axios');
2
+ const basicAuth = require('basic-auth');
3
+
4
+ const API_URL = process.client ? process.env.API_URL : process.env.LOCAL_API_URL;
5
+ const HOST_NAME = process.env.HOST_NAME;
6
+
7
+ const LEAD_ADMIN = 'ladmin';
8
+ const LEAD_ADMIN_PASS = 'ladmin2sad$S';
9
+
10
+ module.exports = async function (req, res, next) {
11
+ if (req.url === '/lead/leads.csv') {
12
+ const credentials = basicAuth(req);
13
+
14
+ if (!credentials || credentials.name !== LEAD_ADMIN || credentials.pass !== LEAD_ADMIN_PASS) {
15
+ res.setHeader('WWW-Authenticate', 'Basic realm="Access restricted"');
16
+ res.statusCode = 401;
17
+ return res.end('Authentication required.');
18
+ }
19
+
20
+ const leads = (await axios.get(`${API_URL}/shop/${HOST_NAME}/leads`)).data;
21
+ console.log('leads: ', leads);
22
+
23
+ const csvHeaders = [
24
+ 'conversion_action',
25
+ 'conversion_event_time',
26
+ 'gclid',
27
+ 'hashed_email',
28
+ 'hashed_phone_number',
29
+ 'conversion_value',
30
+ 'currency_code',
31
+ 'transaction_id'
32
+ ];
33
+
34
+ const csvRows = leads
35
+ .reduce((rows, lead) => {
36
+ if (lead.order) {
37
+ rows.push({ ...lead, type: 'converted_lead', code: lead.order.code });
38
+ }
39
+ if (lead.quote) {
40
+ rows.push({ ...lead, type: 'qualified_lead', code: lead.quote.code });
41
+ }
42
+ if ((lead.quote || lead.order) && lead.contact) {
43
+ rows.push({ ...lead, type: 'contact_form', code: lead.contact.code });
44
+ }
45
+ return rows;
46
+ }, [])
47
+ .map(lead => [
48
+ lead.type,
49
+ (new Date(lead.createdAt)).getTime(),
50
+ lead.googleClickId,
51
+ lead.hashedEmail,
52
+ lead.hashedPhoneNumber,
53
+ lead.conversionValue,
54
+ lead.conversion?.isoCode || 'AUD',
55
+ lead.code
56
+ ]);
57
+
58
+ const csvContent = [
59
+ csvHeaders.join(','),
60
+ ...csvRows.map(row => row.join(','))
61
+ ].join('\n');
62
+
63
+ res.setHeader('Content-Type', 'text/csv');
64
+ res.end(csvContent);
65
+ return;
66
+ }
67
+
68
+ next();
69
+ }
package/store/cart.js CHANGED
@@ -90,7 +90,7 @@ export const getters = {
90
90
  };
91
91
 
92
92
  export const actions = {
93
- async addToCart({ state, commit }, { entities, shop, pricing, country, currency }) {
93
+ async addToCart({ state, commit }, { entities, shop, pricing, country, currency, googleClickId }) {
94
94
  const addingEntities = [...entities];
95
95
  const isSamePrints = (e, e2) => {
96
96
  const samePrints = (e.prints || []).filter(p => (e2.prints || []).some(p2 => p2.guid === p.guid));
@@ -119,6 +119,7 @@ export const actions = {
119
119
  const payload = {
120
120
  _id: state.id || undefined,
121
121
  currency: currency?._id,
122
+ googleClickId,
122
123
  entities: [...cartEntities, ...entities]
123
124
  };
124
125
  const cart = await api.saveCart(payload, shop._id);
package/store/index.js CHANGED
@@ -7,6 +7,7 @@ const CLOSED_NOTIFICATION = 'lancom-closed-notification-1.0';
7
7
  import { getShopCountrySettings } from '@lancom/shared/assets/js/utils/shop';
8
8
 
9
9
  export const state = () => ({
10
+ googleClickId: null,
10
11
  stockCountry: null,
11
12
  country: null,
12
13
  currency: null,
@@ -31,6 +32,7 @@ export const getters = {
31
32
  currency: ({ currency }) => currency,
32
33
  currencies: ({ shop }) => (shop.countries || []).reduce((currencies, { country }) => [...currencies, country?.currency], []).filter(c => !!c),
33
34
  shop: ({ shop }) => shop || {},
35
+ googleClickId: ({ googleClickId }) => googleClickId,
34
36
  payment: ({ payment }) => payment || {},
35
37
  menus: ({ menus }) => menus || [],
36
38
  topMenu: ({ menus }) => (menus || []).find(({ type }) => type === 'top'),
@@ -97,7 +99,7 @@ export const actions = {
97
99
  }
98
100
  } catch (e) {}
99
101
  },
100
- async loadState({ dispatch, commit, state: { shop, currency, country, notificationBar } }) {
102
+ async loadState({ dispatch, commit, state: { shop, currency, country, notificationBar } }, query) {
101
103
  const state = await loadState();
102
104
  if (state) {
103
105
  commit('setState', state);
@@ -118,6 +120,9 @@ export const actions = {
118
120
  dispatch('cart/calculateCartPrice', { shop, country });
119
121
  }
120
122
  }
123
+ if (query.gclid || state?.googleClickId) {
124
+ commit('setGoogleClickId', query.gclid || state?.googleClickId);
125
+ }
121
126
  const closedNotification = localStorage.getItem(CLOSED_NOTIFICATION);
122
127
  if (notificationBar?.text === closedNotification) {
123
128
  commit('setNotificationBar', { ...notificationBar, enabled: false });
@@ -149,6 +154,9 @@ export const mutations = {
149
154
  setCurrency(state, currency) {
150
155
  state.currency = currency;
151
156
  },
157
+ setGoogleClickId(state, googleClickId) {
158
+ state.googleClickId = googleClickId;
159
+ },
152
160
  setSettings(state, { contacts, notificationBar, discountPopup, order, depositInfo, pricing, app }) {
153
161
  state.app = app;
154
162
  state.contacts = contacts;
package/store/order.js CHANGED
@@ -18,14 +18,14 @@ export const actions = {
18
18
  commit('setOrderData', response);
19
19
  },
20
20
  async createOrder({ commit }, data) {
21
- const { shop, products, pricing, recaptchaToken } = data;
21
+ const { shop, products, pricing, recaptchaToken, googleClickId } = data;
22
22
  const order = generateOrderData(data, products, pricing);
23
- const response = await api.createOrder({ ...order, recaptchaToken }, shop);
23
+ const response = await api.createOrder({ ...order, recaptchaToken, googleClickId }, shop);
24
24
  commit('setOrderData', response);
25
25
  },
26
- async submitPayment({ commit, state: { orderData } }, { card, payment, country, shop, currency, recaptchaToken }) {
26
+ async submitPayment({ commit, state: { orderData } }, { card, payment, country, shop, currency, recaptchaToken, googleClickId }) {
27
27
  const { _id } = orderData || {};
28
- const response = await api.createOrderPayment(_id, { card, shop, country, payment, currency, recaptchaToken });
28
+ const response = await api.createOrderPayment(_id, { card, shop, country, payment, currency, recaptchaToken, googleClickId });
29
29
  if (response.redirect_url) {
30
30
  window.location.href = response.redirect_url;
31
31
  return;