@neosianexus/super-tebex 1.1.6 → 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 +470 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +14 -3
- package/dist/index.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1 +1,471 @@
|
|
|
1
1
|
# @neosia-core/super-tebex
|
|
2
|
+
|
|
3
|
+
SDK Tebex permettant une intégration facile dans un environnement React/Next.js. Cette bibliothèque fournit des hooks React et des stores Zustand pour gérer facilement les catégories, paniers et la création de commandes Tebex.
|
|
4
|
+
|
|
5
|
+
## 📦 Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @neosia-core/super-tebex
|
|
9
|
+
# ou
|
|
10
|
+
yarn add @neosia-core/super-tebex
|
|
11
|
+
# ou
|
|
12
|
+
pnpm add @neosia-core/super-tebex
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
### Peer Dependencies
|
|
16
|
+
|
|
17
|
+
Cette bibliothèque nécessite les dépendances suivantes :
|
|
18
|
+
|
|
19
|
+
- `react` ^18.3.1
|
|
20
|
+
- `react-dom` ^18.3.1
|
|
21
|
+
- `zustand` ^5.0.6
|
|
22
|
+
- `sonner` ^2.0.6
|
|
23
|
+
- `tebex_headless` ^1.15.1
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npm install zustand sonner tebex_headless
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## 🚀 Initialisation dans Next.js
|
|
30
|
+
|
|
31
|
+
### 1. Configuration initiale
|
|
32
|
+
|
|
33
|
+
Créez un fichier de configuration (ex: `lib/tebex.ts`) :
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
import { initTebex, initShopUrls } from '@neosia-core/super-tebex';
|
|
37
|
+
|
|
38
|
+
// Initialiser Tebex avec votre clé publique
|
|
39
|
+
export function initializeTebex() {
|
|
40
|
+
const publicKey = process.env.NEXT_PUBLIC_TEBEX_PUBLIC_KEY;
|
|
41
|
+
|
|
42
|
+
if (!publicKey) {
|
|
43
|
+
throw new Error('NEXT_PUBLIC_TEBEX_PUBLIC_KEY is not defined');
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Initialiser l'instance Tebex
|
|
47
|
+
initTebex(publicKey);
|
|
48
|
+
|
|
49
|
+
// Initialiser les URLs du shop (utilisées pour la création de panier)
|
|
50
|
+
const baseUrl = process.env.NEXT_PUBLIC_BASE_URL || 'https://votre-domaine.com';
|
|
51
|
+
|
|
52
|
+
initShopUrls(baseUrl, {
|
|
53
|
+
complete: '/shop/complete-purchase', // Optionnel, défaut: /shop/complete-purchase
|
|
54
|
+
cancel: '/shop/cancel-purchase', // Optionnel, défaut: /shop/cancel-purchase
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### 2. Initialisation dans `app/layout.tsx` (App Router)
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
import { useEffect } from 'react';
|
|
63
|
+
import { Toaster } from 'sonner';
|
|
64
|
+
import { initializeTebex } from '@/lib/tebex';
|
|
65
|
+
|
|
66
|
+
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
|
67
|
+
useEffect(() => {
|
|
68
|
+
initializeTebex();
|
|
69
|
+
}, []);
|
|
70
|
+
|
|
71
|
+
return (
|
|
72
|
+
<html lang="fr">
|
|
73
|
+
<body>
|
|
74
|
+
{children}
|
|
75
|
+
<Toaster position="top-right" />
|
|
76
|
+
</body>
|
|
77
|
+
</html>
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### 3. Initialisation dans `pages/_app.tsx` (Pages Router)
|
|
83
|
+
|
|
84
|
+
```typescript
|
|
85
|
+
import type { AppProps } from 'next/app';
|
|
86
|
+
import { useEffect } from 'react';
|
|
87
|
+
import { Toaster } from 'sonner';
|
|
88
|
+
import { initializeTebex } from '@/lib/tebex';
|
|
89
|
+
|
|
90
|
+
export default function App({ Component, pageProps }: AppProps) {
|
|
91
|
+
useEffect(() => {
|
|
92
|
+
initializeTebex();
|
|
93
|
+
}, []);
|
|
94
|
+
|
|
95
|
+
return (
|
|
96
|
+
<>
|
|
97
|
+
<Component {...pageProps} />
|
|
98
|
+
<Toaster position="top-right" />
|
|
99
|
+
</>
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## 📚 Hooks disponibles
|
|
105
|
+
|
|
106
|
+
### `useBasket`
|
|
107
|
+
|
|
108
|
+
Hook principal pour gérer le panier d'achat.
|
|
109
|
+
|
|
110
|
+
```typescript
|
|
111
|
+
import { useBasket } from '@neosia-core/super-tebex';
|
|
112
|
+
|
|
113
|
+
function BasketComponent() {
|
|
114
|
+
// Le username peut venir du store global ou être passé directement
|
|
115
|
+
const username = useShopUserStore(s => s.username);
|
|
116
|
+
const { basket, loading, error, addPackageToBasket, removePackageFromBasket, refetch } = useBasket(username);
|
|
117
|
+
|
|
118
|
+
if (loading) {
|
|
119
|
+
return <div>Chargement du panier...</div>;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (error) {
|
|
123
|
+
return <div>Erreur: {error.message}</div>;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (!basket) {
|
|
127
|
+
return <div>Votre panier est vide</div>;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return (
|
|
131
|
+
<div>
|
|
132
|
+
<h2>Votre panier</h2>
|
|
133
|
+
<ul>
|
|
134
|
+
{basket.packages.map(pkg => (
|
|
135
|
+
<li key={pkg.id}>
|
|
136
|
+
{pkg.name} - Quantité: {pkg.in_basket.quantity}
|
|
137
|
+
<button onClick={() => removePackageFromBasket(pkg.id)}>
|
|
138
|
+
Supprimer
|
|
139
|
+
</button>
|
|
140
|
+
</li>
|
|
141
|
+
))}
|
|
142
|
+
</ul>
|
|
143
|
+
<button onClick={() => addPackageToBasket(123, 1)}>
|
|
144
|
+
Ajouter un article
|
|
145
|
+
</button>
|
|
146
|
+
</div>
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
#### API
|
|
152
|
+
|
|
153
|
+
```typescript
|
|
154
|
+
interface UseBasketResult {
|
|
155
|
+
basket: Basket | null; // Panier actuel
|
|
156
|
+
loading: boolean; // État de chargement
|
|
157
|
+
error: Error | null; // Erreur éventuelle
|
|
158
|
+
addPackageToBasket: (
|
|
159
|
+
packageId: number,
|
|
160
|
+
quantity?: number,
|
|
161
|
+
type?: PackageType,
|
|
162
|
+
variableData?: Record<string, string>
|
|
163
|
+
) => Promise<void>;
|
|
164
|
+
removePackageFromBasket: (packageId: number) => Promise<void>;
|
|
165
|
+
updateManualBasket: (basket: Basket | null) => void;
|
|
166
|
+
refetch: () => Promise<void>;
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### `useCategories`
|
|
171
|
+
|
|
172
|
+
Hook pour récupérer et gérer les catégories de produits.
|
|
173
|
+
|
|
174
|
+
```typescript
|
|
175
|
+
import { useCategories } from '@neosia-core/super-tebex';
|
|
176
|
+
|
|
177
|
+
function CategoriesComponent() {
|
|
178
|
+
const { categories, loading, error, getByName, refetch } = useCategories({
|
|
179
|
+
includePackages: true,
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
if (loading) {
|
|
183
|
+
return <div>Chargement des catégories...</div>;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
if (error) {
|
|
187
|
+
return <div>Erreur: {error.message}</div>;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
return (
|
|
191
|
+
<div>
|
|
192
|
+
<h2>Catégories</h2>
|
|
193
|
+
<button onClick={() => refetch()}>Actualiser</button>
|
|
194
|
+
<ul>
|
|
195
|
+
{categories?.map(category => (
|
|
196
|
+
<li key={category.id}>
|
|
197
|
+
<h3>{category.name}</h3>
|
|
198
|
+
<p>{category.description}</p>
|
|
199
|
+
</li>
|
|
200
|
+
))}
|
|
201
|
+
</ul>
|
|
202
|
+
</div>
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
#### API
|
|
208
|
+
|
|
209
|
+
```typescript
|
|
210
|
+
interface UseCategoriesResult {
|
|
211
|
+
categories: Category[] | null;
|
|
212
|
+
loading: boolean;
|
|
213
|
+
error: Error | null;
|
|
214
|
+
getByName: (name: string) => Category | undefined;
|
|
215
|
+
refetch: () => Promise<void>;
|
|
216
|
+
}
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
### `useCreateBasket`
|
|
220
|
+
|
|
221
|
+
Hook pour créer un nouveau panier (utilisé en interne par `useBasket`).
|
|
222
|
+
|
|
223
|
+
```typescript
|
|
224
|
+
import { useCreateBasket } from '@neosia-core/super-tebex';
|
|
225
|
+
|
|
226
|
+
function CreateBasketButton() {
|
|
227
|
+
const username = useShopUserStore(s => s.username);
|
|
228
|
+
const createBasket = useCreateBasket(username);
|
|
229
|
+
|
|
230
|
+
const handleCreate = async () => {
|
|
231
|
+
const basket = await createBasket();
|
|
232
|
+
if (basket) {
|
|
233
|
+
console.log('Panier créé:', basket.ident);
|
|
234
|
+
}
|
|
235
|
+
};
|
|
236
|
+
|
|
237
|
+
return <button onClick={handleCreate}>Créer un panier</button>;
|
|
238
|
+
}
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
## 🗄️ Stores Zustand
|
|
242
|
+
|
|
243
|
+
### `useShopUserStore`
|
|
244
|
+
|
|
245
|
+
Store pour gérer le nom d'utilisateur (persisté dans localStorage).
|
|
246
|
+
|
|
247
|
+
```typescript
|
|
248
|
+
import { useShopUserStore } from '@neosia-core/super-tebex';
|
|
249
|
+
|
|
250
|
+
function UserProfile() {
|
|
251
|
+
const username = useShopUserStore(s => s.username);
|
|
252
|
+
const setUsername = useShopUserStore(s => s.setUsername);
|
|
253
|
+
const clearUsername = useShopUserStore(s => s.clearUsername);
|
|
254
|
+
|
|
255
|
+
return (
|
|
256
|
+
<div>
|
|
257
|
+
{username ? (
|
|
258
|
+
<>
|
|
259
|
+
<p>Connecté en tant que: {username}</p>
|
|
260
|
+
<button onClick={clearUsername}>Déconnexion</button>
|
|
261
|
+
</>
|
|
262
|
+
) : (
|
|
263
|
+
<button onClick={() => setUsername('Player123')}>Se connecter</button>
|
|
264
|
+
)}
|
|
265
|
+
</div>
|
|
266
|
+
);
|
|
267
|
+
}
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
### `useShopBasketStore`
|
|
271
|
+
|
|
272
|
+
Store pour gérer l'identifiant du panier (persisté dans localStorage).
|
|
273
|
+
|
|
274
|
+
```typescript
|
|
275
|
+
import { useShopBasketStore } from '@neosia-core/super-tebex';
|
|
276
|
+
|
|
277
|
+
function BasketStatus() {
|
|
278
|
+
const basketIdent = useShopBasketStore(s => s.basketIdent);
|
|
279
|
+
const clearBasketIdent = useShopBasketStore(s => s.clearBasketIdent);
|
|
280
|
+
|
|
281
|
+
return (
|
|
282
|
+
<div>
|
|
283
|
+
{basketIdent ? (
|
|
284
|
+
<>
|
|
285
|
+
<p>Panier actif: {basketIdent}</p>
|
|
286
|
+
<button onClick={clearBasketIdent}>Vider le panier</button>
|
|
287
|
+
</>
|
|
288
|
+
) : (
|
|
289
|
+
<p>Aucun panier actif</p>
|
|
290
|
+
)}
|
|
291
|
+
</div>
|
|
292
|
+
);
|
|
293
|
+
}
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
### `useShopUiStore`
|
|
297
|
+
|
|
298
|
+
Store pour gérer les états d'interface utilisateur (loading, etc.).
|
|
299
|
+
|
|
300
|
+
```typescript
|
|
301
|
+
import { useShopUiStore } from '@neosia-core/super-tebex';
|
|
302
|
+
|
|
303
|
+
function LoadingIndicator() {
|
|
304
|
+
const isGlobalLoading = useShopUiStore(s => s.isGlobalLoading);
|
|
305
|
+
const isCreatingBasket = useShopUiStore(s => s.isCreatingBasket);
|
|
306
|
+
|
|
307
|
+
if (isGlobalLoading || isCreatingBasket) {
|
|
308
|
+
return <div className="spinner">Chargement...</div>;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
return null;
|
|
312
|
+
}
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
## 💡 Exemples complets
|
|
316
|
+
|
|
317
|
+
### Exemple : Page de boutique complète
|
|
318
|
+
|
|
319
|
+
```typescript
|
|
320
|
+
'use client';
|
|
321
|
+
|
|
322
|
+
import { useCategories, useBasket, useShopUserStore } from '@neosia-core/super-tebex';
|
|
323
|
+
|
|
324
|
+
export default function ShopPage() {
|
|
325
|
+
const username = useShopUserStore(s => s.username);
|
|
326
|
+
const { categories, loading: categoriesLoading } = useCategories({ includePackages: true });
|
|
327
|
+
const { basket, loading: basketLoading, addPackageToBasket, removePackageFromBasket } = useBasket(username);
|
|
328
|
+
|
|
329
|
+
if (categoriesLoading || basketLoading) {
|
|
330
|
+
return <div>Chargement...</div>;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
return (
|
|
334
|
+
<div className="shop-container">
|
|
335
|
+
<aside>
|
|
336
|
+
<h2>Panier</h2>
|
|
337
|
+
{basket ? (
|
|
338
|
+
<ul>
|
|
339
|
+
{basket.packages.map(pkg => (
|
|
340
|
+
<li key={pkg.id}>
|
|
341
|
+
{pkg.name} x{pkg.in_basket.quantity}
|
|
342
|
+
<button onClick={() => removePackageFromBasket(pkg.id)}>Retirer</button>
|
|
343
|
+
</li>
|
|
344
|
+
))}
|
|
345
|
+
</ul>
|
|
346
|
+
) : (
|
|
347
|
+
<p>Panier vide</p>
|
|
348
|
+
)}
|
|
349
|
+
</aside>
|
|
350
|
+
|
|
351
|
+
<main>
|
|
352
|
+
<h1>Boutique</h1>
|
|
353
|
+
{categories?.map(category => (
|
|
354
|
+
<section key={category.id}>
|
|
355
|
+
<h2>{category.name}</h2>
|
|
356
|
+
{category.packages?.map(pkg => (
|
|
357
|
+
<div key={pkg.id} className="product-card">
|
|
358
|
+
<h3>{pkg.name}</h3>
|
|
359
|
+
<p>{pkg.description}</p>
|
|
360
|
+
<p className="price">{pkg.price.display}</p>
|
|
361
|
+
<button
|
|
362
|
+
onClick={() => addPackageToBasket(pkg.id, 1)}
|
|
363
|
+
disabled={!username}
|
|
364
|
+
>
|
|
365
|
+
Ajouter au panier
|
|
366
|
+
</button>
|
|
367
|
+
</div>
|
|
368
|
+
))}
|
|
369
|
+
</section>
|
|
370
|
+
))}
|
|
371
|
+
</main>
|
|
372
|
+
</div>
|
|
373
|
+
);
|
|
374
|
+
}
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
### Exemple : Composant de connexion avec gestion d'utilisateur
|
|
378
|
+
|
|
379
|
+
```typescript
|
|
380
|
+
'use client';
|
|
381
|
+
|
|
382
|
+
import { useState } from 'react';
|
|
383
|
+
import { useShopUserStore, useBasket } from '@neosia-core/super-tebex';
|
|
384
|
+
|
|
385
|
+
export default function LoginForm() {
|
|
386
|
+
const [input, setInput] = useState('');
|
|
387
|
+
const username = useShopUserStore(s => s.username);
|
|
388
|
+
const setUsername = useShopUserStore(s => s.setUsername);
|
|
389
|
+
const clearUsername = useShopUserStore(s => s.clearUsername);
|
|
390
|
+
const { basket, refetch } = useBasket(username);
|
|
391
|
+
|
|
392
|
+
const handleLogin = () => {
|
|
393
|
+
if (input.trim()) {
|
|
394
|
+
setUsername(input.trim());
|
|
395
|
+
// Recharger le panier après connexion
|
|
396
|
+
setTimeout(() => refetch(), 100);
|
|
397
|
+
}
|
|
398
|
+
};
|
|
399
|
+
|
|
400
|
+
const handleLogout = () => {
|
|
401
|
+
clearUsername();
|
|
402
|
+
setInput('');
|
|
403
|
+
};
|
|
404
|
+
|
|
405
|
+
if (username) {
|
|
406
|
+
return (
|
|
407
|
+
<div>
|
|
408
|
+
<p>Connecté: {username}</p>
|
|
409
|
+
{basket && <p>Articles dans le panier: {basket.packages.length}</p>}
|
|
410
|
+
<button onClick={handleLogout}>Déconnexion</button>
|
|
411
|
+
</div>
|
|
412
|
+
);
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
return (
|
|
416
|
+
<div>
|
|
417
|
+
<input
|
|
418
|
+
type="text"
|
|
419
|
+
value={input}
|
|
420
|
+
onChange={(e) => setInput(e.target.value)}
|
|
421
|
+
placeholder="Nom d'utilisateur"
|
|
422
|
+
/>
|
|
423
|
+
<button onClick={handleLogin}>Se connecter</button>
|
|
424
|
+
</div>
|
|
425
|
+
);
|
|
426
|
+
}
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
## 🔔 Notifications (Toasts)
|
|
430
|
+
|
|
431
|
+
La bibliothèque utilise `sonner` pour afficher des notifications. Assurez-vous d'avoir le composant `<Toaster />` dans votre application (voir section Initialisation).
|
|
432
|
+
|
|
433
|
+
Les notifications sont automatiquement affichées pour :
|
|
434
|
+
- Ajout/suppression d'articles au panier
|
|
435
|
+
- Erreurs lors de la création du panier
|
|
436
|
+
- Erreurs de connexion
|
|
437
|
+
|
|
438
|
+
## 📝 Types TypeScript
|
|
439
|
+
|
|
440
|
+
Tous les types sont exportés depuis la bibliothèque :
|
|
441
|
+
|
|
442
|
+
```typescript
|
|
443
|
+
import type { Basket, Category, Package, PackageType } from '@neosia-core/super-tebex';
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
## 🐛 Gestion des erreurs
|
|
447
|
+
|
|
448
|
+
Tous les hooks retournent un objet `error` que vous pouvez vérifier :
|
|
449
|
+
|
|
450
|
+
```typescript
|
|
451
|
+
const { basket, error, loading } = useBasket(username);
|
|
452
|
+
|
|
453
|
+
useEffect(() => {
|
|
454
|
+
if (error) {
|
|
455
|
+
console.error('Erreur panier:', error);
|
|
456
|
+
// Gérer l'erreur (afficher un message, logger, etc.)
|
|
457
|
+
}
|
|
458
|
+
}, [error]);
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
## 🔄 Persistance
|
|
462
|
+
|
|
463
|
+
Les stores `useShopUserStore` et `useShopBasketStore` sont automatiquement persistés dans le `localStorage`, permettant de conserver l'état entre les sessions.
|
|
464
|
+
|
|
465
|
+
## 📚 API Reference
|
|
466
|
+
|
|
467
|
+
Pour plus de détails sur les types et interfaces, consultez les définitions TypeScript dans `dist/index.d.ts`.
|
|
468
|
+
|
|
469
|
+
## 🤝 Contribution
|
|
470
|
+
|
|
471
|
+
Les contributions sont les bienvenues ! N'hésitez pas à ouvrir une issue ou une pull request.
|
package/dist/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var{defineProperty:
|
|
1
|
+
var{defineProperty:R,getOwnPropertyNames:ee,getOwnPropertyDescriptor:re}=Object,te=Object.prototype.hasOwnProperty;var W=new WeakMap,oe=(e)=>{var r=W.get(e),t;if(r)return r;if(r=R({},"__esModule",{value:!0}),e&&typeof e==="object"||typeof e==="function")ee(e).map((o)=>!te.call(r,o)&&R(r,o,{get:()=>e[o],enumerable:!(t=re(e,o))||t.enumerable}));return W.set(e,r),r};var se=(e,r)=>{for(var t in r)R(e,t,{get:r[t],enumerable:!0,configurable:!0,set:(o)=>r[t]=()=>o})};var de={};se(de,{useShopUserStore:()=>h,useShopUiStore:()=>d,useShopBasketStore:()=>C,useCreateBasket:()=>T,useCategories:()=>V,useBasket:()=>O,tebex:()=>k,shopUrls:()=>U,initTebex:()=>j,initShopUrls:()=>F,getTebex:()=>p,categoriesService:()=>G,basketService:()=>x});module.exports=oe(de);var U=null,ae=(e,r)=>{let t=r?.complete??"/shop/complete-purchase",o=r?.cancel??"/shop/cancel-purchase";U={completeUrl:new URL(t,e).toString(),cancelUrl:new URL(o,e).toString()}},F=ae;var K=require("tebex_headless"),k=null,ne=(e)=>{k=new K.TebexHeadless(e)},j=ne;var ie=()=>{if(!k)throw Error("Tebex client not initialized. Call initTebex(publicKey) first.");return k},p=ie;var b=require("react"),B=require("sonner");var le=async({username:e,completeUrl:r,cancelUrl:t,custom:o,completeAutoRedirect:i,ipAddress:m})=>{return(await p()).createMinecraftBasket(e,r,t,o,i,m)},ce=async(e)=>{return(await p()).getBasket(e)},me=async(e,r,t,o,i)=>{return(await p()).addPackageToBasket(e,r,t??1,o,i)},pe=async(e,r,t)=>{return(await p()).updateQuantity(e,r,t-1>=0?t-1:0)},fe={createBasket:le,getBasket:ce,addPackageToBasket:me,removePackageFromBasket:pe},x=fe;var q=require("zustand"),y=require("zustand/middleware"),ge=q.create()(y.subscribeWithSelector(y.persist((e)=>({basketIdent:null,setBasketIdent:(r)=>e({basketIdent:r}),clearBasketIdent:()=>e({basketIdent:null})}),{name:"shop-basket-store"}))),C=ge;var D=require("zustand"),J=require("zustand/middleware"),ue=D.create()(J.subscribeWithSelector((e)=>({isGlobalLoading:!1,setIsGlobalLoading:(r)=>e({isGlobalLoading:r}),isCreatingBasket:!1,setIsCreatingBasket:(r)=>e({isCreatingBasket:r})}))),d=ue;var M=require("zustand"),P=require("zustand/middleware"),xe=M.create()(P.subscribeWithSelector(P.persist((e)=>({username:"",setUsername:(r)=>e({username:r}),clearUsername:()=>e({username:""})}),{name:"shop-user-store"}))),h=xe;var N=require("react"),L=require("sonner");var Ce=async({includePackages:e,basketIdent:r,ipAddress:t})=>{return(await p()).getCategories(e,r,t)},Be={getCategories:Ce},G=Be;var be=async(e)=>{let{isCreatingBasket:r,setIsCreatingBasket:t,setBasketIdent:o,createBasket:i,username:m}=e;if(r)return null;let{completeUrl:s,cancelUrl:g}=he();try{t(!0);let c=await i({username:m,completeUrl:s,cancelUrl:g,completeAutoRedirect:!1,ipAddress:""});if(!c?.ident)return L.toast.error("Une erreur est survenue lors de la création du panier"),null;return o(c.ident),c}catch{return L.toast.error("Erreur lors de la création du panier. Contactez le support si le problème persiste."),null}finally{t(!1)}},Ue=(e)=>{let r=d((s)=>s.isCreatingBasket),t=d((s)=>s.setIsCreatingBasket),o=C((s)=>s.setBasketIdent),i=h((s)=>s.username);return N.useCallback(()=>be({isCreatingBasket:r,setIsCreatingBasket:t,setBasketIdent:o,createBasket:x.createBasket,username:e??i}),[r,t,o,e,i])},he=()=>{if(!U)throw Error("Shop URLs not initialized. Call initShopUrls(baseUrl, paths?: { complete?: string; cancel?: string }) first.");return{completeUrl:U.completeUrl,cancelUrl:U.cancelUrl}},T=Ue;var Se=(e)=>{let[r,t]=b.useState(null),[o,i]=b.useState(!1),[m,s]=b.useState(null),[g,c]=b.useState(!1),n=C((a)=>a.basketIdent),w=C((a)=>a.setBasketIdent),X=h((a)=>a.username),v=e??X,Y=T(v),A=C((a)=>a.clearBasketIdent),H=async(a)=>{i(!0),s(null);try{let l=await x.getBasket(a);if(l.complete){t(null),A(),s(null);return}t(l),w(l.ident),s(null)}catch(l){s(l),t(null),A()}finally{i(!1)}},Z=async(a,l,S,I)=>{if(g)return;try{if(c(!0),!v){B.toast.error("Vous devez vous connecter pour ajouter des articles à votre panier");return}let u=null;if(!n){if(u=(await Y())?.ident??null,!u){B.toast.error("Une erreur est survenue lors de la création du panier");return}w(u)}else u=n;if(!u){B.toast.error("Vous n'avez pas de panier. Si le problème persiste, veuillez vous rapprocher du support.");return}let z=x.addPackageToBasket(u,a,l,S,I);B.toast.promise(z,{loading:"Ajout de l'article dans votre panier...",success:"Article ajouté avec succès !",error:"Une erreur est survenue lors de l'ajout de l'article dans votre panier"});let Q=await z;t(Q),s(null)}catch(u){s(u)}finally{c(!1)}},_=async(a)=>{if(g)return;try{if(c(!0),!n){B.toast.error("Vous n'avez pas de panier. Si le problème persiste, veuillez vous rapprocher du support.");return}let l=x.removePackageFromBasket(n,a,r?.packages.find((S)=>S.id===a)?.in_basket.quantity??0);l.then((S)=>{t(S),s(null)}),B.toast.promise(l,{loading:"Suppression de l'article de votre panier...",success:"Article supprimé avec succès !",error:"Une erreur est survenue lors de la suppression de l'article de votre panier"})}catch(l){s(l)}finally{c(!1)}},$=async()=>{if(n)await H(n)},E=(a)=>{t(a)};return b.useEffect(()=>{if(!n)return;H(n)},[n]),{basket:r,loading:o,error:m,updateManualBasket:E,addPackageToBasket:Z,removePackageFromBasket:_,refetch:$}},O=Se;var f=require("react");var ke=(e)=>{let[r,t]=f.useState(null),[o,i]=f.useState(!0),[m,s]=f.useState(null),g=f.useCallback(async()=>{i(!0),s(null);try{let n=await G.getCategories(e);t(n)}catch(n){s(n),t(null)}finally{i(!1)}},[e]);f.useEffect(()=>{g()},[g]);let c=f.useCallback((n)=>r?.find((w)=>w.name.toLowerCase()===n.toLowerCase()),[r]);return{categories:r,loading:o,error:m,getByName:c,refetch:g}},V=ke;
|
package/dist/index.d.ts
CHANGED
|
@@ -2,7 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
import { Basket, Category, InBasket, Package, PackageType, TebexHeadless } from 'tebex_headless';
|
|
4
4
|
|
|
5
|
-
export
|
|
5
|
+
export interface GetShopUrlsResult {
|
|
6
|
+
completeUrl: string;
|
|
7
|
+
cancelUrl: string;
|
|
8
|
+
}
|
|
9
|
+
export declare const useCreateBasket: (username: string | null) => (() => Promise<Basket | null>);
|
|
10
|
+
export declare let shopUrls: GetShopUrlsResult | null;
|
|
11
|
+
export declare const initShopUrls: (baseUrl: string, paths?: {
|
|
12
|
+
complete?: string;
|
|
13
|
+
cancel?: string;
|
|
14
|
+
}) => void;
|
|
15
|
+
export declare let tebex: TebexHeadless | null;
|
|
16
|
+
export declare const initTebex: (publicKey: string) => void;
|
|
17
|
+
export declare const getTebex: () => TebexHeadless;
|
|
6
18
|
export interface UseBasketResult {
|
|
7
19
|
basket: Basket | null;
|
|
8
20
|
loading: boolean;
|
|
@@ -10,7 +22,7 @@ export interface UseBasketResult {
|
|
|
10
22
|
addPackageToBasket: (packageId: Package["id"], quantity?: InBasket["quantity"], type?: PackageType, variableData?: Record<string, string>) => Promise<void>;
|
|
11
23
|
removePackageFromBasket: (packageId: Package["id"]) => Promise<void>;
|
|
12
24
|
updateManualBasket: (basket: Basket | null) => void;
|
|
13
|
-
refetch: () => void
|
|
25
|
+
refetch: () => Promise<void>;
|
|
14
26
|
}
|
|
15
27
|
export declare const useBasket: (username: string | null) => UseBasketResult;
|
|
16
28
|
export interface CreateBasketProps {
|
|
@@ -39,7 +51,6 @@ export interface UseCategoriesResult {
|
|
|
39
51
|
refetch: () => Promise<void>;
|
|
40
52
|
}
|
|
41
53
|
export declare const useCategories: (options: GetCategories) => UseCategoriesResult;
|
|
42
|
-
export declare const useCreateBasket: (username: string | null) => (() => Promise<Basket | null>);
|
|
43
54
|
export declare const basketService: {
|
|
44
55
|
createBasket: ({ username, completeUrl, cancelUrl, custom, completeAutoRedirect, ipAddress, }: CreateBasketProps) => Promise<Basket>;
|
|
45
56
|
getBasket: (basketIdent: Basket["ident"]) => Promise<Basket>;
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{TebexHeadless as
|
|
1
|
+
var b=null,J=(e,r)=>{let t=r?.complete??"/shop/complete-purchase",s=r?.cancel??"/shop/cancel-purchase";b={completeUrl:new URL(t,e).toString(),cancelUrl:new URL(s,e).toString()}},M=J;import{TebexHeadless as N}from"tebex_headless";var S=null,O=(e)=>{S=new N(e)},V=O;var X=()=>{if(!S)throw Error("Tebex client not initialized. Call initTebex(publicKey) first.");return S},g=X;import{useEffect as xe,useState as d}from"react";import{toast as C}from"sonner";var Y=async({username:e,completeUrl:r,cancelUrl:t,custom:s,completeAutoRedirect:i,ipAddress:m})=>{return(await g()).createMinecraftBasket(e,r,t,s,i,m)},Z=async(e)=>{return(await g()).getBasket(e)},_=async(e,r,t,s,i)=>{return(await g()).addPackageToBasket(e,r,t??1,s,i)},$=async(e,r,t)=>{return(await g()).updateQuantity(e,r,t-1>=0?t-1:0)},E={createBasket:Y,getBasket:Z,addPackageToBasket:_,removePackageFromBasket:$},u=E;import{create as I}from"zustand";import{persist as Q,subscribeWithSelector as ee}from"zustand/middleware";var re=I()(ee(Q((e)=>({basketIdent:null,setBasketIdent:(r)=>e({basketIdent:r}),clearBasketIdent:()=>e({basketIdent:null})}),{name:"shop-basket-store"}))),x=re;import{create as te}from"zustand";import{subscribeWithSelector as oe}from"zustand/middleware";var se=te()(oe((e)=>({isGlobalLoading:!1,setIsGlobalLoading:(r)=>e({isGlobalLoading:r}),isCreatingBasket:!1,setIsCreatingBasket:(r)=>e({isCreatingBasket:r})}))),k=se;import{create as ae}from"zustand";import{persist as ne,subscribeWithSelector as ie}from"zustand/middleware";var le=ae()(ie(ne((e)=>({username:"",setUsername:(r)=>e({username:r}),clearUsername:()=>e({username:""})}),{name:"shop-user-store"}))),U=le;import{useCallback as pe}from"react";import{toast as v}from"sonner";var ce=async({includePackages:e,basketIdent:r,ipAddress:t})=>{return(await g()).getCategories(e,r,t)},me={getCategories:ce},w=me;var fe=async(e)=>{let{isCreatingBasket:r,setIsCreatingBasket:t,setBasketIdent:s,createBasket:i,username:m}=e;if(r)return null;let{completeUrl:o,cancelUrl:p}=ue();try{t(!0);let c=await i({username:m,completeUrl:o,cancelUrl:p,completeAutoRedirect:!1,ipAddress:""});if(!c?.ident)return v.error("Une erreur est survenue lors de la création du panier"),null;return s(c.ident),c}catch{return v.error("Erreur lors de la création du panier. Contactez le support si le problème persiste."),null}finally{t(!1)}},ge=(e)=>{let r=k((o)=>o.isCreatingBasket),t=k((o)=>o.setIsCreatingBasket),s=x((o)=>o.setBasketIdent),i=U((o)=>o.username);return pe(()=>fe({isCreatingBasket:r,setIsCreatingBasket:t,setBasketIdent:s,createBasket:u.createBasket,username:e??i}),[r,t,s,e,i])},ue=()=>{if(!b)throw Error("Shop URLs not initialized. Call initShopUrls(baseUrl, paths?: { complete?: string; cancel?: string }) first.");return{completeUrl:b.completeUrl,cancelUrl:b.cancelUrl}},y=ge;var Ce=(e)=>{let[r,t]=d(null),[s,i]=d(!1),[m,o]=d(null),[p,c]=d(!1),n=x((a)=>a.basketIdent),h=x((a)=>a.setBasketIdent),H=U((a)=>a.username),G=e??H,z=y(G),T=x((a)=>a.clearBasketIdent),R=async(a)=>{i(!0),o(null);try{let l=await u.getBasket(a);if(l.complete){t(null),T(),o(null);return}t(l),h(l.ident),o(null)}catch(l){o(l),t(null),T()}finally{i(!1)}},W=async(a,l,B,q)=>{if(p)return;try{if(c(!0),!G){C.error("Vous devez vous connecter pour ajouter des articles à votre panier");return}let f=null;if(!n){if(f=(await z())?.ident??null,!f){C.error("Une erreur est survenue lors de la création du panier");return}h(f)}else f=n;if(!f){C.error("Vous n'avez pas de panier. Si le problème persiste, veuillez vous rapprocher du support.");return}let L=u.addPackageToBasket(f,a,l,B,q);C.promise(L,{loading:"Ajout de l'article dans votre panier...",success:"Article ajouté avec succès !",error:"Une erreur est survenue lors de l'ajout de l'article dans votre panier"});let D=await L;t(D),o(null)}catch(f){o(f)}finally{c(!1)}},F=async(a)=>{if(p)return;try{if(c(!0),!n){C.error("Vous n'avez pas de panier. Si le problème persiste, veuillez vous rapprocher du support.");return}let l=u.removePackageFromBasket(n,a,r?.packages.find((B)=>B.id===a)?.in_basket.quantity??0);l.then((B)=>{t(B),o(null)}),C.promise(l,{loading:"Suppression de l'article de votre panier...",success:"Article supprimé avec succès !",error:"Une erreur est survenue lors de la suppression de l'article de votre panier"})}catch(l){o(l)}finally{c(!1)}},K=async()=>{if(n)await R(n)},j=(a)=>{t(a)};return xe(()=>{if(!n)return;R(n)},[n]),{basket:r,loading:s,error:m,updateManualBasket:j,addPackageToBasket:W,removePackageFromBasket:F,refetch:K}},Be=Ce;import{useCallback as A,useEffect as be,useState as P}from"react";var Ue=(e)=>{let[r,t]=P(null),[s,i]=P(!0),[m,o]=P(null),p=A(async()=>{i(!0),o(null);try{let n=await w.getCategories(e);t(n)}catch(n){o(n),t(null)}finally{i(!1)}},[e]);be(()=>{p()},[p]);let c=A((n)=>r?.find((h)=>h.name.toLowerCase()===n.toLowerCase()),[r]);return{categories:r,loading:s,error:m,getByName:c,refetch:p}},he=Ue;export{U as useShopUserStore,k as useShopUiStore,x as useShopBasketStore,y as useCreateBasket,he as useCategories,Be as useBasket,S as tebex,b as shopUrls,V as initTebex,M as initShopUrls,g as getTebex,w as categoriesService,u as basketService};
|