flowrix 1.0.1-beta.128 → 1.0.1-beta.129

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.
package/dist/module.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "flowrix",
3
3
  "configKey": "flowrix",
4
- "version": "1.0.1-beta.128",
4
+ "version": "1.0.1-beta.129",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "1.0.2",
7
7
  "unbuild": "3.6.1"
@@ -1,17 +1,41 @@
1
- export default function (props: any): {
2
- useCartStore: import("pinia").StoreDefinition<"cart", import("../../stores/Cart.js").CartState, {}, {}>;
3
- ServiceStore: import("pinia").Store<"ServiceStore", {
4
- services: never[];
5
- availability: boolean;
6
- }, {}, {
7
- getAllServices(): Promise<void>;
8
- checkAvailability(data: any): Promise<any>;
9
- }>;
10
- CurrentService: import("vue").Ref<never[], never[]>;
11
- findItemBySlug: (slug: string) => any;
1
+ interface ServiceAvailabilityPayload {
2
+ shipping_country: number;
3
+ shipping_state: number;
4
+ shipping_postcode: string | number;
5
+ }
6
+ export declare function useService(): {
7
+ currentService: import("vue").Ref<never[], never[]>;
12
8
  servicesAvailability: import("vue").Ref<boolean, boolean>;
13
- ServiceAvailability: (data: any) => Promise<any>;
14
- addToCartService: (service: any) => Promise<void>;
15
- GetServiceLocations: () => Promise<void>;
16
- serviceSusccess: import("vue").Ref<string, string>;
9
+ serviceSuccess: import("vue").Ref<string, string>;
10
+ checkingAvailability: import("vue").Ref<boolean, boolean>;
11
+ addingToCart: import("vue").Ref<boolean, boolean>;
12
+ location: import("vue").ComputedRef<{
13
+ city?: string | undefined;
14
+ country_name?: string | undefined;
15
+ country_code?: string | undefined;
16
+ country_id?: number | undefined;
17
+ ip?: string | undefined;
18
+ proxy?: boolean | undefined;
19
+ region?: string | undefined;
20
+ region_short?: string | undefined;
21
+ region_id?: number | undefined;
22
+ zip_code?: string | undefined;
23
+ } | null>;
24
+ services: import("vue").ComputedRef<never[]>;
25
+ cart: import("vue").ComputedRef<{
26
+ items?: Record<string, import("../../stores/Cart.js").CartItem> | undefined;
27
+ totals?: Record<string, any> | undefined;
28
+ abndToken?: string | undefined;
29
+ fields?: Record<string, any> | undefined;
30
+ }>;
31
+ loading: import("vue").ComputedRef<boolean>;
32
+ checkAvailability: (payload: ServiceAvailabilityPayload) => Promise<any>;
33
+ checkAvailabilityByLocation: () => Promise<any>;
34
+ addToCart: (service: any) => Promise<boolean>;
35
+ findItemBySlug: (slug: string) => string | false;
36
+ isServiceInCart: (slug: string) => boolean;
37
+ getAllServices: () => Promise<never[]>;
38
+ clearSuccessMessage: () => void;
39
+ closeServiceModal: () => void;
17
40
  };
41
+ export {};
@@ -1,64 +1,140 @@
1
- import { ref, watch, onMounted, computed } from "vue";
1
+ import { ref, computed, watch } from "vue";
2
2
  import { useServiceStore } from "../../stores/Services.js";
3
3
  import { useCartStore } from "../../stores/Cart.js";
4
4
  import { useIpLocation } from "../../stores/IpLocation.js";
5
- export default function(props) {
6
- const CurrentService = ref([]);
7
- const ServiceStore = useServiceStore();
5
+ export function useService() {
6
+ const serviceStore = useServiceStore();
7
+ const cartStore = useCartStore();
8
+ const locationStore = useIpLocation();
9
+ const currentService = ref([]);
8
10
  const servicesAvailability = ref(false);
9
- const serviceSusccess = ref("");
10
- const ServiceAvailability = async (data) => {
11
- const response = await ServiceStore.checkAvailability(data);
12
- servicesAvailability.value = response.service;
13
- return response;
11
+ const serviceSuccess = ref("");
12
+ const checkingAvailability = ref(false);
13
+ const addingToCart = ref(false);
14
+ const location = computed(() => locationStore.location);
15
+ const services = computed(() => serviceStore.services);
16
+ const cart = computed(() => cartStore.cart);
17
+ const loading = computed(() => serviceStore.loading);
18
+ const checkAvailability = async (payload) => {
19
+ if (!payload.shipping_country || !payload.shipping_state || !payload.shipping_postcode) {
20
+ console.error("Invalid availability check payload:", payload);
21
+ return null;
22
+ }
23
+ checkingAvailability.value = true;
24
+ try {
25
+ const response = await serviceStore.checkAvailability(payload);
26
+ if (response?.service !== void 0) {
27
+ servicesAvailability.value = response.service;
28
+ }
29
+ return response;
30
+ } catch (error) {
31
+ console.error("Error checking service availability:", error);
32
+ return null;
33
+ } finally {
34
+ checkingAvailability.value = false;
35
+ }
14
36
  };
15
- const ipLocation = computed(() => useIpLocation().location);
16
- watch(ipLocation, async (newvalue, oldvalue) => {
17
- if (useIpLocation().location != null) {
18
- await ServiceAvailability({ shipping_country: useIpLocation().location.country_id, shipping_state: useIpLocation().location.region_id, shipping_postcode: useIpLocation().location.zip_code });
37
+ const checkAvailabilityByLocation = async () => {
38
+ if (!location.value) {
39
+ console.warn("No location available for availability check");
40
+ return null;
19
41
  }
20
- });
21
- const addToCartService = async (service) => {
22
- await useCartStore().addToCart("", 1, "", "", service);
23
- if (useCartStore().addedResponse == "success") {
24
- serviceSusccess.value = "Services Added to cart.";
42
+ const payload = {
43
+ shipping_country: location.value.country_id,
44
+ shipping_state: location.value.region_id,
45
+ shipping_postcode: location.value.zip_code
46
+ };
47
+ return await checkAvailability(payload);
48
+ };
49
+ const addToCart = async (service) => {
50
+ if (!service) {
51
+ console.error("No service provided");
52
+ return false;
25
53
  }
26
- var modalEl = document.querySelector(".serviceModelSuccess");
27
- var serviceModelsuccess = bootstrap.Modal.getInstance(modalEl);
28
- if (serviceModelsuccess) {
29
- serviceModelsuccess.hide();
54
+ addingToCart.value = true;
55
+ serviceSuccess.value = "";
56
+ try {
57
+ await cartStore.addToCart("", 1, "", "", service);
58
+ if (cartStore.addedResponse === "success") {
59
+ serviceSuccess.value = "Service added to cart successfully.";
60
+ closeServiceModal();
61
+ return true;
62
+ }
63
+ return false;
64
+ } catch (error) {
65
+ console.error("Error adding service to cart:", error);
66
+ return false;
67
+ } finally {
68
+ addingToCart.value = false;
30
69
  }
31
70
  };
32
71
  const findItemBySlug = (slug) => {
33
- if (Object.values(useCartStore().cart).length > 0) {
34
- const entries = Object.values(useCartStore().cart.items);
35
- let item = entries.find((entry) => entry.slug === slug);
36
- if (item) {
37
- return item.rowId;
38
- } else {
39
- return false;
72
+ if (!cart.value?.items || Object.keys(cart.value.items).length === 0) {
73
+ return false;
74
+ }
75
+ const entries = Object.values(cart.value.items);
76
+ const item = entries.find((entry) => entry.slug === slug);
77
+ return item ? item.rowId : false;
78
+ };
79
+ const isServiceInCart = (slug) => {
80
+ return findItemBySlug(slug) !== false;
81
+ };
82
+ const closeServiceModal = () => {
83
+ const modalEl = document.querySelector(".serviceModelSuccess");
84
+ if (modalEl && typeof bootstrap !== "undefined") {
85
+ const serviceModal = bootstrap.Modal.getInstance(modalEl);
86
+ if (serviceModal) {
87
+ serviceModal.hide();
40
88
  }
41
89
  }
42
- return false;
43
90
  };
44
- onMounted(async () => {
45
- await ServiceStore.getAllServices();
46
- findItemBySlug("check-measure");
47
- if (useIpLocation().location != null) {
48
- ServiceAvailability({ shipping_country: useIpLocation().location.country_id, shipping_state: useIpLocation().location.region_id, shipping_postcode: useIpLocation().location.zip_code });
91
+ const getAllServices = async () => {
92
+ try {
93
+ await serviceStore.getAllServices();
94
+ return services.value;
95
+ } catch (error) {
96
+ console.error("Error fetching services:", error);
97
+ return [];
49
98
  }
50
- });
51
- const GetServiceLocations = async () => {
52
99
  };
100
+ const clearSuccessMessage = () => {
101
+ serviceSuccess.value = "";
102
+ };
103
+ const autoClearSuccess = () => {
104
+ if (serviceSuccess.value) {
105
+ setTimeout(() => {
106
+ clearSuccessMessage();
107
+ }, 5e3);
108
+ }
109
+ };
110
+ watch(location, async (newLocation) => {
111
+ if (newLocation) {
112
+ await checkAvailabilityByLocation();
113
+ }
114
+ });
115
+ watch(() => serviceSuccess.value, () => {
116
+ autoClearSuccess();
117
+ });
53
118
  return {
54
- useCartStore,
55
- ServiceStore,
56
- CurrentService,
57
- findItemBySlug,
119
+ // State
120
+ currentService,
58
121
  servicesAvailability,
59
- ServiceAvailability,
60
- addToCartService,
61
- GetServiceLocations,
62
- serviceSusccess
122
+ serviceSuccess,
123
+ checkingAvailability,
124
+ addingToCart,
125
+ // Computed
126
+ location,
127
+ services,
128
+ cart,
129
+ loading,
130
+ // Methods
131
+ checkAvailability,
132
+ checkAvailabilityByLocation,
133
+ addToCart,
134
+ findItemBySlug,
135
+ isServiceInCart,
136
+ getAllServices,
137
+ clearSuccessMessage,
138
+ closeServiceModal
63
139
  };
64
140
  }
@@ -1,13 +1,63 @@
1
- export interface LocationData {
1
+ interface LocationInputs {
2
2
  country: string;
3
- countryCode?: string;
4
- state?: string;
3
+ country_id: string | number;
4
+ zip_code: string | number;
5
+ region: string;
6
+ region_id: string | number | null;
7
+ }
8
+ interface LocationData {
5
9
  city?: string;
10
+ country_name?: string;
11
+ country_code?: string;
12
+ country_id?: number;
13
+ ip?: string;
14
+ proxy?: boolean;
15
+ region?: string;
16
+ region_short?: string;
17
+ region_id?: number;
18
+ zip_code?: string;
6
19
  }
7
- export declare const useLocation: () => {
8
- location: Readonly<import("vue").Ref<any, any>>;
9
- shippingCountry: Readonly<import("vue").Ref<any, any>>;
10
- updateLocation: (newLocation: Partial<LocationData>) => void;
11
- updateCountry: (country: string, countryCode?: string) => void;
12
- resetLocation: () => void;
20
+ export declare function useLocation(): {
21
+ states: import("vue").Ref<never[], never[]>;
22
+ manualLocationHeading: import("vue").Ref<string | null, string | null>;
23
+ locationInputs: import("vue").Ref<{
24
+ country: string;
25
+ country_id: string | number;
26
+ zip_code: string | number;
27
+ region: string;
28
+ region_id: string | number | null;
29
+ }, LocationInputs | {
30
+ country: string;
31
+ country_id: string | number;
32
+ zip_code: string | number;
33
+ region: string;
34
+ region_id: string | number | null;
35
+ }>;
36
+ location: import("vue").ComputedRef<{
37
+ city?: string | undefined;
38
+ country_name?: string | undefined;
39
+ country_code?: string | undefined;
40
+ country_id?: number | undefined;
41
+ ip?: string | undefined;
42
+ proxy?: boolean | undefined;
43
+ region?: string | undefined;
44
+ region_short?: string | undefined;
45
+ region_id?: number | undefined;
46
+ zip_code?: string | undefined;
47
+ } | null>;
48
+ countries: import("vue").ComputedRef<any>;
49
+ loading: import("vue").ComputedRef<boolean>;
50
+ companyCountryId: import("vue").ComputedRef<any>;
51
+ getStateShort: (stateName: string) => string;
52
+ getStates: (countryId: number | string) => any;
53
+ changeStates: (selectedCountry: string | number) => void;
54
+ changeLocation: (data?: Partial<LocationInputs>) => Promise<void>;
55
+ updateLocationData: (data?: Partial<LocationInputs>) => Promise<void>;
56
+ getLocation: () => Promise<void>;
57
+ checkCurrentLocation: () => void;
58
+ initLocationInputs: () => void;
59
+ loadLocation: () => LocationData | null;
60
+ checkLocationPermission: () => Promise<string>;
61
+ initializeCountriesAndStates: () => Promise<void>;
13
62
  };
63
+ export {};
@@ -1,32 +1,357 @@
1
- import { computed, readonly } from "vue";
2
- import { useCookie } from "#imports";
3
- export const useLocation = () => {
4
- const locationCookie = useCookie("location", {
5
- default: () => ({ country: "US" }),
6
- // Default country
7
- maxAge: 60 * 60 * 24 * 365,
8
- // 1 year
9
- sameSite: "lax"
1
+ import { ref, computed, watch, nextTick } from "vue";
2
+ import { useIpLocation } from "../stores/IpLocation.js";
3
+ import { useCountriesStore } from "../stores/countries.js";
4
+ import { useCompanyProfile } from "../stores/useCompanyProfile.js";
5
+ import { useCheckoutStore } from "../stores/Checkout.js";
6
+ export function useLocation() {
7
+ const locationStore = useIpLocation();
8
+ const countriesStore = useCountriesStore();
9
+ const companyProfileStore = useCompanyProfile();
10
+ const checkoutStore = useCheckoutStore();
11
+ const states = ref([]);
12
+ const manualLocationHeading = ref(null);
13
+ const locationInputs = ref({
14
+ country: "Australia",
15
+ country_id: 14,
16
+ zip_code: 3370,
17
+ region: "",
18
+ region_id: null
10
19
  });
11
- const location = computed(() => locationCookie.value);
12
- const updateLocation = (newLocation) => {
13
- locationCookie.value = {
14
- ...locationCookie.value,
15
- ...newLocation
20
+ const location = computed(() => locationStore.location);
21
+ const countries = computed(() => {
22
+ const storeCountries = countriesStore.countries;
23
+ if (Array.isArray(storeCountries)) {
24
+ return storeCountries;
25
+ } else if (storeCountries?.data && Array.isArray(storeCountries.data)) {
26
+ return storeCountries.data;
27
+ }
28
+ return [];
29
+ });
30
+ const loading = computed(() => locationStore.loading);
31
+ const profile = computed(() => companyProfileStore.profile);
32
+ const companyCountryId = computed(() => profile.value?.country_id || 14);
33
+ const stateShortCodes = {
34
+ "New South Wales": "NSW",
35
+ "Victoria": "VIC",
36
+ "Queensland": "QLD",
37
+ "South Australia": "SA",
38
+ "Western Australia": "WA",
39
+ "Tasmania": "TAS",
40
+ "Northern Territory": "NT",
41
+ "Australian Capital Territory": "ACT"
42
+ };
43
+ const getStateShort = (stateName) => {
44
+ return stateShortCodes[stateName] || stateName;
45
+ };
46
+ const getStates = (countryId) => {
47
+ if (!countries.value || countries.value.length === 0) {
48
+ console.warn("No countries available");
49
+ return [];
50
+ }
51
+ const activeCountry = countries.value.find(
52
+ (country) => country.id == countryId || country.name == countryId
53
+ );
54
+ if (activeCountry && activeCountry.states) {
55
+ states.value = activeCountry.states;
56
+ return activeCountry.states;
57
+ } else {
58
+ states.value = [];
59
+ console.warn("No states found for country:", countryId);
60
+ return [];
61
+ }
62
+ };
63
+ const changeStates = (selectedCountry) => {
64
+ const country = countries.value?.find(
65
+ (c) => c.name === selectedCountry || c.id === selectedCountry
66
+ );
67
+ if (country) {
68
+ states.value = country.states || [];
69
+ locationInputs.value.country_id = country.id;
70
+ locationInputs.value.region = "";
71
+ locationInputs.value.region_id = null;
72
+ if (window.locationcountry === country.name && window.locationstate) {
73
+ locationInputs.value.region = window.locationstate;
74
+ const state = country.states?.find((s) => s.name === window.locationstate);
75
+ if (state) {
76
+ locationInputs.value.region_id = state.id;
77
+ }
78
+ }
79
+ } else {
80
+ console.warn("Country not found:", selectedCountry);
81
+ }
82
+ };
83
+ const updateLocationData = async (data = {}) => {
84
+ try {
85
+ const currentLocation = location.value;
86
+ const updateData = {
87
+ region: data.region || currentLocation?.region || "",
88
+ region_id: data.region_id || currentLocation?.region_id || null,
89
+ zip_code: data.zip_code || currentLocation?.zip_code || "",
90
+ country: data.country || currentLocation?.country_name || "Australia",
91
+ country_id: data.country_id || currentLocation?.country_id || companyCountryId.value
92
+ };
93
+ const country = countries.value?.find(
94
+ (c) => c.name === updateData.country || c.id === updateData.country_id
95
+ );
96
+ if (!country) {
97
+ console.error("Country not found:", updateData.country);
98
+ return;
99
+ }
100
+ const state = country.states?.find(
101
+ (s) => s.name === updateData.region || s.id === updateData.region_id
102
+ );
103
+ if (!state) {
104
+ console.error("State not found:", updateData.region);
105
+ return;
106
+ }
107
+ const newLocation = {
108
+ zip_code: updateData.zip_code,
109
+ region: state.name,
110
+ region_short: getStateShort(state.name),
111
+ region_id: state.id,
112
+ country_name: country.name,
113
+ country_id: country.id
114
+ };
115
+ locationStore.location = newLocation;
116
+ checkoutStore.saveToCheckoutSession(newLocation, "changelocation");
117
+ } catch (error) {
118
+ console.error("Error updating location:", error);
119
+ }
120
+ };
121
+ const changeLocation = async (data) => {
122
+ if (data && Object.keys(data).length > 0) {
123
+ await updateLocationData(data);
124
+ }
125
+ };
126
+ const checkLocationPermission = async () => {
127
+ try {
128
+ const permissionStatus = await navigator.permissions.query({
129
+ name: "geolocation"
130
+ });
131
+ return permissionStatus.state;
132
+ } catch (error) {
133
+ console.error("Permission check failed:", error);
134
+ return "error";
135
+ }
136
+ };
137
+ const getBrowserLocation = async () => {
138
+ return new Promise((resolve, reject) => {
139
+ if (!navigator.geolocation) {
140
+ reject(new Error("Geolocation not supported"));
141
+ return;
142
+ }
143
+ navigator.geolocation.getCurrentPosition(
144
+ async (position) => {
145
+ try {
146
+ await processGeolocation(position);
147
+ resolve();
148
+ } catch (error) {
149
+ reject(error);
150
+ }
151
+ },
152
+ async (error) => {
153
+ console.error("Geolocation error:", error);
154
+ if (profile.value?.iplocation && !location.value) {
155
+ await locationStore.getLocation();
156
+ } else {
157
+ manualLocationHeading.value = "We need your location to check service availability in your area. You can add your location manually.";
158
+ const changeLocationBtn = document.querySelector(".change_location");
159
+ if (changeLocationBtn) {
160
+ changeLocationBtn.click();
161
+ }
162
+ }
163
+ reject(error);
164
+ }
165
+ );
166
+ });
167
+ };
168
+ const processGeolocation = async (position) => {
169
+ const lat = position.coords.latitude;
170
+ const lng = position.coords.longitude;
171
+ const apiKey = window.GeocodingAPI;
172
+ if (!apiKey) {
173
+ throw new Error("Geocoding API key not found");
174
+ }
175
+ try {
176
+ const response = await fetch(
177
+ `https://maps.googleapis.com/maps/api/geocode/json?latlng=${lat},${lng}&key=${apiKey}`
178
+ );
179
+ const data = await response.json();
180
+ if (data.status !== "OK") {
181
+ throw new Error("Geocoding failed");
182
+ }
183
+ const locationData = extractLocationData(data.results);
184
+ const country = countries.value?.find((c) => c.name === locationData.country);
185
+ if (country) {
186
+ const state = country.states?.find((s) => s.name === locationData.state);
187
+ locationStore.location = {
188
+ city: locationData.city,
189
+ country_name: country.name,
190
+ country_code: locationData.country_code,
191
+ country_id: country.id,
192
+ ip: "",
193
+ proxy: false,
194
+ region: locationData.state,
195
+ region_short: locationData.state_short,
196
+ region_id: state?.id,
197
+ zip_code: locationData.postal_code
198
+ };
199
+ }
200
+ } catch (error) {
201
+ console.error("Geocoding error:", error);
202
+ if (profile.value?.iplocation && !location.value) {
203
+ await locationStore.getLocation();
204
+ }
205
+ }
206
+ };
207
+ const extractLocationData = (results) => {
208
+ const data = {
209
+ city: "N/A",
210
+ country: "N/A",
211
+ country_code: "N/A",
212
+ state: "N/A",
213
+ state_short: "N/A",
214
+ postal_code: "N/A"
16
215
  };
216
+ for (const result of results) {
217
+ for (const component of result.address_components) {
218
+ if (component.types.includes("administrative_area_level_2")) {
219
+ data.city = component.long_name;
220
+ }
221
+ if (component.types.includes("country")) {
222
+ data.country = component.long_name;
223
+ data.country_code = component.short_name;
224
+ }
225
+ if (component.types.includes("administrative_area_level_1")) {
226
+ data.state = component.long_name;
227
+ data.state_short = component.short_name;
228
+ }
229
+ if (component.types.includes("postal_code")) {
230
+ data.postal_code = component.long_name;
231
+ }
232
+ }
233
+ }
234
+ return data;
235
+ };
236
+ const initializeCountriesAndStates = async () => {
237
+ try {
238
+ if (!countries.value || countries.value.length === 0) {
239
+ const fetchedCountries = await countriesStore.getCountries();
240
+ }
241
+ await nextTick();
242
+ if (countries.value && countries.value.length > 0) {
243
+ const statesResult = getStates(companyCountryId.value);
244
+ const defaultCountry = countries.value.find((c) => c.id === companyCountryId.value);
245
+ if (defaultCountry) {
246
+ locationInputs.value.country = defaultCountry.name;
247
+ locationInputs.value.country_id = defaultCountry.id;
248
+ }
249
+ }
250
+ } catch (error) {
251
+ console.error("Error initializing countries and states:", error);
252
+ }
253
+ };
254
+ const getLocation = async () => {
255
+ try {
256
+ await initializeCountriesAndStates();
257
+ if (location.value) {
258
+ initLocationInputs();
259
+ return;
260
+ }
261
+ if (profile.value) {
262
+ profile.value.iplocation = true;
263
+ }
264
+ if (window.GeocodingAPI && !location.value) {
265
+ try {
266
+ await getBrowserLocation();
267
+ return;
268
+ } catch (error) {
269
+ console.log("Browser location failed, falling back to IP location");
270
+ }
271
+ }
272
+ if (profile.value?.iplocation && !location.value) {
273
+ await locationStore.getLocation();
274
+ }
275
+ if (location.value) {
276
+ initLocationInputs();
277
+ }
278
+ } catch (error) {
279
+ console.error("Error getting location:", error);
280
+ }
17
281
  };
18
- const updateCountry = (country, countryCode) => {
19
- updateLocation({ country, countryCode });
282
+ const checkCurrentLocation = () => {
283
+ if (location.value?.region) {
284
+ locationInputs.value.region = location.value.region;
285
+ locationInputs.value.region_id = location.value.region_id || null;
286
+ if (location.value.country_id) {
287
+ getStates(location.value.country_id);
288
+ }
289
+ }
20
290
  };
21
- const shippingCountry = computed(() => location.value.country);
22
- const resetLocation = () => {
23
- locationCookie.value = { country: "US" };
291
+ const initLocationInputs = () => {
292
+ if (location.value) {
293
+ locationInputs.value = {
294
+ country: location.value.country_name || "Australia",
295
+ country_id: location.value.country_id || companyCountryId.value,
296
+ zip_code: location.value.zip_code || 3370,
297
+ region: location.value.region || "",
298
+ region_id: location.value.region_id || null
299
+ };
300
+ if (location.value.country_id) {
301
+ getStates(location.value.country_id);
302
+ }
303
+ }
24
304
  };
305
+ const loadLocation = () => {
306
+ const stored = localStorage.getItem("IpLocation");
307
+ if (stored) {
308
+ try {
309
+ const parsed = JSON.parse(stored);
310
+ return parsed.location || null;
311
+ } catch (error) {
312
+ console.error("Invalid IpLocation data:", error);
313
+ return null;
314
+ }
315
+ }
316
+ return null;
317
+ };
318
+ watch(location, (newLocation) => {
319
+ if (newLocation) {
320
+ initLocationInputs();
321
+ }
322
+ });
323
+ watch(countries, (newCountries) => {
324
+ if (newCountries && newCountries.length > 0) {
325
+ getStates(companyCountryId.value);
326
+ if (locationInputs.value.country_id) {
327
+ const country = newCountries.find((c) => c.id === locationInputs.value.country_id);
328
+ if (country) {
329
+ locationInputs.value.country = country.name;
330
+ }
331
+ }
332
+ }
333
+ });
25
334
  return {
26
- location: readonly(location),
27
- shippingCountry: readonly(shippingCountry),
28
- updateLocation,
29
- updateCountry,
30
- resetLocation
335
+ // State
336
+ states,
337
+ manualLocationHeading,
338
+ locationInputs,
339
+ // Computed
340
+ location,
341
+ countries,
342
+ loading,
343
+ companyCountryId,
344
+ // Methods
345
+ getStateShort,
346
+ getStates,
347
+ changeStates,
348
+ changeLocation,
349
+ updateLocationData,
350
+ getLocation,
351
+ checkCurrentLocation,
352
+ initLocationInputs,
353
+ loadLocation,
354
+ checkLocationPermission,
355
+ initializeCountriesAndStates
31
356
  };
32
- };
357
+ }
@@ -78,7 +78,11 @@ export const useCheckoutStore = defineStore("checkout", {
78
78
  if (useCartStore().coupon?.length > 0) {
79
79
  formData.vouchercodes = useCartStore().coupon;
80
80
  }
81
- formData.cart = useCartStore().cart.items;
81
+ if (useCartStore().cart.items != void 0 && Object.keys(useCartStore().cart.items).length > 0) {
82
+ formData.cart = useCartStore().cart.items;
83
+ } else {
84
+ delete formData.cart;
85
+ }
82
86
  formData.abndToken = useCartStore().cart.abndToken;
83
87
  const apiUrl = `checkout/configs`;
84
88
  const config = useRuntimeConfig();
@@ -1,4 +1,4 @@
1
- interface LocationData {
1
+ export interface LocationData {
2
2
  city?: string;
3
3
  country_name?: string;
4
4
  country_code?: string;
@@ -10,9 +10,100 @@ interface LocationData {
10
10
  region_id?: number;
11
11
  zip_code?: string;
12
12
  }
13
+ export interface LocationResponse {
14
+ status: string;
15
+ message?: string;
16
+ data: LocationData | null;
17
+ }
13
18
  export declare const useIpLocation: import("pinia").StoreDefinition<"IpLocation", {
14
19
  location: LocationData | null;
15
- }, {}, {
16
- getLocation(): Promise<void>;
20
+ loading: boolean;
21
+ error: string | null;
22
+ }, {
23
+ hasLocation: (state: {
24
+ location: {
25
+ city?: string | undefined;
26
+ country_name?: string | undefined;
27
+ country_code?: string | undefined;
28
+ country_id?: number | undefined;
29
+ ip?: string | undefined;
30
+ proxy?: boolean | undefined;
31
+ region?: string | undefined;
32
+ region_short?: string | undefined;
33
+ region_id?: number | undefined;
34
+ zip_code?: string | undefined;
35
+ } | null;
36
+ loading: boolean;
37
+ error: string | null;
38
+ } & import("pinia").PiniaCustomStateProperties<{
39
+ location: LocationData | null;
40
+ loading: boolean;
41
+ error: string | null;
42
+ }>) => boolean;
43
+ isLoading: (state: {
44
+ location: {
45
+ city?: string | undefined;
46
+ country_name?: string | undefined;
47
+ country_code?: string | undefined;
48
+ country_id?: number | undefined;
49
+ ip?: string | undefined;
50
+ proxy?: boolean | undefined;
51
+ region?: string | undefined;
52
+ region_short?: string | undefined;
53
+ region_id?: number | undefined;
54
+ zip_code?: string | undefined;
55
+ } | null;
56
+ loading: boolean;
57
+ error: string | null;
58
+ } & import("pinia").PiniaCustomStateProperties<{
59
+ location: LocationData | null;
60
+ loading: boolean;
61
+ error: string | null;
62
+ }>) => boolean;
63
+ locationString: (state: {
64
+ location: {
65
+ city?: string | undefined;
66
+ country_name?: string | undefined;
67
+ country_code?: string | undefined;
68
+ country_id?: number | undefined;
69
+ ip?: string | undefined;
70
+ proxy?: boolean | undefined;
71
+ region?: string | undefined;
72
+ region_short?: string | undefined;
73
+ region_id?: number | undefined;
74
+ zip_code?: string | undefined;
75
+ } | null;
76
+ loading: boolean;
77
+ error: string | null;
78
+ } & import("pinia").PiniaCustomStateProperties<{
79
+ location: LocationData | null;
80
+ loading: boolean;
81
+ error: string | null;
82
+ }>) => string;
83
+ fullAddress: (state: {
84
+ location: {
85
+ city?: string | undefined;
86
+ country_name?: string | undefined;
87
+ country_code?: string | undefined;
88
+ country_id?: number | undefined;
89
+ ip?: string | undefined;
90
+ proxy?: boolean | undefined;
91
+ region?: string | undefined;
92
+ region_short?: string | undefined;
93
+ region_id?: number | undefined;
94
+ zip_code?: string | undefined;
95
+ } | null;
96
+ loading: boolean;
97
+ error: string | null;
98
+ } & import("pinia").PiniaCustomStateProperties<{
99
+ location: LocationData | null;
100
+ loading: boolean;
101
+ error: string | null;
102
+ }>) => string;
103
+ }, {
104
+ getLocation(): Promise<LocationData | null>;
105
+ setLocation(locationData: LocationData): void;
106
+ updateLocation(partialData: Partial<LocationData>): void;
107
+ clearLocation(): void;
108
+ clearError(): void;
17
109
  }>;
18
- export {};
@@ -1,29 +1,107 @@
1
1
  import { defineStore } from "pinia";
2
+ import { flowrixApi } from "../middleware/flowrix.js";
3
+ import { useRuntimeConfig } from "#imports";
4
+ function formatErrorMessage(message) {
5
+ if (Array.isArray(message)) {
6
+ return message.join(", ");
7
+ }
8
+ return message;
9
+ }
2
10
  export const useIpLocation = defineStore("IpLocation", {
3
11
  state: () => ({
4
- location: null
12
+ location: null,
13
+ loading: false,
14
+ error: null
5
15
  }),
16
+ getters: {
17
+ hasLocation: (state) => state.location !== null,
18
+ isLoading: (state) => state.loading,
19
+ locationString: (state) => {
20
+ if (!state.location) return "";
21
+ const parts = [
22
+ state.location.city,
23
+ state.location.region_short || state.location.region,
24
+ state.location.zip_code
25
+ ].filter(Boolean);
26
+ return parts.join(", ");
27
+ },
28
+ fullAddress: (state) => {
29
+ if (!state.location) return "";
30
+ const parts = [
31
+ state.location.city,
32
+ state.location.region,
33
+ state.location.zip_code,
34
+ state.location.country_name
35
+ ].filter(Boolean);
36
+ return parts.join(", ");
37
+ }
38
+ },
6
39
  actions: {
7
40
  async getLocation() {
41
+ if (this.loading || this.location !== null) {
42
+ console.log("Location already loaded or loading:", this.location);
43
+ return this.location;
44
+ }
45
+ this.loading = true;
46
+ this.error = null;
8
47
  try {
9
- if (this.location == null) {
10
- const response = await $fetch(`/api/location`, {
11
- method: "POST",
12
- headers: {
13
- "Content-Type": "application/json"
14
- }
15
- });
16
- if (response.status == "Success" && response.data != null) {
17
- this.location = response.data;
18
- } else {
19
- this.location = null;
20
- }
48
+ const config = useRuntimeConfig();
49
+ let rawCookies = "";
50
+ if (process.client) {
51
+ rawCookies = document.cookie || "";
52
+ }
53
+ const apiConfig = {
54
+ ...config,
55
+ cookies: rawCookies
56
+ };
57
+ const apiUrl = "location";
58
+ const response = await flowrixApi.post(apiUrl, apiConfig);
59
+ if (response.status === "Success" && response.data !== null) {
60
+ this.location = response.data;
61
+ console.log("Location loaded:", this.location);
62
+ return response.data;
63
+ } else {
64
+ const errorMessage = response.message ? formatErrorMessage(response.message) : "Failed to fetch location";
65
+ this.error = errorMessage;
66
+ console.error("Failed to fetch location:", errorMessage);
67
+ this.location = null;
68
+ return null;
21
69
  }
22
70
  } catch (error) {
23
- console.error("Error fetching data:", error);
71
+ console.error("Error fetching location:", error);
72
+ this.error = error.message || "Unknown error occurred";
24
73
  this.location = null;
74
+ return null;
75
+ } finally {
76
+ this.loading = false;
77
+ }
78
+ },
79
+ setLocation(locationData) {
80
+ this.location = locationData;
81
+ this.error = null;
82
+ console.log("Location set manually:", this.location);
83
+ },
84
+ updateLocation(partialData) {
85
+ if (this.location) {
86
+ this.location = { ...this.location, ...partialData };
87
+ console.log("Location updated:", this.location);
88
+ } else {
89
+ console.warn("Cannot update location: no location data exists");
25
90
  }
91
+ },
92
+ clearLocation() {
93
+ this.location = null;
94
+ this.error = null;
95
+ this.loading = false;
96
+ console.log("Location cleared");
97
+ },
98
+ clearError() {
99
+ this.error = null;
26
100
  }
27
101
  },
28
- persist: true
102
+ persist: {
103
+ key: "IpLocation",
104
+ storage: typeof window !== "undefined" ? localStorage : void 0,
105
+ paths: ["location"]
106
+ }
29
107
  });
@@ -1,6 +1,8 @@
1
1
  export declare const useServiceStore: import("pinia").StoreDefinition<"ServiceStore", {
2
2
  services: never[];
3
3
  availability: boolean;
4
+ loading: boolean;
5
+ error: string | null;
4
6
  }, {}, {
5
7
  getAllServices(): Promise<void>;
6
8
  checkAvailability(data: any): Promise<any>;
@@ -1,9 +1,13 @@
1
1
  import { defineStore } from "pinia";
2
+ import { flowrixApi } from "../middleware/flowrix.js";
3
+ import { useRuntimeConfig } from "#imports";
2
4
  import { useCheckoutStore } from "./Checkout.js";
3
5
  export const useServiceStore = defineStore("ServiceStore", {
4
6
  state: () => ({
5
7
  services: [],
6
- availability: false
8
+ availability: false,
9
+ loading: false,
10
+ error: null
7
11
  }),
8
12
  actions: {
9
13
  async getAllServices() {
@@ -25,24 +29,36 @@ export const useServiceStore = defineStore("ServiceStore", {
25
29
  }
26
30
  },
27
31
  async checkAvailability(data) {
32
+ this.loading = true;
33
+ this.error = null;
28
34
  try {
29
- const apiUrl = `/api/services/availability`;
30
- const response = await $fetch(apiUrl, {
31
- method: "POST",
32
- headers: {
33
- "Content-Type": "application/json"
34
- },
35
+ const config = useRuntimeConfig();
36
+ let rawCookies = "";
37
+ if (process.client) {
38
+ rawCookies = document.cookie || "";
39
+ }
40
+ const apiConfig = {
41
+ ...config,
42
+ cookies: rawCookies
43
+ };
44
+ const apiUrl = "services/availability";
45
+ const response = await flowrixApi.post(apiUrl, apiConfig, {
35
46
  body: data
36
47
  });
37
- if (response.status == "Success") {
48
+ if (response.status === "Success") {
38
49
  this.availability = response.data.service;
39
50
  useCheckoutStore().saveToCheckoutSession(data);
40
51
  return response.data;
41
52
  } else {
42
- this.data = null;
53
+ this.error = response.message || "Failed to check availability";
54
+ return null;
43
55
  }
44
56
  } catch (error) {
45
- console.error("Error fetching data:", error);
57
+ console.error("Error checking availability:", error);
58
+ this.error = error.message || "Failed to check availability";
59
+ return null;
60
+ } finally {
61
+ this.loading = false;
46
62
  }
47
63
  }
48
64
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "flowrix",
3
- "version": "1.0.1-beta.128",
3
+ "version": "1.0.1-beta.129",
4
4
  "description": "Plug-and-play Nuxt eCommerce cart powered by FLOWRiX. Subscription required.",
5
5
  "license": "MIT",
6
6
  "type": "module",