@diffsome/react 1.1.1 → 1.1.2

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.
Files changed (2) hide show
  1. package/README.md +218 -24
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -8,25 +8,91 @@ Headless React hooks and providers for Diffsome SDK. Build any e-commerce or CMS
8
8
  npm install @diffsome/react @diffsome/sdk
9
9
  # or
10
10
  yarn add @diffsome/react @diffsome/sdk
11
+ # or
12
+ pnpm add @diffsome/react @diffsome/sdk
11
13
  ```
12
14
 
13
- ## Quick Start
15
+ ## Configuration
16
+
17
+ ### Option 1: Environment Variables (Recommended)
18
+
19
+ **Next.js** (`.env.local`)
20
+ ```bash
21
+ NEXT_PUBLIC_DIFFSOME_TENANT_ID=my-store
22
+ NEXT_PUBLIC_DIFFSOME_API_KEY=pky_xxx # optional
23
+ NEXT_PUBLIC_DIFFSOME_BASE_URL=https://api.diffsome.com # optional
24
+ ```
25
+
26
+ **Create React App** (`.env`)
27
+ ```bash
28
+ REACT_APP_DIFFSOME_TENANT_ID=my-store
29
+ REACT_APP_DIFFSOME_API_KEY=pky_xxx
30
+ ```
31
+
32
+ Then simply wrap your app:
14
33
 
15
34
  ```tsx
16
- import { DiffsomeProvider, useAuth, useCart, useProducts } from '@diffsome/react';
35
+ import { DiffsomeProvider } from '@diffsome/react';
17
36
 
18
37
  function App() {
19
38
  return (
20
- <DiffsomeProvider
21
- config={{
22
- tenantId: 'my-store',
23
- apiKey: 'pky_your_api_key',
24
- }}
25
- >
26
- <Shop />
39
+ <DiffsomeProvider>
40
+ <YourApp />
27
41
  </DiffsomeProvider>
28
42
  );
29
43
  }
44
+ ```
45
+
46
+ ### Option 2: Direct Config
47
+
48
+ ```tsx
49
+ <DiffsomeProvider
50
+ config={{
51
+ tenantId: 'my-store', // required
52
+ apiKey: 'pky_xxx', // optional
53
+ baseUrl: 'https://api.diffsome.com', // optional
54
+ persistToken: true, // default: true
55
+ storageType: 'localStorage', // 'localStorage' | 'sessionStorage'
56
+ }}
57
+ >
58
+ <YourApp />
59
+ </DiffsomeProvider>
60
+ ```
61
+
62
+ ### Next.js App Router Setup
63
+
64
+ ```tsx
65
+ // app/providers.tsx
66
+ 'use client';
67
+
68
+ import { DiffsomeProvider } from '@diffsome/react';
69
+
70
+ export function Providers({ children }: { children: React.ReactNode }) {
71
+ return (
72
+ <DiffsomeProvider>
73
+ {children}
74
+ </DiffsomeProvider>
75
+ );
76
+ }
77
+
78
+ // app/layout.tsx
79
+ import { Providers } from './providers';
80
+
81
+ export default function RootLayout({ children }) {
82
+ return (
83
+ <html>
84
+ <body>
85
+ <Providers>{children}</Providers>
86
+ </body>
87
+ </html>
88
+ );
89
+ }
90
+ ```
91
+
92
+ ## Quick Start
93
+
94
+ ```tsx
95
+ import { DiffsomeProvider, useAuth, useCart, useProducts } from '@diffsome/react';
30
96
 
31
97
  function Shop() {
32
98
  const { user, login, logout } = useAuth();
@@ -62,29 +128,34 @@ function Shop() {
62
128
  ## Available Hooks
63
129
 
64
130
  ### Authentication
65
- - `useAuth()` - Login, register, logout, profile management
131
+ - `useAuth()` - Login, register, logout, profile, password reset
66
132
  - `useSocialAuth()` - Social login (Google, Kakao, Naver, etc.)
67
133
 
68
134
  ### E-commerce
69
135
  - `useCart()` - Cart management (add, update, remove items)
70
- - `useWishlist()` - Wishlist management
71
- - `useProducts()` - Product listing with pagination
136
+ - `useWishlist()` - Wishlist management with toggle
137
+ - `useProducts(options?)` - Product listing with pagination & search
72
138
  - `useProduct(slug)` - Single product details
73
139
  - `useCategories()` - Product categories
74
- - `useFeaturedProducts()` - Featured products
140
+ - `useFeaturedProducts(limit?)` - Featured products
141
+ - `useProductsByType(type)` - Products by type (digital, subscription, bundle)
142
+ - `useDigitalProducts()` - Digital products shorthand
143
+ - `useSubscriptionProducts()` - Subscription products shorthand
144
+ - `useBundleProducts()` - Bundle products shorthand
145
+ - `useBundleItems(slug)` - Bundle items with pricing
75
146
  - `useOrders()` - Order history
76
147
  - `useOrder(id)` - Single order details
77
148
  - `useCreateOrder()` - Create new order
78
149
 
79
150
  ### Payment
80
- - `usePaymentStatus()` - Check available payment methods (Toss, Stripe)
151
+ - `usePaymentStatus()` - Check available payment methods
81
152
  - `useTossPayment()` - Toss Payments (Korea)
82
153
  - `useStripePayment()` - Stripe Payments (Global)
83
154
  - `useCoupons()` - User's available coupons
84
155
  - `useValidateCoupon()` - Validate coupon code
85
156
 
86
157
  ### Subscriptions
87
- - `useSubscriptions()` - User's subscriptions
158
+ - `useSubscriptions()` - User's subscriptions list
88
159
  - `useSubscription(id)` - Single subscription with cancel/pause/resume
89
160
  - `useCreateSubscription()` - Create subscription via Stripe
90
161
 
@@ -93,15 +164,18 @@ function Shop() {
93
164
  - `useOrderDownloads(orderNumber)` - Downloads for specific order
94
165
 
95
166
  ### Reviews
96
- - `useProductReviews(slug)` - Product reviews
167
+ - `useProductReviews(slug)` - Product reviews with stats
97
168
  - `useMyReviews()` - User's reviews
98
169
  - `useCanReview(slug)` - Check review eligibility
99
170
  - `useCreateReview()` - Create product review
100
171
 
101
172
  ### Content
102
- - `useBlog()` - Blog posts with pagination
173
+ - `useBlog(options?)` - Blog posts with pagination
103
174
  - `useBlogPost(slug)` - Single blog post
104
175
  - `useBlogCategories()` - Blog categories
176
+ - `useBlogTags()` - Blog tags
177
+ - `useFeaturedBlog(limit?)` - Featured blog posts
178
+ - `useBlogSearch()` - Blog search
105
179
  - `useBoards()` - Board listing
106
180
  - `useBoard(slug)` - Single board
107
181
  - `useBoardPosts(slug)` - Board posts
@@ -112,8 +186,8 @@ function Shop() {
112
186
 
113
187
  ### Reservations
114
188
  - `useReservationServices()` - Available services
115
- - `useReservationStaffs()` - Staff members
116
- - `useAvailableSlots(serviceId, date)` - Time slots
189
+ - `useReservationStaffs(serviceId?)` - Staff members
190
+ - `useAvailableSlots(serviceId, staffId?, date)` - Available time slots
117
191
  - `useMyReservations()` - User's reservations
118
192
  - `useCreateReservation()` - Create reservation
119
193
  - `useReservationSettings()` - Reservation settings
@@ -134,7 +208,7 @@ function Shop() {
134
208
 
135
209
  ```tsx
136
210
  function LoginForm() {
137
- const { user, login, logout, loading, error } = useAuth();
211
+ const { user, login, logout, forgotPassword, loading, error } = useAuth();
138
212
  const [email, setEmail] = useState('');
139
213
  const [password, setPassword] = useState('');
140
214
 
@@ -143,6 +217,11 @@ function LoginForm() {
143
217
  await login({ email, password });
144
218
  };
145
219
 
220
+ const handleForgotPassword = async () => {
221
+ await forgotPassword(email);
222
+ alert('Password reset email sent!');
223
+ };
224
+
146
225
  if (user) {
147
226
  return (
148
227
  <div>
@@ -157,17 +236,53 @@ function LoginForm() {
157
236
  <input value={email} onChange={(e) => setEmail(e.target.value)} />
158
237
  <input type="password" value={password} onChange={(e) => setPassword(e.target.value)} />
159
238
  <button disabled={loading}>Login</button>
239
+ <button type="button" onClick={handleForgotPassword}>Forgot Password</button>
160
240
  {error && <p>{error.message}</p>}
161
241
  </form>
162
242
  );
163
243
  }
164
244
  ```
165
245
 
246
+ ### useProducts with Filters
247
+
248
+ ```tsx
249
+ function ProductGrid() {
250
+ const { products, loading, hasMore, loadMore, search } = useProducts({
251
+ per_page: 12,
252
+ category: 'electronics',
253
+ });
254
+ const [query, setQuery] = useState('');
255
+
256
+ return (
257
+ <div>
258
+ <input
259
+ placeholder="Search products..."
260
+ value={query}
261
+ onChange={(e) => setQuery(e.target.value)}
262
+ onKeyDown={(e) => e.key === 'Enter' && search(query)}
263
+ />
264
+
265
+ <div className="grid grid-cols-4 gap-4">
266
+ {products.map(product => (
267
+ <ProductCard key={product.id} product={product} />
268
+ ))}
269
+ </div>
270
+
271
+ {hasMore && (
272
+ <button onClick={loadMore} disabled={loading}>
273
+ Load More
274
+ </button>
275
+ )}
276
+ </div>
277
+ );
278
+ }
279
+ ```
280
+
166
281
  ### useCart
167
282
 
168
283
  ```tsx
169
284
  function Cart() {
170
- const { items, total, updateItem, removeItem, clearCart } = useCart();
285
+ const { items, total, updateItem, removeItem, clearCart, applyCoupon } = useCart();
171
286
 
172
287
  return (
173
288
  <div>
@@ -193,12 +308,17 @@ function Cart() {
193
308
 
194
309
  ```tsx
195
310
  function WishlistButton({ productId }) {
196
- const { isInWishlist, toggleWishlist } = useWishlist();
311
+ const { isInWishlist, toggleWishlist, getProductWishlistCount } = useWishlist();
312
+ const [count, setCount] = useState(0);
197
313
  const inWishlist = isInWishlist(productId);
198
314
 
315
+ useEffect(() => {
316
+ getProductWishlistCount(productId).then(setCount);
317
+ }, [productId]);
318
+
199
319
  return (
200
320
  <button onClick={() => toggleWishlist(productId)}>
201
- {inWishlist ? '❤️' : '🤍'}
321
+ {inWishlist ? '❤️' : '🤍'} {count}
202
322
  </button>
203
323
  );
204
324
  }
@@ -227,6 +347,65 @@ function CheckoutButton({ orderNumber }) {
227
347
  }
228
348
  ```
229
349
 
350
+ ### useSubscription
351
+
352
+ ```tsx
353
+ function SubscriptionManager({ subscriptionId }) {
354
+ const { subscription, cancel, pause, resume, loading } = useSubscription(subscriptionId);
355
+
356
+ if (!subscription) return null;
357
+
358
+ return (
359
+ <div>
360
+ <p>Plan: {subscription.plan.name}</p>
361
+ <p>Status: {subscription.status}</p>
362
+ <p>Next billing: {subscription.current_period_end}</p>
363
+
364
+ {subscription.status === 'active' && (
365
+ <>
366
+ <button onClick={pause}>Pause</button>
367
+ <button onClick={cancel}>Cancel</button>
368
+ </>
369
+ )}
370
+ {subscription.status === 'paused' && (
371
+ <button onClick={resume}>Resume</button>
372
+ )}
373
+ </div>
374
+ );
375
+ }
376
+ ```
377
+
378
+ ### useBlogSearch
379
+
380
+ ```tsx
381
+ function BlogSearch() {
382
+ const { results, search, loading } = useBlogSearch();
383
+ const [query, setQuery] = useState('');
384
+
385
+ const handleSearch = () => {
386
+ search(query);
387
+ };
388
+
389
+ return (
390
+ <div>
391
+ <input
392
+ value={query}
393
+ onChange={(e) => setQuery(e.target.value)}
394
+ placeholder="Search blog..."
395
+ />
396
+ <button onClick={handleSearch} disabled={loading}>Search</button>
397
+
398
+ {results.map(post => (
399
+ <article key={post.id}>
400
+ <h3>{post.title}</h3>
401
+ <p>{post.excerpt}</p>
402
+ </article>
403
+ ))}
404
+ </div>
405
+ );
406
+ }
407
+ ```
408
+
230
409
  ### useComments
231
410
 
232
411
  ```tsx
@@ -345,9 +524,24 @@ function CustomComponent() {
345
524
  All types are re-exported from `@diffsome/sdk`:
346
525
 
347
526
  ```tsx
348
- import type { Product, Cart, Order, Member, CustomEntity, EntityRecord } from '@diffsome/react';
527
+ import type {
528
+ Product,
529
+ Cart,
530
+ Order,
531
+ Member,
532
+ CustomEntity,
533
+ EntityRecord,
534
+ BlogPost,
535
+ Reservation,
536
+ // ... and more
537
+ } from '@diffsome/react';
349
538
  ```
350
539
 
540
+ ## Requirements
541
+
542
+ - React 18.0+
543
+ - @diffsome/sdk 3.2.0+
544
+
351
545
  ## License
352
546
 
353
547
  MIT
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diffsome/react",
3
- "version": "1.1.1",
3
+ "version": "1.1.2",
4
4
  "description": "React hooks and providers for Diffsome SDK - Headless e-commerce & CMS",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",