@diffsome/react 1.1.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 ADDED
@@ -0,0 +1,353 @@
1
+ # @diffsome/react
2
+
3
+ Headless React hooks and providers for Diffsome SDK. Build any e-commerce or CMS frontend with your own UI components.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @diffsome/react @diffsome/sdk
9
+ # or
10
+ yarn add @diffsome/react @diffsome/sdk
11
+ ```
12
+
13
+ ## Quick Start
14
+
15
+ ```tsx
16
+ import { DiffsomeProvider, useAuth, useCart, useProducts } from '@diffsome/react';
17
+
18
+ function App() {
19
+ return (
20
+ <DiffsomeProvider
21
+ config={{
22
+ tenantId: 'my-store',
23
+ apiKey: 'pky_your_api_key',
24
+ }}
25
+ >
26
+ <Shop />
27
+ </DiffsomeProvider>
28
+ );
29
+ }
30
+
31
+ function Shop() {
32
+ const { user, login, logout } = useAuth();
33
+ const { items, addToCart, total } = useCart();
34
+ const { products, loading } = useProducts();
35
+
36
+ if (loading) return <div>Loading...</div>;
37
+
38
+ return (
39
+ <div>
40
+ {user ? (
41
+ <p>Welcome, {user.name}! <button onClick={logout}>Logout</button></p>
42
+ ) : (
43
+ <button onClick={() => login({ email: '...', password: '...' })}>Login</button>
44
+ )}
45
+
46
+ <h2>Products</h2>
47
+ {products.map(product => (
48
+ <div key={product.id}>
49
+ <h3>{product.name}</h3>
50
+ <p>${product.sale_price}</p>
51
+ <button onClick={() => addToCart(product.id)}>Add to Cart</button>
52
+ </div>
53
+ ))}
54
+
55
+ <h2>Cart ({items.length} items)</h2>
56
+ <p>Total: ${total}</p>
57
+ </div>
58
+ );
59
+ }
60
+ ```
61
+
62
+ ## Available Hooks
63
+
64
+ ### Authentication
65
+ - `useAuth()` - Login, register, logout, profile management
66
+ - `useSocialAuth()` - Social login (Google, Kakao, Naver, etc.)
67
+
68
+ ### E-commerce
69
+ - `useCart()` - Cart management (add, update, remove items)
70
+ - `useWishlist()` - Wishlist management
71
+ - `useProducts()` - Product listing with pagination
72
+ - `useProduct(slug)` - Single product details
73
+ - `useCategories()` - Product categories
74
+ - `useFeaturedProducts()` - Featured products
75
+ - `useOrders()` - Order history
76
+ - `useOrder(id)` - Single order details
77
+ - `useCreateOrder()` - Create new order
78
+
79
+ ### Payment
80
+ - `usePaymentStatus()` - Check available payment methods (Toss, Stripe)
81
+ - `useTossPayment()` - Toss Payments (Korea)
82
+ - `useStripePayment()` - Stripe Payments (Global)
83
+ - `useCoupons()` - User's available coupons
84
+ - `useValidateCoupon()` - Validate coupon code
85
+
86
+ ### Subscriptions
87
+ - `useSubscriptions()` - User's subscriptions
88
+ - `useSubscription(id)` - Single subscription with cancel/pause/resume
89
+ - `useCreateSubscription()` - Create subscription via Stripe
90
+
91
+ ### Digital Downloads
92
+ - `useDownloads()` - User's digital download links
93
+ - `useOrderDownloads(orderNumber)` - Downloads for specific order
94
+
95
+ ### Reviews
96
+ - `useProductReviews(slug)` - Product reviews
97
+ - `useMyReviews()` - User's reviews
98
+ - `useCanReview(slug)` - Check review eligibility
99
+ - `useCreateReview()` - Create product review
100
+
101
+ ### Content
102
+ - `useBlog()` - Blog posts with pagination
103
+ - `useBlogPost(slug)` - Single blog post
104
+ - `useBlogCategories()` - Blog categories
105
+ - `useBoards()` - Board listing
106
+ - `useBoard(slug)` - Single board
107
+ - `useBoardPosts(slug)` - Board posts
108
+ - `useBoardPost(id)` - Single board post
109
+ - `useCreateBoardPost()` - Create board post
110
+ - `useComments({ type, target })` - Comments for board/blog/standalone
111
+ - `useForm(slug)` - Form with submission
112
+
113
+ ### Reservations
114
+ - `useReservationServices()` - Available services
115
+ - `useReservationStaffs()` - Staff members
116
+ - `useAvailableSlots(serviceId, date)` - Time slots
117
+ - `useMyReservations()` - User's reservations
118
+ - `useCreateReservation()` - Create reservation
119
+ - `useReservationSettings()` - Reservation settings
120
+
121
+ ### Media
122
+ - `useMedia()` - File upload and management
123
+
124
+ ### Custom Entities (Dynamic Data)
125
+ - `useEntities()` - List all entity definitions
126
+ - `useEntity(slug)` - Single entity with schema
127
+ - `useEntityRecords(slug)` - CRUD for entity records
128
+ - `useEntityRecord(slug, id)` - Single record
129
+ - `useTypedEntity<T>(slug)` - Typed entity accessor
130
+
131
+ ## Hook Examples
132
+
133
+ ### useAuth
134
+
135
+ ```tsx
136
+ function LoginForm() {
137
+ const { user, login, logout, loading, error } = useAuth();
138
+ const [email, setEmail] = useState('');
139
+ const [password, setPassword] = useState('');
140
+
141
+ const handleSubmit = async (e) => {
142
+ e.preventDefault();
143
+ await login({ email, password });
144
+ };
145
+
146
+ if (user) {
147
+ return (
148
+ <div>
149
+ <p>Welcome, {user.name}</p>
150
+ <button onClick={logout}>Logout</button>
151
+ </div>
152
+ );
153
+ }
154
+
155
+ return (
156
+ <form onSubmit={handleSubmit}>
157
+ <input value={email} onChange={(e) => setEmail(e.target.value)} />
158
+ <input type="password" value={password} onChange={(e) => setPassword(e.target.value)} />
159
+ <button disabled={loading}>Login</button>
160
+ {error && <p>{error.message}</p>}
161
+ </form>
162
+ );
163
+ }
164
+ ```
165
+
166
+ ### useCart
167
+
168
+ ```tsx
169
+ function Cart() {
170
+ const { items, total, updateItem, removeItem, clearCart } = useCart();
171
+
172
+ return (
173
+ <div>
174
+ {items.map(item => (
175
+ <div key={item.id}>
176
+ <span>{item.product_name}</span>
177
+ <input
178
+ type="number"
179
+ value={item.quantity}
180
+ onChange={(e) => updateItem(item.id, parseInt(e.target.value))}
181
+ />
182
+ <button onClick={() => removeItem(item.id)}>Remove</button>
183
+ </div>
184
+ ))}
185
+ <p>Total: ${total}</p>
186
+ <button onClick={clearCart}>Clear Cart</button>
187
+ </div>
188
+ );
189
+ }
190
+ ```
191
+
192
+ ### useWishlist
193
+
194
+ ```tsx
195
+ function WishlistButton({ productId }) {
196
+ const { isInWishlist, toggleWishlist } = useWishlist();
197
+ const inWishlist = isInWishlist(productId);
198
+
199
+ return (
200
+ <button onClick={() => toggleWishlist(productId)}>
201
+ {inWishlist ? '❤️' : '🤍'}
202
+ </button>
203
+ );
204
+ }
205
+ ```
206
+
207
+ ### useStripePayment
208
+
209
+ ```tsx
210
+ function CheckoutButton({ orderNumber }) {
211
+ const { createCheckout, loading } = useStripePayment();
212
+
213
+ const handleCheckout = async () => {
214
+ const { checkout_url } = await createCheckout(
215
+ orderNumber,
216
+ `${window.location.origin}/checkout/success`,
217
+ `${window.location.origin}/checkout/cancel`
218
+ );
219
+ window.location.href = checkout_url;
220
+ };
221
+
222
+ return (
223
+ <button onClick={handleCheckout} disabled={loading}>
224
+ Pay with Stripe
225
+ </button>
226
+ );
227
+ }
228
+ ```
229
+
230
+ ### useComments
231
+
232
+ ```tsx
233
+ function Comments({ postId }) {
234
+ const { comments, createComment, likeComment, loading } = useComments({
235
+ type: 'board',
236
+ target: postId,
237
+ });
238
+
239
+ const handleSubmit = async (content) => {
240
+ await createComment({ content });
241
+ };
242
+
243
+ return (
244
+ <div>
245
+ {comments.map(comment => (
246
+ <div key={comment.id}>
247
+ <p>{comment.content}</p>
248
+ <button onClick={() => likeComment(comment.id)}>
249
+ Like ({comment.likes})
250
+ </button>
251
+ </div>
252
+ ))}
253
+ </div>
254
+ );
255
+ }
256
+ ```
257
+
258
+ ### useEntityRecords (Custom Entities)
259
+
260
+ ```tsx
261
+ // Dynamic CRM example
262
+ function CustomerList() {
263
+ const { records, createRecord, deleteRecord, loading } = useEntityRecords('customers');
264
+
265
+ const addCustomer = async () => {
266
+ await createRecord({
267
+ company: 'ACME Corp',
268
+ email: 'contact@acme.com',
269
+ tier: 'vip',
270
+ });
271
+ };
272
+
273
+ return (
274
+ <div>
275
+ {records.map(customer => (
276
+ <div key={customer.id}>
277
+ <span>{customer.data.company}</span>
278
+ <button onClick={() => deleteRecord(customer.id)}>Delete</button>
279
+ </div>
280
+ ))}
281
+ <button onClick={addCustomer}>Add Customer</button>
282
+ </div>
283
+ );
284
+ }
285
+
286
+ // With TypeScript
287
+ interface Customer {
288
+ company: string;
289
+ email: string;
290
+ tier: 'standard' | 'vip';
291
+ }
292
+
293
+ function TypedCustomerList() {
294
+ const customers = useTypedEntity<Customer>('customers');
295
+ // customers.useRecords() returns typed records
296
+ // customers.create({ company: '...' }) has type checking
297
+ }
298
+ ```
299
+
300
+ ### useMedia
301
+
302
+ ```tsx
303
+ function FileUploader() {
304
+ const { upload, uploading, uploadProgress } = useMedia();
305
+
306
+ const handleFileChange = async (e) => {
307
+ const file = e.target.files[0];
308
+ if (file) {
309
+ const media = await upload(file);
310
+ console.log('Uploaded:', media.url);
311
+ }
312
+ };
313
+
314
+ return (
315
+ <div>
316
+ <input type="file" onChange={handleFileChange} disabled={uploading} />
317
+ {uploading && <progress value={uploadProgress} max={100} />}
318
+ </div>
319
+ );
320
+ }
321
+ ```
322
+
323
+ ## Low-level Access
324
+
325
+ Use `useClient()` to access the SDK directly:
326
+
327
+ ```tsx
328
+ import { useClient } from '@diffsome/react';
329
+
330
+ function CustomComponent() {
331
+ const client = useClient();
332
+
333
+ const handleCustomAction = async () => {
334
+ // Direct SDK access
335
+ const result = await client.shop.validateCoupon('SAVE10', 5000);
336
+ console.log(result);
337
+ };
338
+
339
+ return <button onClick={handleCustomAction}>Validate Coupon</button>;
340
+ }
341
+ ```
342
+
343
+ ## TypeScript
344
+
345
+ All types are re-exported from `@diffsome/sdk`:
346
+
347
+ ```tsx
348
+ import type { Product, Cart, Order, Member, CustomEntity, EntityRecord } from '@diffsome/react';
349
+ ```
350
+
351
+ ## License
352
+
353
+ MIT