@neosianexus/super-tebex 1.1.6 → 2.0.0

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 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:E,getOwnPropertyNames:J,getOwnPropertyDescriptor:O}=Object,V=Object.prototype.hasOwnProperty;var v=new WeakMap,Z=(r)=>{var e=v.get(r),o;if(e)return e;if(e=E({},"__esModule",{value:!0}),r&&typeof r==="object"||typeof r==="function")J(r).map((t)=>!V.call(e,t)&&E(e,t,{get:()=>r[t],enumerable:!(o=O(r,t))||o.enumerable}));return v.set(r,e),e};var Q=(r,e)=>{for(var o in e)E(r,o,{get:e[o],enumerable:!0,configurable:!0,set:(t)=>e[o]=()=>t})};var ge={};Q(ge,{useShopUserStore:()=>C,useShopUiStore:()=>k,useShopBasketStore:()=>g,useCreateBasket:()=>G,useCategories:()=>$,useBasket:()=>Y,getTebex:()=>m,categoriesService:()=>w,basketService:()=>c});module.exports=Z(ge);var N=require("tebex_headless"),R=null,ee=async()=>{if(!R){let r=process.env.NEXT_PUBLIC_TEBEX_PUBLIC_KEY;if(!r)throw new Error("Missing NEXT_PUBLIC_TEBEX_PUBLIC_KEY env variable");R=new N.TebexHeadless(r)}return R},m=ee;var U=require("react"),P=require("sonner");var re=async({username:r,completeUrl:e,cancelUrl:o,custom:t,completeAutoRedirect:n,ipAddress:i})=>{return(await m()).createMinecraftBasket(r,e,o,t,n,i)},oe=async(r)=>{return(await m()).getBasket(r)},te=async(r,e,o,t,n)=>{return(await m()).addPackageToBasket(r,e,o??1,t,n)},se=async(r,e,o)=>{return(await m()).updateQuantity(r,e,o-1>=0?o-1:0)},ne={createBasket:re,getBasket:oe,addPackageToBasket:te,removePackageFromBasket:se},c=ne;var y=require("zustand"),h=require("zustand/middleware"),ie=y.create()(h.subscribeWithSelector(h.persist((r)=>({basketIdent:null,setBasketIdent:(e)=>r({basketIdent:e}),clearBasketIdent:()=>r({basketIdent:null})}),{name:"shop-basket-store"}))),g=ie;var I=require("zustand"),H=require("zustand/middleware"),le=I.create()(H.subscribeWithSelector((r)=>({isGlobalLoading:!1,setIsGlobalLoading:(e)=>r({isGlobalLoading:e}),isCreatingBasket:!1,setIsCreatingBasket:(e)=>r({isCreatingBasket:e})}))),k=le;var K=require("zustand"),L=require("zustand/middleware"),ae=K.create()(L.subscribeWithSelector(L.persist((r)=>({username:"",setUsername:(e)=>r({username:e}),clearUsername:()=>r({username:""})}),{name:"shop-user-store"}))),C=ae;var W=require("react"),X=require("sonner");var me=async({includePackages:r,basketIdent:e,ipAddress:o})=>{return(await m()).getCategories(r,e,o)},pe={getCategories:me},w=pe;var ce=async(r)=>{let{isCreatingBasket:e,setIsCreatingBasket:o,setBasketIdent:t,createBasket:n,username:i}=r;if(e)return null;let{completeUrl:s,cancelUrl:B}=Be();try{o(!0);let u=await n({username:i,completeUrl:s,cancelUrl:B,completeAutoRedirect:!1,ipAddress:""});if(!u?.ident)return X.toast.error("Une erreur est survenue lors de la création du panier"),null;return t(u.ident),u}catch{return X.toast.error("Erreur lors de la création du panier. Contactez le support si le problème persiste."),null}finally{o(!1)}},fe=(r)=>{let e=k((s)=>s.isCreatingBasket),o=k((s)=>s.setIsCreatingBasket),t=g((s)=>s.setBasketIdent),n=C((s)=>s.username);return W.useCallback(()=>ce({isCreatingBasket:e,setIsCreatingBasket:o,setBasketIdent:t,createBasket:c.createBasket,username:r??n}),[e,o,t,r,n])},Be=()=>{if(!process.env.NEXT_PUBLIC_APP_URL)throw new Error("NEXT_PUBLIC_APP_URL is not set");return{completeUrl:`${process.env.NEXT_PUBLIC_APP_URL}/shop/complete-purchase`,cancelUrl:`${process.env.NEXT_PUBLIC_APP_URL}/shop/cancel-purchase`}},G=fe;var ue=(r)=>{let e=g((l)=>l.basketIdent),o=g((l)=>l.setBasketIdent),t=C((l)=>l.username),[n,i]=U.useState(null),[s,B]=U.useState(!1),[u,p]=U.useState(null),[S,_]=U.useState(!1),z=G(r??t),T=async(l)=>{B(!0);try{let a=await c.getBasket(l);if(a.complete){i(null),o("");return}i(a),o(a.ident),p(null)}catch(a){p(a),i(null),o("")}finally{B(!1)}},F=async(l,a,b,j)=>{if(S)return;try{if(_(!0),!r&&!t){P.toast.error("Vous devez vous connecter pour ajouter des articles à votre panier");return}let x=null;if(!e){if(x=(await z())?.ident??null,!x){P.toast.error("Une erreur est survenue lors de la création du panier");return}o(x),await T(x)}else await T(e),x=e;if(!x){P.toast.error("Vous n'avez pas de panier. Si le problème persiste, veuillez vous rapprocher du support.");return}let q=c.addPackageToBasket(x,l,a,b,j)?.then((D)=>{i(D),A()});P.toast.promise(q,{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"})}finally{_(!1)}},M=async(l)=>{if(S)return;try{if(_(!0),!e){P.toast.error("Vous n'avez pas de panier. Si le problème persiste, veuillez vous rapprocher du support.");return}let a=c.removePackageFromBasket(e,l,n?.packages.find((b)=>b.id===l)?.in_basket.quantity??0)?.then((b)=>{i(b),A()});P.toast.promise(a,{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"})}finally{_(!1)}},A=()=>{if(e)T(e)},d=(l)=>{i(l)};return U.useEffect(()=>{if(!e)return;T(e)},[e]),{basket:n,loading:s,error:u,updateManualBasket:d,addPackageToBasket:F,removePackageFromBasket:M,refetch:A}},Y=ue;var f=require("react");var xe=(r)=>{let[e,o]=f.useState(null),[t,n]=f.useState(!0),[i,s]=f.useState(null),B=async()=>{n(!0),s(null);try{let p=await w.getCategories(r);o(p)}catch(p){s(p),o(null)}finally{n(!1)}};f.useEffect(()=>{B()},[]);let u=f.useCallback((p)=>e?.find((S)=>S.name.toLowerCase()===p.toLowerCase()),[e]);return{categories:e,loading:t,error:i,getByName:u,refetch:B}},$=xe;
1
+ var{defineProperty:T,getOwnPropertyNames:E,getOwnPropertyDescriptor:I}=Object,Q=Object.prototype.hasOwnProperty;var W=new WeakMap,ee=(r)=>{var e=W.get(r),t;if(e)return e;if(e=T({},"__esModule",{value:!0}),r&&typeof r==="object"||typeof r==="function")E(r).map((s)=>!Q.call(e,s)&&T(e,s,{get:()=>r[s],enumerable:!(t=I(r,s))||t.enumerable}));return W.set(r,e),e};var re=(r,e)=>{for(var t in e)T(r,t,{get:e[t],enumerable:!0,configurable:!0,set:(s)=>e[t]=()=>s})};var Ue={};re(Ue,{useShopUserStore:()=>U,useShopUiStore:()=>S,useShopBasketStore:()=>C,useCreateBasket:()=>G,useCategories:()=>M,useBasket:()=>J,getTebex:()=>p,categoriesService:()=>P,basketService:()=>x});module.exports=ee(Ue);var te=require("tebex_headless"),R=null;var oe=()=>{if(!R)throw Error("Tebex client not initialized. Call initTebex(publicKey) first.");return R},p=oe;var b=require("react"),B=require("sonner");var se=async({username:r,completeUrl:e,cancelUrl:t,custom:s,completeAutoRedirect:i,ipAddress:m})=>{return(await p()).createMinecraftBasket(r,e,t,s,i,m)},ae=async(r)=>{return(await p()).getBasket(r)},ne=async(r,e,t,s,i)=>{return(await p()).addPackageToBasket(r,e,t??1,s,i)},ie=async(r,e,t)=>{return(await p()).updateQuantity(r,e,t-1>=0?t-1:0)},le={createBasket:se,getBasket:ae,addPackageToBasket:ne,removePackageFromBasket:ie},x=le;var F=require("zustand"),d=require("zustand/middleware"),ce=F.create()(d.subscribeWithSelector(d.persist((r)=>({basketIdent:null,setBasketIdent:(e)=>r({basketIdent:e}),clearBasketIdent:()=>r({basketIdent:null})}),{name:"shop-basket-store"}))),C=ce;var K=require("zustand"),j=require("zustand/middleware"),me=K.create()(j.subscribeWithSelector((r)=>({isGlobalLoading:!1,setIsGlobalLoading:(e)=>r({isGlobalLoading:e}),isCreatingBasket:!1,setIsCreatingBasket:(e)=>r({isCreatingBasket:e})}))),S=me;var q=require("zustand"),w=require("zustand/middleware"),pe=q.create()(w.subscribeWithSelector(w.persist((r)=>({username:"",setUsername:(e)=>r({username:e}),clearUsername:()=>r({username:""})}),{name:"shop-user-store"}))),U=pe;var D=require("react"),L=require("sonner");var y=null;var fe=async({includePackages:r,basketIdent:e,ipAddress:t})=>{return(await p()).getCategories(r,e,t)},ge={getCategories:fe},P=ge;var ue=async(r)=>{let{isCreatingBasket:e,setIsCreatingBasket:t,setBasketIdent:s,createBasket:i,username:m}=r;if(e)return null;let{completeUrl:o,cancelUrl:g}=Ce();try{t(!0);let c=await i({username:m,completeUrl:o,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 s(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)}},xe=(r)=>{let e=S((o)=>o.isCreatingBasket),t=S((o)=>o.setIsCreatingBasket),s=C((o)=>o.setBasketIdent),i=U((o)=>o.username);return D.useCallback(()=>ue({isCreatingBasket:e,setIsCreatingBasket:t,setBasketIdent:s,createBasket:x.createBasket,username:r??i}),[e,t,s,r,i])},Ce=()=>{if(!y)throw Error("Shop URLs not initialized. Call initShopUrls(baseUrl, paths?: { complete?: string; cancel?: string }) first.");return{completeUrl:y.completeUrl,cancelUrl:y.cancelUrl}},G=xe;var Be=(r)=>{let[e,t]=b.useState(null),[s,i]=b.useState(!1),[m,o]=b.useState(null),[g,c]=b.useState(!1),n=C((a)=>a.basketIdent),k=C((a)=>a.setBasketIdent),N=U((a)=>a.username),v=r??N,O=G(v),A=C((a)=>a.clearBasketIdent),H=async(a)=>{i(!0),o(null);try{let l=await x.getBasket(a);if(l.complete){t(null),A(),o(null);return}t(l),k(l.ident),o(null)}catch(l){o(l),t(null),A()}finally{i(!1)}},V=async(a,l,h,_)=>{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 O())?.ident??null,!u){B.toast.error("Une erreur est survenue lors de la création du panier");return}k(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,h,_);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 $=await z;t($),o(null)}catch(u){o(u)}finally{c(!1)}},X=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,e?.packages.find((h)=>h.id===a)?.in_basket.quantity??0);l.then((h)=>{t(h),o(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){o(l)}finally{c(!1)}},Y=async()=>{if(n)await H(n)},Z=(a)=>{t(a)};return b.useEffect(()=>{if(!n)return;H(n)},[n]),{basket:e,loading:s,error:m,updateManualBasket:Z,addPackageToBasket:V,removePackageFromBasket:X,refetch:Y}},J=Be;var f=require("react");var be=(r)=>{let[e,t]=f.useState(null),[s,i]=f.useState(!0),[m,o]=f.useState(null),g=f.useCallback(async()=>{i(!0),o(null);try{let n=await P.getCategories(r);t(n)}catch(n){o(n),t(null)}finally{i(!1)}},[r]);f.useEffect(()=>{g()},[g]);let c=f.useCallback((n)=>e?.find((k)=>k.name.toLowerCase()===n.toLowerCase()),[e]);return{categories:e,loading:s,error:m,getByName:c,refetch:g}},M=be;
package/dist/index.d.ts CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  import { Basket, Category, InBasket, Package, PackageType, TebexHeadless } from 'tebex_headless';
4
4
 
5
- export declare const getTebex: () => Promise<TebexHeadless>;
5
+ export declare const getTebex: () => TebexHeadless;
6
6
  export interface UseBasketResult {
7
7
  basket: Basket | null;
8
8
  loading: boolean;
@@ -10,7 +10,7 @@ export interface UseBasketResult {
10
10
  addPackageToBasket: (packageId: Package["id"], quantity?: InBasket["quantity"], type?: PackageType, variableData?: Record<string, string>) => Promise<void>;
11
11
  removePackageFromBasket: (packageId: Package["id"]) => Promise<void>;
12
12
  updateManualBasket: (basket: Basket | null) => void;
13
- refetch: () => void;
13
+ refetch: () => Promise<void>;
14
14
  }
15
15
  export declare const useBasket: (username: string | null) => UseBasketResult;
16
16
  export interface CreateBasketProps {
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- import{TebexHeadless as H}from"tebex_headless";var h=null,K=async()=>{if(!h){let r=process.env.NEXT_PUBLIC_TEBEX_PUBLIC_KEY;if(!r)throw new Error("Missing NEXT_PUBLIC_TEBEX_PUBLIC_KEY env variable");h=new H(r)}return h},p=K;import{useEffect as le,useState as _}from"react";import{toast as g}from"sonner";var W=async({username:r,completeUrl:e,cancelUrl:o,custom:t,completeAutoRedirect:n,ipAddress:i})=>{return(await p()).createMinecraftBasket(r,e,o,t,n,i)},Y=async(r)=>{return(await p()).getBasket(r)},$=async(r,e,o,t,n)=>{return(await p()).addPackageToBasket(r,e,o??1,t,n)},z=async(r,e,o)=>{return(await p()).updateQuantity(r,e,o-1>=0?o-1:0)},F={createBasket:W,getBasket:Y,addPackageToBasket:$,removePackageFromBasket:z},u=F;import{create as M}from"zustand";import{persist as d,subscribeWithSelector as j}from"zustand/middleware";var q=M()(j(d((r)=>({basketIdent:null,setBasketIdent:(e)=>r({basketIdent:e}),clearBasketIdent:()=>r({basketIdent:null})}),{name:"shop-basket-store"}))),x=q;import{create as D}from"zustand";import{subscribeWithSelector as J}from"zustand/middleware";var O=D()(J((r)=>({isGlobalLoading:!1,setIsGlobalLoading:(e)=>r({isGlobalLoading:e}),isCreatingBasket:!1,setIsCreatingBasket:(e)=>r({isCreatingBasket:e})}))),S=O;import{create as V}from"zustand";import{persist as Z,subscribeWithSelector as Q}from"zustand/middleware";var ee=V()(Q(Z((r)=>({username:"",setUsername:(e)=>r({username:e}),clearUsername:()=>r({username:""})}),{name:"shop-user-store"}))),U=ee;import{useCallback as te}from"react";import{toast as A}from"sonner";var re=async({includePackages:r,basketIdent:e,ipAddress:o})=>{return(await p()).getCategories(r,e,o)},oe={getCategories:re},L=oe;var se=async(r)=>{let{isCreatingBasket:e,setIsCreatingBasket:o,setBasketIdent:t,createBasket:n,username:i}=r;if(e)return null;let{completeUrl:s,cancelUrl:c}=ie();try{o(!0);let f=await n({username:i,completeUrl:s,cancelUrl:c,completeAutoRedirect:!1,ipAddress:""});if(!f?.ident)return A.error("Une erreur est survenue lors de la création du panier"),null;return t(f.ident),f}catch{return A.error("Erreur lors de la création du panier. Contactez le support si le problème persiste."),null}finally{o(!1)}},ne=(r)=>{let e=S((s)=>s.isCreatingBasket),o=S((s)=>s.setIsCreatingBasket),t=x((s)=>s.setBasketIdent),n=U((s)=>s.username);return te(()=>se({isCreatingBasket:e,setIsCreatingBasket:o,setBasketIdent:t,createBasket:u.createBasket,username:r??n}),[e,o,t,r,n])},ie=()=>{if(!process.env.NEXT_PUBLIC_APP_URL)throw new Error("NEXT_PUBLIC_APP_URL is not set");return{completeUrl:`${process.env.NEXT_PUBLIC_APP_URL}/shop/complete-purchase`,cancelUrl:`${process.env.NEXT_PUBLIC_APP_URL}/shop/cancel-purchase`}},w=ne;var ae=(r)=>{let e=x((l)=>l.basketIdent),o=x((l)=>l.setBasketIdent),t=U((l)=>l.username),[n,i]=_(null),[s,c]=_(!1),[f,m]=_(null),[C,b]=_(!1),E=w(r??t),k=async(l)=>{c(!0);try{let a=await u.getBasket(l);if(a.complete){i(null),o("");return}i(a),o(a.ident),m(null)}catch(a){m(a),i(null),o("")}finally{c(!1)}},R=async(l,a,P,N)=>{if(C)return;try{if(b(!0),!r&&!t){g.error("Vous devez vous connecter pour ajouter des articles à votre panier");return}let B=null;if(!e){if(B=(await E())?.ident??null,!B){g.error("Une erreur est survenue lors de la création du panier");return}o(B),await k(B)}else await k(e),B=e;if(!B){g.error("Vous n'avez pas de panier. Si le problème persiste, veuillez vous rapprocher du support.");return}let y=u.addPackageToBasket(B,l,a,P,N)?.then((I)=>{i(I),T()});g.promise(y,{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"})}finally{b(!1)}},X=async(l)=>{if(C)return;try{if(b(!0),!e){g.error("Vous n'avez pas de panier. Si le problème persiste, veuillez vous rapprocher du support.");return}let a=u.removePackageFromBasket(e,l,n?.packages.find((P)=>P.id===l)?.in_basket.quantity??0)?.then((P)=>{i(P),T()});g.promise(a,{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"})}finally{b(!1)}},T=()=>{if(e)k(e)},v=(l)=>{i(l)};return le(()=>{if(!e)return;k(e)},[e]),{basket:n,loading:s,error:f,updateManualBasket:v,addPackageToBasket:R,removePackageFromBasket:X,refetch:T}},me=ae;import{useCallback as pe,useEffect as ce,useState as G}from"react";var fe=(r)=>{let[e,o]=G(null),[t,n]=G(!0),[i,s]=G(null),c=async()=>{n(!0),s(null);try{let m=await L.getCategories(r);o(m)}catch(m){s(m),o(null)}finally{n(!1)}};ce(()=>{c()},[]);let f=pe((m)=>e?.find((C)=>C.name.toLowerCase()===m.toLowerCase()),[e]);return{categories:e,loading:t,error:i,getByName:f,refetch:c}},Be=fe;export{U as useShopUserStore,S as useShopUiStore,x as useShopBasketStore,w as useCreateBasket,Be as useCategories,me as useBasket,p as getTebex,L as categoriesService,u as basketService};
1
+ import{TebexHeadless as Be}from"tebex_headless";var d=null;var J=()=>{if(!d)throw Error("Tebex client not initialized. Call initTebex(publicKey) first.");return d},g=J;import{useEffect as me,useState as k}from"react";import{toast as C}from"sonner";var M=async({username:e,completeUrl:r,cancelUrl:t,custom:n,completeAutoRedirect:i,ipAddress:m})=>{return(await g()).createMinecraftBasket(e,r,t,n,i,m)},N=async(e)=>{return(await g()).getBasket(e)},O=async(e,r,t,n,i)=>{return(await g()).addPackageToBasket(e,r,t??1,n,i)},V=async(e,r,t)=>{return(await g()).updateQuantity(e,r,t-1>=0?t-1:0)},X={createBasket:M,getBasket:N,addPackageToBasket:O,removePackageFromBasket:V},u=X;import{create as Y}from"zustand";import{persist as Z,subscribeWithSelector as _}from"zustand/middleware";var $=Y()(_(Z((e)=>({basketIdent:null,setBasketIdent:(r)=>e({basketIdent:r}),clearBasketIdent:()=>e({basketIdent:null})}),{name:"shop-basket-store"}))),x=$;import{create as E}from"zustand";import{subscribeWithSelector as I}from"zustand/middleware";var Q=E()(I((e)=>({isGlobalLoading:!1,setIsGlobalLoading:(r)=>e({isGlobalLoading:r}),isCreatingBasket:!1,setIsCreatingBasket:(r)=>e({isCreatingBasket:r})}))),h=Q;import{create as ee}from"zustand";import{persist as re,subscribeWithSelector as te}from"zustand/middleware";var oe=ee()(te(re((e)=>({username:"",setUsername:(r)=>e({username:r}),clearUsername:()=>e({username:""})}),{name:"shop-user-store"}))),b=oe;import{useCallback as ne}from"react";import{toast as v}from"sonner";var S=null;var se=async({includePackages:e,basketIdent:r,ipAddress:t})=>{return(await g()).getCategories(e,r,t)},ae={getCategories:se},w=ae;var ie=async(e)=>{let{isCreatingBasket:r,setIsCreatingBasket:t,setBasketIdent:n,createBasket:i,username:m}=e;if(r)return null;let{completeUrl:o,cancelUrl:p}=ce();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 n(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)}},le=(e)=>{let r=h((o)=>o.isCreatingBasket),t=h((o)=>o.setIsCreatingBasket),n=x((o)=>o.setBasketIdent),i=b((o)=>o.username);return ne(()=>ie({isCreatingBasket:r,setIsCreatingBasket:t,setBasketIdent:n,createBasket:u.createBasket,username:e??i}),[r,t,n,e,i])},ce=()=>{if(!S)throw Error("Shop URLs not initialized. Call initShopUrls(baseUrl, paths?: { complete?: string; cancel?: string }) first.");return{completeUrl:S.completeUrl,cancelUrl:S.cancelUrl}},y=le;var pe=(e)=>{let[r,t]=k(null),[n,i]=k(!1),[m,o]=k(null),[p,c]=k(!1),a=x((s)=>s.basketIdent),U=x((s)=>s.setBasketIdent),H=b((s)=>s.username),G=e??H,z=y(G),T=x((s)=>s.clearBasketIdent),R=async(s)=>{i(!0),o(null);try{let l=await u.getBasket(s);if(l.complete){t(null),T(),o(null);return}t(l),U(l.ident),o(null)}catch(l){o(l),t(null),T()}finally{i(!1)}},W=async(s,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(!a){if(f=(await z())?.ident??null,!f){C.error("Une erreur est survenue lors de la création du panier");return}U(f)}else f=a;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,s,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(s)=>{if(p)return;try{if(c(!0),!a){C.error("Vous n'avez pas de panier. Si le problème persiste, veuillez vous rapprocher du support.");return}let l=u.removePackageFromBasket(a,s,r?.packages.find((B)=>B.id===s)?.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(a)await R(a)},j=(s)=>{t(s)};return me(()=>{if(!a)return;R(a)},[a]),{basket:r,loading:n,error:m,updateManualBasket:j,addPackageToBasket:W,removePackageFromBasket:F,refetch:K}},fe=pe;import{useCallback as A,useEffect as ge,useState as P}from"react";var ue=(e)=>{let[r,t]=P(null),[n,i]=P(!0),[m,o]=P(null),p=A(async()=>{i(!0),o(null);try{let a=await w.getCategories(e);t(a)}catch(a){o(a),t(null)}finally{i(!1)}},[e]);ge(()=>{p()},[p]);let c=A((a)=>r?.find((U)=>U.name.toLowerCase()===a.toLowerCase()),[r]);return{categories:r,loading:n,error:m,getByName:c,refetch:p}},xe=ue;export{b as useShopUserStore,h as useShopUiStore,x as useShopBasketStore,y as useCreateBasket,xe as useCategories,fe as useBasket,g as getTebex,w as categoriesService,u as basketService};
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@neosianexus/super-tebex",
3
3
  "type": "module",
4
- "version": "1.1.6",
4
+ "version": "2.0.0",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.js",
7
7
  "types": "./dist/index.d.ts",