@tagadapay/plugin-sdk 2.4.9 → 2.4.12

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.
@@ -0,0 +1,137 @@
1
+ export interface GeoLocationData {
2
+ ip_address?: string | null;
3
+ city?: string | null;
4
+ city_geoname_id?: number | null;
5
+ region?: string | null;
6
+ region_iso_code?: string | null;
7
+ region_geoname_id?: number | null;
8
+ postal_code?: string | null;
9
+ country?: string | null;
10
+ country_code?: string | null;
11
+ country_geoname_id?: number | null;
12
+ country_is_eu?: boolean | null;
13
+ continent?: string | null;
14
+ continent_code?: string | null;
15
+ continent_geoname_id?: number | null;
16
+ latitude?: number | null;
17
+ longitude?: number | null;
18
+ security?: {
19
+ is_vpn?: boolean | null;
20
+ } | null;
21
+ timezone?: {
22
+ name?: string | null;
23
+ abbreviation?: string | null;
24
+ gmt_offset?: number | null;
25
+ current_time?: string | null;
26
+ is_dst?: boolean | null;
27
+ } | null;
28
+ currency?: {
29
+ currency_name?: string | null;
30
+ currency_code?: string | null;
31
+ } | null;
32
+ connection?: {
33
+ autonomous_system_number?: number | null;
34
+ autonomous_system_organization?: string | null;
35
+ connection_type?: string | null;
36
+ isp_name?: string | null;
37
+ organization_name?: string | null;
38
+ } | null;
39
+ flag?: {
40
+ emoji?: string | null;
41
+ unicode?: string | null;
42
+ png?: string | null;
43
+ svg?: string | null;
44
+ } | null;
45
+ as?: string | null;
46
+ isp?: string | null;
47
+ lat?: number | null;
48
+ lon?: number | null;
49
+ org?: string | null;
50
+ query?: string | null;
51
+ regionName?: string | null;
52
+ status?: string | null;
53
+ zip?: string | null;
54
+ error?: string;
55
+ }
56
+ export interface UseGeoLocationOptions {
57
+ /**
58
+ * Whether to automatically fetch geolocation data on mount
59
+ * @default true
60
+ */
61
+ autoFetch?: boolean;
62
+ /**
63
+ * Custom IP address to fetch geolocation for
64
+ * If not provided, will use the client's IP
65
+ */
66
+ ip?: string;
67
+ /**
68
+ * Whether to refetch data when the hook mounts
69
+ * @default false
70
+ */
71
+ refetchOnMount?: boolean;
72
+ }
73
+ export interface UseGeoLocationReturn {
74
+ /**
75
+ * The geolocation data
76
+ */
77
+ data: GeoLocationData | null;
78
+ /**
79
+ * Whether the request is currently loading
80
+ */
81
+ isLoading: boolean;
82
+ /**
83
+ * Any error that occurred during the request
84
+ */
85
+ error: string | null;
86
+ /**
87
+ * Function to manually fetch geolocation data
88
+ */
89
+ fetchGeoData: (ip?: string) => Promise<void>;
90
+ /**
91
+ * Function to clear the current data and error state
92
+ */
93
+ clearData: () => void;
94
+ /**
95
+ * Whether the data is from localhost/development
96
+ */
97
+ isLocalhost: boolean;
98
+ /**
99
+ * Whether the current IP is valid
100
+ */
101
+ isValidIP: boolean;
102
+ }
103
+ /**
104
+ * Hook to fetch and manage geolocation data
105
+ *
106
+ * @example
107
+ * ```tsx
108
+ * function MyComponent() {
109
+ * const { data, isLoading, error, fetchGeoData } = useGeoLocation();
110
+ *
111
+ * if (isLoading) return <div>Loading location...</div>;
112
+ * if (error) return <div>Error: {error}</div>;
113
+ *
114
+ * return (
115
+ * <div>
116
+ * <p>Country: {data?.country}</p>
117
+ * <p>City: {data?.city}</p>
118
+ * <p>IP: {data?.ip_address}</p>
119
+ * </div>
120
+ * );
121
+ * }
122
+ * ```
123
+ *
124
+ * @example
125
+ * ```tsx
126
+ * function MyComponent() {
127
+ * const { fetchGeoData } = useGeoLocation({ autoFetch: false });
128
+ *
129
+ * const handleClick = () => {
130
+ * fetchGeoData('8.8.8.8'); // Fetch for specific IP
131
+ * };
132
+ *
133
+ * return <button onClick={handleClick}>Get Location for Google DNS</button>;
134
+ * }
135
+ * ```
136
+ */
137
+ export declare function useGeoLocation(options?: UseGeoLocationOptions): UseGeoLocationReturn;
@@ -0,0 +1,125 @@
1
+ 'use client';
2
+ import { useCallback, useEffect, useState } from 'react';
3
+ import { useTagadaContext } from '../providers/TagadaProvider';
4
+ /**
5
+ * Hook to fetch and manage geolocation data
6
+ *
7
+ * @example
8
+ * ```tsx
9
+ * function MyComponent() {
10
+ * const { data, isLoading, error, fetchGeoData } = useGeoLocation();
11
+ *
12
+ * if (isLoading) return <div>Loading location...</div>;
13
+ * if (error) return <div>Error: {error}</div>;
14
+ *
15
+ * return (
16
+ * <div>
17
+ * <p>Country: {data?.country}</p>
18
+ * <p>City: {data?.city}</p>
19
+ * <p>IP: {data?.ip_address}</p>
20
+ * </div>
21
+ * );
22
+ * }
23
+ * ```
24
+ *
25
+ * @example
26
+ * ```tsx
27
+ * function MyComponent() {
28
+ * const { fetchGeoData } = useGeoLocation({ autoFetch: false });
29
+ *
30
+ * const handleClick = () => {
31
+ * fetchGeoData('8.8.8.8'); // Fetch for specific IP
32
+ * };
33
+ *
34
+ * return <button onClick={handleClick}>Get Location for Google DNS</button>;
35
+ * }
36
+ * ```
37
+ */
38
+ export function useGeoLocation(options = {}) {
39
+ const { autoFetch = true, ip, refetchOnMount = false } = options;
40
+ const { apiService } = useTagadaContext();
41
+ const [data, setData] = useState(null);
42
+ const [isLoading, setIsLoading] = useState(false);
43
+ const [error, setError] = useState(null);
44
+ // Helper function to check if IP is localhost
45
+ const isLocalhost = useCallback((ipAddress) => {
46
+ if (!ipAddress)
47
+ return false;
48
+ return ipAddress === '127.0.0.1' || ipAddress === '::1' || ipAddress === 'localhost';
49
+ }, []);
50
+ // Helper function to validate IP address format
51
+ const isValidIP = useCallback((ipAddress) => {
52
+ if (!ipAddress)
53
+ return false;
54
+ // IPv4 regex pattern
55
+ const ipv4Pattern = /^(\d{1,3}\.){3}\d{1,3}$/;
56
+ // IPv6 regex pattern (simplified)
57
+ const ipv6Pattern = /^([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$/;
58
+ if (!ipv4Pattern.test(ipAddress) && !ipv6Pattern.test(ipAddress)) {
59
+ return false;
60
+ }
61
+ // Additional validation for IPv4
62
+ if (ipv4Pattern.test(ipAddress)) {
63
+ const parts = ipAddress.split('.');
64
+ return parts.every((part) => {
65
+ const num = parseInt(part, 10);
66
+ return num >= 0 && num <= 255;
67
+ });
68
+ }
69
+ return true;
70
+ }, []);
71
+ // Function to fetch geolocation data
72
+ const fetchGeoData = useCallback(async (customIp) => {
73
+ if (!apiService) {
74
+ setError('API service not available');
75
+ return;
76
+ }
77
+ setIsLoading(true);
78
+ setError(null);
79
+ try {
80
+ const targetIp = customIp || ip;
81
+ const endpoint = targetIp ? `/api/v1/geo?ip=${encodeURIComponent(targetIp)}` : '/api/v1/geo';
82
+ console.log('[SDK] Fetching geolocation data for IP:', targetIp || 'client IP');
83
+ const geoData = await apiService.fetch(endpoint, {
84
+ method: 'GET',
85
+ skipAuth: true, // Geolocation endpoint doesn't require authentication
86
+ });
87
+ setData(geoData);
88
+ console.log('[SDK] Geolocation data fetched successfully:', geoData);
89
+ }
90
+ catch (err) {
91
+ const errorMessage = err instanceof Error ? err.message : 'Failed to fetch geolocation data';
92
+ setError(errorMessage);
93
+ console.error('[SDK] Error fetching geolocation data:', err);
94
+ }
95
+ finally {
96
+ setIsLoading(false);
97
+ }
98
+ }, [apiService, ip]);
99
+ // Function to clear data and error state
100
+ const clearData = useCallback(() => {
101
+ setData(null);
102
+ setError(null);
103
+ }, []);
104
+ // Auto-fetch on mount if enabled
105
+ useEffect(() => {
106
+ if (autoFetch && apiService) {
107
+ fetchGeoData();
108
+ }
109
+ }, [autoFetch, apiService, fetchGeoData]);
110
+ // Refetch on mount if enabled
111
+ useEffect(() => {
112
+ if (refetchOnMount && apiService) {
113
+ fetchGeoData();
114
+ }
115
+ }, [refetchOnMount, apiService, fetchGeoData]);
116
+ return {
117
+ data,
118
+ isLoading,
119
+ error,
120
+ fetchGeoData,
121
+ clearData,
122
+ isLocalhost: isLocalhost(data?.ip_address),
123
+ isValidIP: isValidIP(data?.ip_address),
124
+ };
125
+ }
@@ -63,7 +63,16 @@ export const useShippingRates = ({ onSuccess, checkout } = {}) => {
63
63
  },
64
64
  });
65
65
  if (isMountedRef.current) {
66
- setShippingRates(response.rates);
66
+ // Order rates: free ones first, then by ascending amount
67
+ setShippingRates(response.rates
68
+ .slice()
69
+ .sort((a, b) => {
70
+ if (a.isFree && !b.isFree)
71
+ return -1;
72
+ if (!a.isFree && b.isFree)
73
+ return 1;
74
+ return (a.amount ?? 0) - (b.amount ?? 0);
75
+ }));
67
76
  }
68
77
  }
69
78
  catch (err) {
@@ -8,6 +8,7 @@ export { useCurrency } from './hooks/useCurrency';
8
8
  export { useCustomer } from './hooks/useCustomer';
9
9
  export { useDiscounts } from './hooks/useDiscounts';
10
10
  export { useEnvironment } from './hooks/useEnvironment';
11
+ export { useGeoLocation } from './hooks/useGeoLocation';
11
12
  export { useGoogleAutocomplete } from './hooks/useGoogleAutocomplete';
12
13
  export { useLocale } from './hooks/useLocale';
13
14
  export { useLogin } from './hooks/useLogin';
@@ -25,6 +26,7 @@ export { clearPluginConfigCache, debugPluginConfig, getPluginConfig, useBasePath
25
26
  export type { PluginConfig } from './hooks/usePluginConfig';
26
27
  export { getAvailableLanguages, useCountryOptions, useISOData, useRegionOptions } from './hooks/useISOData';
27
28
  export type { ISOCountry, ISORegion, UseISODataResult } from './hooks/useISOData';
29
+ export type { GeoLocationData, UseGeoLocationOptions, UseGeoLocationReturn } from './hooks/useGeoLocation';
28
30
  export type { ExtractedAddress, GoogleAddressComponent, GooglePlaceDetails, GooglePrediction, UseGoogleAutocompleteOptions, UseGoogleAutocompleteResult } from './hooks/useGoogleAutocomplete';
29
31
  export { useOrder } from './hooks/useOrder';
30
32
  export type { UseOrderOptions, UseOrderResult } from './hooks/useOrder';
@@ -11,6 +11,7 @@ export { useCurrency } from './hooks/useCurrency';
11
11
  export { useCustomer } from './hooks/useCustomer';
12
12
  export { useDiscounts } from './hooks/useDiscounts';
13
13
  export { useEnvironment } from './hooks/useEnvironment';
14
+ export { useGeoLocation } from './hooks/useGeoLocation';
14
15
  export { useGoogleAutocomplete } from './hooks/useGoogleAutocomplete';
15
16
  export { useLocale } from './hooks/useLocale';
16
17
  export { useLogin } from './hooks/useLogin';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tagadapay/plugin-sdk",
3
- "version": "2.4.9",
3
+ "version": "2.4.12",
4
4
  "description": "Modern React SDK for building Tagada Pay plugins",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",