@tagadapay/plugin-sdk 1.0.29 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +150 -18
- package/dist/data/iso3166.d.ts +30 -0
- package/dist/data/iso3166.js +102 -0
- package/dist/react/hooks/useAddressV2.d.ts +53 -0
- package/dist/react/hooks/useAddressV2.js +379 -0
- package/dist/react/hooks/useGoogleAutocomplete.d.ts +69 -0
- package/dist/react/hooks/useGoogleAutocomplete.js +219 -0
- package/dist/react/hooks/useISOData.d.ts +41 -0
- package/dist/react/hooks/useISOData.js +127 -0
- package/dist/react/hooks/useLogin.d.ts +20 -0
- package/dist/react/hooks/useLogin.js +75 -0
- package/dist/react/hooks/usePayment.d.ts +43 -0
- package/dist/react/hooks/usePayment.js +16 -2
- package/dist/react/hooks/usePluginConfig.d.ts +53 -0
- package/dist/react/hooks/usePluginConfig.js +190 -0
- package/dist/react/index.d.ts +7 -0
- package/dist/react/index.js +7 -0
- package/dist/react/providers/TagadaProvider.d.ts +5 -1
- package/dist/react/providers/TagadaProvider.js +48 -2
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -6,16 +6,110 @@ A comprehensive SDK for building checkout plugins on the TagadaPay platform. Cre
|
|
|
6
6
|
|
|
7
7
|
### Core APIs
|
|
8
8
|
|
|
9
|
-
- **[useCheckout](./README-useCheckout.md)** - Checkout state management and flow control
|
|
10
|
-
- **[setCheckoutInfo](./README-setCheckoutInfo.md)** - Customer information and validation
|
|
11
|
-
- **[useOffers](./README-useOffers.md)** - Dynamic pricing and promotional offers
|
|
12
|
-
- **[Money utilities](./README-money.md)** - Currency formatting and calculations
|
|
13
|
-
- **[URL utilities](./README-urlUtils.md)** - Navigation and routing helpers
|
|
9
|
+
- **[useCheckout](./docs/README-useCheckout.md)** - Checkout state management and flow control
|
|
10
|
+
- **[setCheckoutInfo](./docs/README-setCheckoutInfo.md)** - Customer information and validation
|
|
11
|
+
- **[useOffers](./docs/README-useOffers.md)** - Dynamic pricing and promotional offers
|
|
12
|
+
- **[Money utilities](./docs/README-money.md)** - Currency formatting and calculations
|
|
13
|
+
- **[URL utilities](./docs/README-urlUtils.md)** - Navigation and routing helpers
|
|
14
|
+
|
|
15
|
+
### Plugin Development
|
|
16
|
+
|
|
17
|
+
- **[Plugin Configuration](./docs/PLUGIN_CONFIG.md)** - How to access store context, config, and branding
|
|
18
|
+
- **[Google Autocomplete](./docs/README-google-autocomplete.md)** - Address autocomplete with Google Places API
|
|
19
|
+
- **[ISO Data](./docs/README-iso-data.md)** - Country and region data with Google integration
|
|
14
20
|
|
|
15
21
|
### Examples
|
|
16
22
|
|
|
17
23
|
- **[Vite Checkout Demo](../checkout-vite)** - Complete checkout implementation
|
|
18
24
|
|
|
25
|
+
## 🏗️ Building a Plugin
|
|
26
|
+
|
|
27
|
+
### Plugin Structure
|
|
28
|
+
|
|
29
|
+
Every TagadaPay plugin follows this simple structure:
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
my-plugin/
|
|
33
|
+
├── plugin.manifest.json # Plugin metadata & routing
|
|
34
|
+
├── .local.json # Local dev config (auto-injected in production)
|
|
35
|
+
├── config/ # Optional deployment configs
|
|
36
|
+
│ ├── theme-green.json # Config variant A
|
|
37
|
+
│ └── theme-blue.json # Config variant B
|
|
38
|
+
├── src/
|
|
39
|
+
│ └── App.tsx # Your plugin code
|
|
40
|
+
└── dist/ # Built plugin files
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Configuration Flow
|
|
44
|
+
|
|
45
|
+
```mermaid
|
|
46
|
+
graph TD
|
|
47
|
+
A[🛠️ Local Development] --> B[.local.json]
|
|
48
|
+
A --> C[config/*.json]
|
|
49
|
+
B --> D[usePluginConfig()]
|
|
50
|
+
C --> D
|
|
51
|
+
|
|
52
|
+
E[🚀 Production] --> F[Platform Injection]
|
|
53
|
+
F --> G[HTTP Headers & Meta Tags]
|
|
54
|
+
G --> D
|
|
55
|
+
|
|
56
|
+
D --> H[Your Plugin Component]
|
|
57
|
+
|
|
58
|
+
style A fill:#e1f5fe
|
|
59
|
+
style E fill:#f3e5f5
|
|
60
|
+
style D fill:#fff3e0
|
|
61
|
+
style H fill:#e8f5e8
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Essential Files
|
|
65
|
+
|
|
66
|
+
#### 1. **`plugin.manifest.json`** - Plugin Metadata
|
|
67
|
+
|
|
68
|
+
```json
|
|
69
|
+
{
|
|
70
|
+
"pluginId": "my-awesome-plugin",
|
|
71
|
+
"name": "My Awesome Plugin",
|
|
72
|
+
"version": "1.0.0",
|
|
73
|
+
"mode": "direct-mode",
|
|
74
|
+
"router": {
|
|
75
|
+
"basePath": "/",
|
|
76
|
+
"matcher": ".*",
|
|
77
|
+
"excluder": "/checkout"
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
#### 2. **`.local.json`** - Local Development Context
|
|
83
|
+
|
|
84
|
+
```json
|
|
85
|
+
{
|
|
86
|
+
"storeId": "store_abc123",
|
|
87
|
+
"accountId": "acc_xyz789",
|
|
88
|
+
"basePath": "/"
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
> ⚠️ **Auto-managed**: This file is only for local dev. In production, the platform injects this data automatically.
|
|
93
|
+
|
|
94
|
+
#### 3. **`config/my-theme.json`** - Optional Deployment Config
|
|
95
|
+
|
|
96
|
+
```json
|
|
97
|
+
{
|
|
98
|
+
"configName": "green-theme",
|
|
99
|
+
"branding": {
|
|
100
|
+
"primaryColor": "#059669",
|
|
101
|
+
"companyName": "My Store",
|
|
102
|
+
"logoUrl": "https://example.com/logo.png"
|
|
103
|
+
},
|
|
104
|
+
"features": {
|
|
105
|
+
"enableChat": true,
|
|
106
|
+
"maxItems": 10
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
> 📝 **Note**: Config can contain any keys you need - the SDK doesn't enforce a specific structure.
|
|
112
|
+
|
|
19
113
|
## 🚀 Quick Start
|
|
20
114
|
|
|
21
115
|
### Installation
|
|
@@ -24,27 +118,65 @@ A comprehensive SDK for building checkout plugins on the TagadaPay platform. Cre
|
|
|
24
118
|
npm install @tagadapay/plugin-sdk
|
|
25
119
|
```
|
|
26
120
|
|
|
27
|
-
### Basic
|
|
121
|
+
### Basic Plugin Setup
|
|
28
122
|
|
|
29
|
-
```
|
|
30
|
-
import
|
|
123
|
+
```tsx
|
|
124
|
+
import React from 'react';
|
|
125
|
+
import {
|
|
126
|
+
TagadaProvider,
|
|
127
|
+
usePluginConfig,
|
|
128
|
+
useGoogleAutocomplete,
|
|
129
|
+
useISOData
|
|
130
|
+
} from '@tagadapay/plugin-sdk/react';
|
|
131
|
+
|
|
132
|
+
function MyPlugin() {
|
|
133
|
+
const { storeId, accountId, basePath, config, loading } = usePluginConfig();
|
|
31
134
|
|
|
32
|
-
|
|
33
|
-
const {
|
|
135
|
+
// Optional: Add address autocomplete
|
|
136
|
+
const { searchPlaces, predictions } = useGoogleAutocomplete({
|
|
137
|
+
apiKey: config?.googleMapsApiKey || 'YOUR_API_KEY'
|
|
138
|
+
});
|
|
34
139
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
});
|
|
40
|
-
};
|
|
140
|
+
// Optional: Add country/region data
|
|
141
|
+
const { countries } = useISOData('en');
|
|
142
|
+
|
|
143
|
+
if (loading) return <div>Loading...</div>;
|
|
41
144
|
|
|
42
145
|
return (
|
|
43
|
-
<div>
|
|
44
|
-
|
|
146
|
+
<div style={{ '--primary': config?.branding?.primaryColor }}>
|
|
147
|
+
<h1>Welcome to {config?.branding?.companyName}</h1>
|
|
148
|
+
<p>Store: {storeId}</p>
|
|
149
|
+
<p>Base Path: {basePath}</p>
|
|
150
|
+
<p>Available Countries: {Object.keys(countries).length}</p>
|
|
45
151
|
</div>
|
|
46
152
|
);
|
|
47
153
|
}
|
|
154
|
+
|
|
155
|
+
// Wrap your plugin with TagadaProvider
|
|
156
|
+
function App() {
|
|
157
|
+
return (
|
|
158
|
+
<TagadaProvider>
|
|
159
|
+
<MyPlugin />
|
|
160
|
+
</TagadaProvider>
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export default App;
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### Development vs Production
|
|
168
|
+
|
|
169
|
+
| Environment | Store/Account ID | Deployment Config | How it Works |
|
|
170
|
+
| -------------- | ---------------- | ----------------- | ------------------ |
|
|
171
|
+
| **Local Dev** | `.local.json` | `config/*.json` | Files on disk |
|
|
172
|
+
| **Production** | HTTP Headers | Meta Tags | Platform injection |
|
|
173
|
+
|
|
174
|
+
```tsx
|
|
175
|
+
// ✅ ALWAYS use hooks - works in both environments
|
|
176
|
+
const { storeId, accountId, basePath, config } = usePluginConfig();
|
|
177
|
+
|
|
178
|
+
// ❌ NEVER access directly
|
|
179
|
+
// const config = window.__PLUGIN_CONFIG__; // Doesn't exist!
|
|
48
180
|
```
|
|
49
181
|
|
|
50
182
|
## 🎯 Key Features
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export interface Country {
|
|
2
|
+
code: string;
|
|
3
|
+
name: string;
|
|
4
|
+
iso3?: string;
|
|
5
|
+
numeric?: number;
|
|
6
|
+
uniqueKey?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface State {
|
|
9
|
+
code: string;
|
|
10
|
+
name: string;
|
|
11
|
+
countryCode: string;
|
|
12
|
+
uniqueKey?: string;
|
|
13
|
+
}
|
|
14
|
+
export declare const getCountries: () => Country[];
|
|
15
|
+
export declare const getAllStates: () => State[];
|
|
16
|
+
export declare const getStatesForCountry: (countryCode: string) => State[];
|
|
17
|
+
export declare const findCountryByName: (countryName: string) => Country | null;
|
|
18
|
+
export declare const findRegionByCode: (regionCode: string) => State | null;
|
|
19
|
+
export declare const isValidCountryCode: (countryCode: string) => boolean;
|
|
20
|
+
export declare const isValidStateCode: (countryCode: string, stateCode: string) => boolean;
|
|
21
|
+
export declare const getCountryWithRegions: (countryCode: string) => {
|
|
22
|
+
country: {
|
|
23
|
+
code: any;
|
|
24
|
+
name: any;
|
|
25
|
+
iso3: any;
|
|
26
|
+
numeric: any;
|
|
27
|
+
uniqueKey: string;
|
|
28
|
+
};
|
|
29
|
+
regions: State[];
|
|
30
|
+
} | null;
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
// Import the ISO3166 library API functions
|
|
2
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
3
|
+
// @ts-ignore - iso3166-2-db doesn't have TypeScript definitions
|
|
4
|
+
import { getDataSet, reduce } from 'iso3166-2-db';
|
|
5
|
+
// Get the full dataset with default English language
|
|
6
|
+
const worldDatabase = reduce(getDataSet(), 'en');
|
|
7
|
+
// Transform the ISO3166 data into our expected format
|
|
8
|
+
export const getCountries = () => {
|
|
9
|
+
const countries = [];
|
|
10
|
+
Object.keys(worldDatabase).forEach((countryCode) => {
|
|
11
|
+
const countryData = worldDatabase[countryCode];
|
|
12
|
+
countries.push({
|
|
13
|
+
code: countryData.iso, // iso3166-1 alpha-2 code
|
|
14
|
+
name: countryData.name,
|
|
15
|
+
iso3: countryData.iso3, // iso3166-1 alpha-3 code
|
|
16
|
+
numeric: countryData.numeric,
|
|
17
|
+
uniqueKey: `country-${countryData.iso}`,
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
// Sort countries alphabetically by name
|
|
21
|
+
return countries.sort((a, b) => a.name.localeCompare(b.name));
|
|
22
|
+
};
|
|
23
|
+
// Get all states/regions for all countries
|
|
24
|
+
export const getAllStates = () => {
|
|
25
|
+
const states = [];
|
|
26
|
+
Object.keys(worldDatabase).forEach((countryCode) => {
|
|
27
|
+
const countryData = worldDatabase[countryCode];
|
|
28
|
+
if (countryData.regions && Array.isArray(countryData.regions)) {
|
|
29
|
+
countryData.regions.forEach((region, index) => {
|
|
30
|
+
states.push({
|
|
31
|
+
code: region.iso, // iso3166-2 code (the part after the dash)
|
|
32
|
+
name: region.name,
|
|
33
|
+
countryCode: countryData.iso,
|
|
34
|
+
uniqueKey: `state-${countryData.iso}-${region.iso}-${index}`,
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
// Sort states alphabetically by name
|
|
40
|
+
return states.sort((a, b) => a.name.localeCompare(b.name));
|
|
41
|
+
};
|
|
42
|
+
// Get states for a specific country
|
|
43
|
+
export const getStatesForCountry = (countryCode) => {
|
|
44
|
+
const countryData = worldDatabase[countryCode];
|
|
45
|
+
if (!countryData?.regions || !Array.isArray(countryData.regions)) {
|
|
46
|
+
return [];
|
|
47
|
+
}
|
|
48
|
+
return countryData.regions
|
|
49
|
+
.map((region, index) => ({
|
|
50
|
+
code: region.iso,
|
|
51
|
+
name: region.name,
|
|
52
|
+
countryCode: countryData.iso,
|
|
53
|
+
uniqueKey: `state-${countryData.iso}-${region.iso}-${index}`,
|
|
54
|
+
}))
|
|
55
|
+
.sort((a, b) => a.name.localeCompare(b.name));
|
|
56
|
+
};
|
|
57
|
+
// Find country by name (fuzzy search)
|
|
58
|
+
export const findCountryByName = (countryName) => {
|
|
59
|
+
const countries = getCountries();
|
|
60
|
+
const normalizedSearchName = countryName.toLowerCase().trim();
|
|
61
|
+
// Exact match first
|
|
62
|
+
const exactMatch = countries.find((country) => country.name.toLowerCase() === normalizedSearchName);
|
|
63
|
+
if (exactMatch)
|
|
64
|
+
return exactMatch;
|
|
65
|
+
// Partial match
|
|
66
|
+
const partialMatch = countries.find((country) => country.name.toLowerCase().includes(normalizedSearchName) ||
|
|
67
|
+
normalizedSearchName.includes(country.name.toLowerCase()));
|
|
68
|
+
return partialMatch ?? null;
|
|
69
|
+
};
|
|
70
|
+
// Find region by ISO code (e.g., "US-CA" for California)
|
|
71
|
+
export const findRegionByCode = (regionCode) => {
|
|
72
|
+
const [countryCode, stateCode] = regionCode.split('-');
|
|
73
|
+
if (!countryCode || !stateCode)
|
|
74
|
+
return null;
|
|
75
|
+
const states = getStatesForCountry(countryCode);
|
|
76
|
+
return states.find((state) => state.code === stateCode) ?? null;
|
|
77
|
+
};
|
|
78
|
+
// Validate if a country code exists
|
|
79
|
+
export const isValidCountryCode = (countryCode) => {
|
|
80
|
+
return Object.prototype.hasOwnProperty.call(worldDatabase, countryCode);
|
|
81
|
+
};
|
|
82
|
+
// Validate if a state code exists for a given country
|
|
83
|
+
export const isValidStateCode = (countryCode, stateCode) => {
|
|
84
|
+
const states = getStatesForCountry(countryCode);
|
|
85
|
+
return states.some((state) => state.code === stateCode);
|
|
86
|
+
};
|
|
87
|
+
// Get country info including regions
|
|
88
|
+
export const getCountryWithRegions = (countryCode) => {
|
|
89
|
+
const countryData = worldDatabase[countryCode];
|
|
90
|
+
if (!countryData)
|
|
91
|
+
return null;
|
|
92
|
+
return {
|
|
93
|
+
country: {
|
|
94
|
+
code: countryData.iso,
|
|
95
|
+
name: countryData.name,
|
|
96
|
+
iso3: countryData.iso3,
|
|
97
|
+
numeric: countryData.numeric,
|
|
98
|
+
uniqueKey: `country-${countryData.iso}`,
|
|
99
|
+
},
|
|
100
|
+
regions: getStatesForCountry(countryCode),
|
|
101
|
+
};
|
|
102
|
+
};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { type Country as ISO3166Country, type State as ISO3166State } from '../../data/iso3166';
|
|
2
|
+
export type Country = ISO3166Country;
|
|
3
|
+
export type State = ISO3166State;
|
|
4
|
+
export interface AddressField {
|
|
5
|
+
value: string;
|
|
6
|
+
isValid: boolean;
|
|
7
|
+
error?: string;
|
|
8
|
+
touched?: boolean;
|
|
9
|
+
}
|
|
10
|
+
export interface AddressData {
|
|
11
|
+
firstName: string;
|
|
12
|
+
lastName: string;
|
|
13
|
+
email: string;
|
|
14
|
+
phone: string;
|
|
15
|
+
country: string;
|
|
16
|
+
address1: string;
|
|
17
|
+
address2: string;
|
|
18
|
+
city: string;
|
|
19
|
+
state: string;
|
|
20
|
+
postal: string;
|
|
21
|
+
}
|
|
22
|
+
export interface UseAddressV2Config {
|
|
23
|
+
autoValidate?: boolean;
|
|
24
|
+
enableGooglePlaces?: boolean;
|
|
25
|
+
googlePlacesApiKey?: string;
|
|
26
|
+
countryRestrictions?: string[];
|
|
27
|
+
onFieldsChange?: (data: AddressData) => void;
|
|
28
|
+
debounceConfig?: {
|
|
29
|
+
autoSaveDelay?: number;
|
|
30
|
+
enabled?: boolean;
|
|
31
|
+
};
|
|
32
|
+
initialValues?: Partial<AddressData>;
|
|
33
|
+
}
|
|
34
|
+
export interface UseAddressV2Return {
|
|
35
|
+
fields: Record<keyof AddressData, AddressField>;
|
|
36
|
+
setValue: (field: keyof AddressData, value: string) => void;
|
|
37
|
+
setValues: (values: Partial<AddressData>) => void;
|
|
38
|
+
getValue: (field: keyof AddressData) => string;
|
|
39
|
+
getValues: () => AddressData;
|
|
40
|
+
validateField: (field: keyof AddressData) => boolean;
|
|
41
|
+
validateAll: () => boolean;
|
|
42
|
+
isValid: boolean;
|
|
43
|
+
reset: () => void;
|
|
44
|
+
countries: Country[];
|
|
45
|
+
states: State[];
|
|
46
|
+
getStatesForCountry: (countryCode: string) => State[];
|
|
47
|
+
addressRef: React.RefObject<HTMLInputElement | null>;
|
|
48
|
+
addressInputValue: string;
|
|
49
|
+
setAddressInputValue: (value: string) => void;
|
|
50
|
+
handleFieldChange: (field: keyof AddressData) => (value: string) => void;
|
|
51
|
+
handleFieldBlur: (field: keyof AddressData) => () => void;
|
|
52
|
+
}
|
|
53
|
+
export declare const useAddressV2: (config?: UseAddressV2Config) => UseAddressV2Return;
|