@back23/promptly-sdk 1.3.0 → 1.3.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.
- package/README.md +297 -179
- package/dist/index.js +5 -5
- package/dist/index.mjs +5 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
# @
|
|
1
|
+
# @back23/promptly-sdk
|
|
2
2
|
|
|
3
3
|
Promptly AI CMS SDK for JavaScript/TypeScript
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
npm install @
|
|
8
|
+
npm install @back23/promptly-sdk
|
|
9
9
|
```
|
|
10
10
|
|
|
11
11
|
## Quick Start
|
|
12
12
|
|
|
13
13
|
```typescript
|
|
14
|
-
import { Promptly } from '@
|
|
14
|
+
import { Promptly } from '@back23/promptly-sdk';
|
|
15
15
|
|
|
16
16
|
const client = new Promptly({
|
|
17
17
|
tenantId: 'demo',
|
|
@@ -19,6 +19,38 @@ const client = new Promptly({
|
|
|
19
19
|
});
|
|
20
20
|
```
|
|
21
21
|
|
|
22
|
+
## v1.3.0 Changes
|
|
23
|
+
|
|
24
|
+
### Unified Response Structure
|
|
25
|
+
|
|
26
|
+
All list APIs now return a consistent `ListResponse<T>` format:
|
|
27
|
+
|
|
28
|
+
```typescript
|
|
29
|
+
interface ListResponse<T> {
|
|
30
|
+
data: T[]; // Always an array (never null/undefined)
|
|
31
|
+
meta: {
|
|
32
|
+
current_page: number;
|
|
33
|
+
last_page: number;
|
|
34
|
+
per_page: number;
|
|
35
|
+
total: number;
|
|
36
|
+
from: number | null;
|
|
37
|
+
to: number | null;
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
**No more defensive code needed:**
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
// Before (v1.1.0)
|
|
46
|
+
const posts = await client.blog.list();
|
|
47
|
+
const items = posts?.data ?? []; // Defensive check needed
|
|
48
|
+
|
|
49
|
+
// After (v1.3.0)
|
|
50
|
+
const { data, meta } = await client.blog.list();
|
|
51
|
+
data.map(post => ...); // data is always an array
|
|
52
|
+
```
|
|
53
|
+
|
|
22
54
|
## API Overview
|
|
23
55
|
|
|
24
56
|
| Resource | Public (No Auth) | Protected (Auth Required) |
|
|
@@ -26,12 +58,13 @@ const client = new Promptly({
|
|
|
26
58
|
| **Boards** | list, get | - |
|
|
27
59
|
| **Posts** | listPosts, getPost | createPost, updatePost, deletePost |
|
|
28
60
|
| **Comments** | listComments | createComment, updateComment, deleteComment |
|
|
29
|
-
| **Blog** | list, get | - |
|
|
61
|
+
| **Blog** | list, get, featured, byCategory, byTag | - |
|
|
30
62
|
| **Shop** | listProducts, getProduct, listCategories | getCart, addToCart, listOrders, createOrder |
|
|
31
63
|
| **Forms** | list, get, submit | mySubmissions |
|
|
32
64
|
| **Auth** | login, register | logout, me, updateProfile |
|
|
33
65
|
| **Media** | - | upload, list, delete |
|
|
34
66
|
| **Entities** | list, getSchema, listRecords, getRecord | createRecord, updateRecord, deleteRecord |
|
|
67
|
+
| **Reservation** | getSettings, listServices, listStaff, getAvailableDates, getAvailableSlots | create, list, get, cancel |
|
|
35
68
|
|
|
36
69
|
## API Reference
|
|
37
70
|
|
|
@@ -39,20 +72,20 @@ const client = new Promptly({
|
|
|
39
72
|
|
|
40
73
|
```typescript
|
|
41
74
|
// 게시판 목록
|
|
42
|
-
const boards = await client.boards.list();
|
|
43
|
-
// Returns: Board
|
|
75
|
+
const { data: boards, meta } = await client.boards.list();
|
|
76
|
+
// Returns: ListResponse<Board>
|
|
44
77
|
|
|
45
78
|
// 게시판 상세
|
|
46
79
|
const board = await client.boards.get('first'); // slug or id
|
|
47
80
|
// Returns: Board
|
|
48
81
|
|
|
49
82
|
// 게시판 글 목록
|
|
50
|
-
const posts = await client.boards.listPosts('first', {
|
|
83
|
+
const { data: posts, meta } = await client.boards.listPosts('first', {
|
|
51
84
|
page: 1,
|
|
52
85
|
per_page: 10,
|
|
53
86
|
search: '검색어', // optional
|
|
54
87
|
});
|
|
55
|
-
// Returns:
|
|
88
|
+
// Returns: ListResponse<BoardPost>
|
|
56
89
|
|
|
57
90
|
// 글 상세
|
|
58
91
|
const post = await client.boards.getPost(1);
|
|
@@ -60,7 +93,7 @@ const post = await client.boards.getPost(1);
|
|
|
60
93
|
|
|
61
94
|
// 댓글 목록
|
|
62
95
|
const comments = await client.boards.listComments(1);
|
|
63
|
-
// Returns: BoardComment[]
|
|
96
|
+
// Returns: BoardComment[] (always an array)
|
|
64
97
|
```
|
|
65
98
|
|
|
66
99
|
### Posts & Comments - Protected (로그인 필요)
|
|
@@ -105,14 +138,14 @@ await client.boards.deleteComment(commentId);
|
|
|
105
138
|
|
|
106
139
|
```typescript
|
|
107
140
|
// 블로그 글 목록
|
|
108
|
-
const posts = await client.blog.list({
|
|
141
|
+
const { data: posts, meta } = await client.blog.list({
|
|
109
142
|
page: 1,
|
|
110
143
|
per_page: 10,
|
|
111
144
|
category: 'news', // optional
|
|
112
145
|
tag: 'featured', // optional
|
|
113
146
|
search: '검색어', // optional
|
|
114
147
|
});
|
|
115
|
-
// Returns:
|
|
148
|
+
// Returns: ListResponse<BlogPost>
|
|
116
149
|
|
|
117
150
|
// 블로그 글 상세
|
|
118
151
|
const post = await client.blog.get('post-slug');
|
|
@@ -120,13 +153,21 @@ const post = await client.blog.get('post-slug');
|
|
|
120
153
|
|
|
121
154
|
// 추천 글
|
|
122
155
|
const featured = await client.blog.featured(5);
|
|
123
|
-
// Returns: BlogPost[]
|
|
156
|
+
// Returns: BlogPost[] (always an array)
|
|
124
157
|
|
|
125
158
|
// 카테고리별 조회
|
|
126
|
-
const newsPosts = await client.blog.byCategory('news');
|
|
159
|
+
const { data: newsPosts } = await client.blog.byCategory('news');
|
|
127
160
|
|
|
128
161
|
// 태그별 조회
|
|
129
|
-
const taggedPosts = await client.blog.byTag('featured');
|
|
162
|
+
const { data: taggedPosts } = await client.blog.byTag('featured');
|
|
163
|
+
|
|
164
|
+
// 카테고리 목록
|
|
165
|
+
const categories = await client.blog.categories();
|
|
166
|
+
// Returns: string[] (always an array)
|
|
167
|
+
|
|
168
|
+
// 태그 목록
|
|
169
|
+
const tags = await client.blog.tags();
|
|
170
|
+
// Returns: string[] (always an array)
|
|
130
171
|
```
|
|
131
172
|
|
|
132
173
|
### Shop (쇼핑)
|
|
@@ -135,14 +176,14 @@ const taggedPosts = await client.blog.byTag('featured');
|
|
|
135
176
|
|
|
136
177
|
```typescript
|
|
137
178
|
// 상품 목록
|
|
138
|
-
const products = await client.shop.listProducts({
|
|
179
|
+
const { data: products, meta } = await client.shop.listProducts({
|
|
139
180
|
page: 1,
|
|
140
181
|
per_page: 10,
|
|
141
182
|
category: 'electronics', // optional
|
|
142
183
|
is_featured: true, // optional
|
|
143
184
|
search: '검색어', // optional
|
|
144
185
|
});
|
|
145
|
-
// Returns:
|
|
186
|
+
// Returns: ListResponse<Product>
|
|
146
187
|
|
|
147
188
|
// 상품 상세
|
|
148
189
|
const product = await client.shop.getProduct('product-slug');
|
|
@@ -150,11 +191,11 @@ const product = await client.shop.getProduct('product-slug');
|
|
|
150
191
|
|
|
151
192
|
// 추천 상품
|
|
152
193
|
const featured = await client.shop.featuredProducts(8);
|
|
153
|
-
// Returns: Product[]
|
|
194
|
+
// Returns: Product[] (always an array)
|
|
154
195
|
|
|
155
196
|
// 카테고리 목록
|
|
156
197
|
const categories = await client.shop.listCategories();
|
|
157
|
-
// Returns: ProductCategory[]
|
|
198
|
+
// Returns: ProductCategory[] (always an array)
|
|
158
199
|
```
|
|
159
200
|
|
|
160
201
|
#### Protected (로그인 필요)
|
|
@@ -195,8 +236,8 @@ const order = await client.shop.createOrder({
|
|
|
195
236
|
});
|
|
196
237
|
|
|
197
238
|
// 주문 목록
|
|
198
|
-
const orders = await client.shop.listOrders();
|
|
199
|
-
// Returns:
|
|
239
|
+
const { data: orders, meta } = await client.shop.listOrders();
|
|
240
|
+
// Returns: ListResponse<Order>
|
|
200
241
|
|
|
201
242
|
// 주문 상세
|
|
202
243
|
const order = await client.shop.getOrder(orderId);
|
|
@@ -208,6 +249,89 @@ await client.shop.cancelOrder(orderId);
|
|
|
208
249
|
// 쿠폰 검증
|
|
209
250
|
const validation = await client.shop.validateCoupon('SAVE10', 50000);
|
|
210
251
|
// Returns: { valid: boolean, discount_amount: number, coupon: Coupon }
|
|
252
|
+
|
|
253
|
+
// 내 쿠폰 목록
|
|
254
|
+
const coupons = await client.shop.myCoupons();
|
|
255
|
+
// Returns: Coupon[] (always an array)
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
### Reservation (예약) - NEW in v1.3.0
|
|
259
|
+
|
|
260
|
+
#### Public (로그인 불필요)
|
|
261
|
+
|
|
262
|
+
```typescript
|
|
263
|
+
// 예약 설정 조회
|
|
264
|
+
const settings = await client.reservation.getSettings();
|
|
265
|
+
// Returns: ReservationSettings
|
|
266
|
+
|
|
267
|
+
// 서비스 목록
|
|
268
|
+
const services = await client.reservation.listServices();
|
|
269
|
+
// Returns: ReservationService[] (always an array)
|
|
270
|
+
|
|
271
|
+
// 담당자 목록
|
|
272
|
+
const staffs = await client.reservation.listStaff();
|
|
273
|
+
// Returns: ReservationStaff[] (always an array)
|
|
274
|
+
|
|
275
|
+
// 특정 서비스의 담당자만 조회
|
|
276
|
+
const serviceStaffs = await client.reservation.listStaff(serviceId);
|
|
277
|
+
|
|
278
|
+
// 예약 가능 날짜 조회
|
|
279
|
+
const dates = await client.reservation.getAvailableDates({
|
|
280
|
+
service_id: 1,
|
|
281
|
+
staff_id: 2, // optional
|
|
282
|
+
start_date: '2026-01-01', // optional
|
|
283
|
+
end_date: '2026-01-31', // optional
|
|
284
|
+
});
|
|
285
|
+
// Returns: string[] (YYYY-MM-DD format)
|
|
286
|
+
|
|
287
|
+
// 예약 가능 시간 슬롯 조회
|
|
288
|
+
const slots = await client.reservation.getAvailableSlots({
|
|
289
|
+
service_id: 1,
|
|
290
|
+
date: '2026-01-15',
|
|
291
|
+
staff_id: 2, // optional
|
|
292
|
+
});
|
|
293
|
+
// Returns: ReservationSlot[]
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
#### Protected (로그인 필요)
|
|
297
|
+
|
|
298
|
+
```typescript
|
|
299
|
+
// 예약 생성
|
|
300
|
+
const result = await client.reservation.create({
|
|
301
|
+
service_id: 1,
|
|
302
|
+
staff_id: 2, // optional
|
|
303
|
+
reservation_date: '2026-01-15',
|
|
304
|
+
start_time: '14:00',
|
|
305
|
+
customer_name: '홍길동',
|
|
306
|
+
customer_phone: '010-1234-5678', // optional
|
|
307
|
+
customer_email: 'hong@example.com', // optional
|
|
308
|
+
customer_memo: '요청사항', // optional
|
|
309
|
+
});
|
|
310
|
+
// Returns: { reservation: Reservation, requires_payment: boolean, deposit: number }
|
|
311
|
+
|
|
312
|
+
// 내 예약 목록
|
|
313
|
+
const { data: reservations, meta } = await client.reservation.list({
|
|
314
|
+
status: 'confirmed', // optional
|
|
315
|
+
upcoming: true, // optional
|
|
316
|
+
past: false, // optional
|
|
317
|
+
});
|
|
318
|
+
// Returns: ListResponse<Reservation>
|
|
319
|
+
|
|
320
|
+
// 다가오는 예약
|
|
321
|
+
const upcoming = await client.reservation.upcoming(5);
|
|
322
|
+
// Returns: Reservation[] (always an array)
|
|
323
|
+
|
|
324
|
+
// 지난 예약
|
|
325
|
+
const past = await client.reservation.past(10);
|
|
326
|
+
// Returns: Reservation[] (always an array)
|
|
327
|
+
|
|
328
|
+
// 예약 상세
|
|
329
|
+
const reservation = await client.reservation.get('RES-20260115-001');
|
|
330
|
+
// Returns: Reservation
|
|
331
|
+
|
|
332
|
+
// 예약 취소
|
|
333
|
+
const cancelled = await client.reservation.cancel('RES-20260115-001', '일정 변경');
|
|
334
|
+
// Returns: Reservation
|
|
211
335
|
```
|
|
212
336
|
|
|
213
337
|
### Auth (인증)
|
|
@@ -280,8 +404,8 @@ const response = await client.auth.socialCallback('google', code);
|
|
|
280
404
|
|
|
281
405
|
```typescript
|
|
282
406
|
// 폼 목록
|
|
283
|
-
const forms = await client.forms.list();
|
|
284
|
-
// Returns: Form
|
|
407
|
+
const { data: forms } = await client.forms.list();
|
|
408
|
+
// Returns: ListResponse<Form>
|
|
285
409
|
|
|
286
410
|
// 폼 상세
|
|
287
411
|
const form = await client.forms.get('contact');
|
|
@@ -293,6 +417,10 @@ await client.forms.submit('contact', {
|
|
|
293
417
|
email: 'user@example.com',
|
|
294
418
|
message: '문의 내용',
|
|
295
419
|
});
|
|
420
|
+
|
|
421
|
+
// 내 제출 목록 (로그인 필요)
|
|
422
|
+
const { data: submissions } = await client.forms.mySubmissions();
|
|
423
|
+
// Returns: ListResponse<FormSubmission>
|
|
296
424
|
```
|
|
297
425
|
|
|
298
426
|
### Media (미디어) - Protected
|
|
@@ -307,12 +435,12 @@ const mediaList = await client.media.uploadMultiple([file1, file2]);
|
|
|
307
435
|
// Returns: Media[]
|
|
308
436
|
|
|
309
437
|
// 내 미디어 목록
|
|
310
|
-
const mediaList = await client.media.list({
|
|
438
|
+
const { data: mediaList, meta } = await client.media.list({
|
|
311
439
|
page: 1,
|
|
312
440
|
per_page: 20,
|
|
313
441
|
type: 'image/jpeg', // optional
|
|
314
442
|
});
|
|
315
|
-
// Returns:
|
|
443
|
+
// Returns: ListResponse<Media>
|
|
316
444
|
|
|
317
445
|
// 미디어 삭제
|
|
318
446
|
await client.media.delete(mediaId);
|
|
@@ -327,22 +455,22 @@ AI가 MCP를 통해 생성한 커스텀 데이터 구조에 접근합니다.
|
|
|
327
455
|
```typescript
|
|
328
456
|
// 엔티티 목록 조회
|
|
329
457
|
const entities = await client.entities.list();
|
|
330
|
-
// Returns: CustomEntity[]
|
|
458
|
+
// Returns: CustomEntity[] (always an array)
|
|
331
459
|
|
|
332
460
|
// 엔티티 스키마 조회
|
|
333
461
|
const schema = await client.entities.getSchema('customer');
|
|
334
462
|
// Returns: EntitySchema
|
|
335
463
|
|
|
336
464
|
// 레코드 목록 조회
|
|
337
|
-
const customers = await client.entities.listRecords('customer', {
|
|
465
|
+
const { data: customers, meta } = await client.entities.listRecords('customer', {
|
|
338
466
|
page: 1,
|
|
339
467
|
per_page: 20,
|
|
340
468
|
status: 'active',
|
|
341
469
|
});
|
|
342
|
-
// Returns:
|
|
470
|
+
// Returns: ListResponse<EntityRecord>
|
|
343
471
|
|
|
344
472
|
// 데이터 필드로 필터링
|
|
345
|
-
const vipCustomers = await client.entities.listRecords('customer', {
|
|
473
|
+
const { data: vipCustomers } = await client.entities.listRecords('customer', {
|
|
346
474
|
'data.tier': 'vip',
|
|
347
475
|
});
|
|
348
476
|
|
|
@@ -415,6 +543,27 @@ const settings = await client.getSettings();
|
|
|
415
543
|
|
|
416
544
|
## Types
|
|
417
545
|
|
|
546
|
+
### Common Types
|
|
547
|
+
|
|
548
|
+
```typescript
|
|
549
|
+
// Unified list response type
|
|
550
|
+
interface ListResponse<T> {
|
|
551
|
+
data: T[];
|
|
552
|
+
meta: PaginationMeta;
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
interface PaginationMeta {
|
|
556
|
+
current_page: number;
|
|
557
|
+
last_page: number;
|
|
558
|
+
per_page: number;
|
|
559
|
+
total: number;
|
|
560
|
+
from: number | null;
|
|
561
|
+
to: number | null;
|
|
562
|
+
}
|
|
563
|
+
```
|
|
564
|
+
|
|
565
|
+
### Resource Types
|
|
566
|
+
|
|
418
567
|
```typescript
|
|
419
568
|
interface Board {
|
|
420
569
|
id: number;
|
|
@@ -440,16 +589,6 @@ interface BoardPost {
|
|
|
440
589
|
created_at: string;
|
|
441
590
|
}
|
|
442
591
|
|
|
443
|
-
interface BoardComment {
|
|
444
|
-
id: number;
|
|
445
|
-
post_id: number;
|
|
446
|
-
member?: Member;
|
|
447
|
-
parent_id?: number;
|
|
448
|
-
content: string;
|
|
449
|
-
replies?: BoardComment[];
|
|
450
|
-
created_at: string;
|
|
451
|
-
}
|
|
452
|
-
|
|
453
592
|
interface BlogPost {
|
|
454
593
|
id: number;
|
|
455
594
|
slug: string;
|
|
@@ -463,8 +602,6 @@ interface BlogPost {
|
|
|
463
602
|
is_published: boolean;
|
|
464
603
|
published_at?: string;
|
|
465
604
|
view_count: number;
|
|
466
|
-
seo_title?: string;
|
|
467
|
-
seo_description?: string;
|
|
468
605
|
created_at: string;
|
|
469
606
|
}
|
|
470
607
|
|
|
@@ -473,38 +610,60 @@ interface Product {
|
|
|
473
610
|
slug: string;
|
|
474
611
|
name: string;
|
|
475
612
|
description?: string;
|
|
476
|
-
content?: string;
|
|
477
613
|
price: number;
|
|
478
614
|
compare_price?: number;
|
|
479
615
|
thumbnail?: string;
|
|
480
616
|
images?: string[];
|
|
481
617
|
status: 'draft' | 'active' | 'inactive';
|
|
482
618
|
is_featured: boolean;
|
|
483
|
-
has_options: boolean;
|
|
484
|
-
variants?: ProductVariant[];
|
|
485
619
|
in_stock?: boolean;
|
|
486
620
|
discount_percent?: number;
|
|
487
621
|
created_at: string;
|
|
488
622
|
}
|
|
489
623
|
|
|
490
|
-
interface
|
|
624
|
+
interface Reservation {
|
|
491
625
|
id: number;
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
626
|
+
reservation_number: string;
|
|
627
|
+
status: 'pending' | 'confirmed' | 'completed' | 'cancelled' | 'no_show';
|
|
628
|
+
status_label: string;
|
|
629
|
+
reservation_date: string;
|
|
630
|
+
start_time: string;
|
|
631
|
+
end_time: string;
|
|
632
|
+
time_range: string;
|
|
633
|
+
customer_name: string;
|
|
634
|
+
customer_phone: string | null;
|
|
635
|
+
customer_email: string | null;
|
|
636
|
+
price: number;
|
|
637
|
+
deposit: number;
|
|
638
|
+
payment_status: 'pending' | 'paid' | 'refunded' | 'partial';
|
|
639
|
+
can_cancel: boolean;
|
|
640
|
+
service: { id: number; name: string; duration: number; } | null;
|
|
641
|
+
staff: { id: number; name: string; avatar: string | null; } | null;
|
|
642
|
+
created_at: string;
|
|
496
643
|
}
|
|
497
644
|
|
|
498
|
-
interface
|
|
645
|
+
interface ReservationService {
|
|
499
646
|
id: number;
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
647
|
+
name: string;
|
|
648
|
+
slug: string;
|
|
649
|
+
description: string | null;
|
|
650
|
+
thumbnail: string | null;
|
|
651
|
+
duration: number;
|
|
652
|
+
price: number;
|
|
653
|
+
requires_staff: boolean;
|
|
654
|
+
requires_payment: boolean;
|
|
655
|
+
deposit: number;
|
|
656
|
+
staffs: Array<{ id: number; name: string; avatar: string | null; }>;
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
interface ReservationSettings {
|
|
660
|
+
timezone: string;
|
|
661
|
+
slot_interval: number;
|
|
662
|
+
min_notice_hours: number;
|
|
663
|
+
max_advance_days: number;
|
|
664
|
+
cancellation_hours: number;
|
|
665
|
+
allow_online_payment: boolean;
|
|
666
|
+
bookable_date_range: { start: string; end: string; };
|
|
508
667
|
}
|
|
509
668
|
|
|
510
669
|
interface Member {
|
|
@@ -517,56 +676,16 @@ interface Member {
|
|
|
517
676
|
created_at: string;
|
|
518
677
|
}
|
|
519
678
|
|
|
520
|
-
interface Form {
|
|
521
|
-
id: number;
|
|
522
|
-
slug: string;
|
|
523
|
-
name: string;
|
|
524
|
-
description?: string;
|
|
525
|
-
fields: FormField[];
|
|
526
|
-
settings: FormSettings;
|
|
527
|
-
is_active: boolean;
|
|
528
|
-
}
|
|
529
|
-
|
|
530
|
-
interface Media {
|
|
531
|
-
id: number;
|
|
532
|
-
url: string;
|
|
533
|
-
thumbnail_url?: string;
|
|
534
|
-
filename: string;
|
|
535
|
-
mime_type: string;
|
|
536
|
-
size: number;
|
|
537
|
-
created_at: string;
|
|
538
|
-
}
|
|
539
|
-
|
|
540
679
|
interface CustomEntity {
|
|
541
680
|
id: number;
|
|
542
681
|
name: string;
|
|
543
682
|
slug: string;
|
|
544
683
|
description?: string;
|
|
545
684
|
schema: EntitySchema;
|
|
546
|
-
icon?: string;
|
|
547
685
|
is_active: boolean;
|
|
548
|
-
records_count?: number;
|
|
549
686
|
created_at: string;
|
|
550
687
|
}
|
|
551
688
|
|
|
552
|
-
interface EntitySchema {
|
|
553
|
-
fields: EntityField[];
|
|
554
|
-
display?: {
|
|
555
|
-
title_field?: string;
|
|
556
|
-
list_fields?: string;
|
|
557
|
-
};
|
|
558
|
-
}
|
|
559
|
-
|
|
560
|
-
interface EntityField {
|
|
561
|
-
name: string;
|
|
562
|
-
label: string;
|
|
563
|
-
type: 'text' | 'textarea' | 'number' | 'email' | 'url' | 'date' | 'datetime' | 'boolean' | 'select' | 'multiselect';
|
|
564
|
-
required?: boolean;
|
|
565
|
-
searchable?: boolean;
|
|
566
|
-
default?: any;
|
|
567
|
-
options?: Array<{ value: string; label: string }>;
|
|
568
|
-
}
|
|
569
|
-
|
|
570
689
|
interface EntityRecord {
|
|
571
690
|
id: number;
|
|
572
691
|
entity_id: number;
|
|
@@ -580,7 +699,7 @@ interface EntityRecord {
|
|
|
580
699
|
## Error Handling
|
|
581
700
|
|
|
582
701
|
```typescript
|
|
583
|
-
import { Promptly, PromptlyError } from '@
|
|
702
|
+
import { Promptly, PromptlyError } from '@back23/promptly-sdk';
|
|
584
703
|
|
|
585
704
|
try {
|
|
586
705
|
await client.auth.login({ email: 'wrong@email.com', password: 'wrong' });
|
|
@@ -597,107 +716,106 @@ try {
|
|
|
597
716
|
|
|
598
717
|
```tsx
|
|
599
718
|
import { useState, useEffect } from 'react';
|
|
600
|
-
import { Promptly } from '@
|
|
719
|
+
import { Promptly } from '@back23/promptly-sdk';
|
|
601
720
|
|
|
602
721
|
const client = new Promptly({
|
|
603
722
|
tenantId: 'demo',
|
|
604
723
|
baseUrl: 'https://promptly.webbyon.com',
|
|
605
724
|
});
|
|
606
725
|
|
|
607
|
-
//
|
|
608
|
-
function
|
|
726
|
+
// 블로그 글 목록 (with pagination)
|
|
727
|
+
function BlogList() {
|
|
609
728
|
const [posts, setPosts] = useState([]);
|
|
610
|
-
const [
|
|
729
|
+
const [meta, setMeta] = useState(null);
|
|
730
|
+
const [page, setPage] = useState(1);
|
|
611
731
|
|
|
612
732
|
useEffect(() => {
|
|
613
|
-
client.
|
|
614
|
-
.then(
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
733
|
+
client.blog.list({ page, per_page: 10 })
|
|
734
|
+
.then(({ data, meta }) => {
|
|
735
|
+
setPosts(data); // Always an array
|
|
736
|
+
setMeta(meta);
|
|
737
|
+
});
|
|
738
|
+
}, [page]);
|
|
619
739
|
|
|
620
740
|
return (
|
|
621
|
-
<
|
|
622
|
-
|
|
623
|
-
<
|
|
624
|
-
<
|
|
625
|
-
<
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
</tr>
|
|
629
|
-
</thead>
|
|
630
|
-
<tbody>
|
|
631
|
-
{posts.map(post => (
|
|
632
|
-
<tr key={post.id}>
|
|
633
|
-
<td>{post.title}</td>
|
|
634
|
-
<td>{post.author}</td>
|
|
635
|
-
<td>{post.views}</td>
|
|
636
|
-
<td>{new Date(post.created_at).toLocaleDateString()}</td>
|
|
637
|
-
</tr>
|
|
638
|
-
))}
|
|
639
|
-
</tbody>
|
|
640
|
-
</table>
|
|
641
|
-
);
|
|
642
|
-
}
|
|
643
|
-
|
|
644
|
-
// 로그인 폼
|
|
645
|
-
function LoginForm() {
|
|
646
|
-
const [email, setEmail] = useState('');
|
|
647
|
-
const [password, setPassword] = useState('');
|
|
648
|
-
const [error, setError] = useState('');
|
|
649
|
-
|
|
650
|
-
const handleSubmit = async (e) => {
|
|
651
|
-
e.preventDefault();
|
|
652
|
-
try {
|
|
653
|
-
await client.auth.login({ email, password });
|
|
654
|
-
// 로그인 성공 - 리다이렉트 등
|
|
655
|
-
} catch (err) {
|
|
656
|
-
setError(err.message);
|
|
657
|
-
}
|
|
658
|
-
};
|
|
741
|
+
<div>
|
|
742
|
+
{posts.map(post => (
|
|
743
|
+
<article key={post.id}>
|
|
744
|
+
<h2>{post.title}</h2>
|
|
745
|
+
<p>{post.excerpt}</p>
|
|
746
|
+
</article>
|
|
747
|
+
))}
|
|
659
748
|
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
749
|
+
{meta && (
|
|
750
|
+
<div>
|
|
751
|
+
Page {meta.current_page} of {meta.last_page}
|
|
752
|
+
<button
|
|
753
|
+
onClick={() => setPage(p => p - 1)}
|
|
754
|
+
disabled={page <= 1}
|
|
755
|
+
>
|
|
756
|
+
Previous
|
|
757
|
+
</button>
|
|
758
|
+
<button
|
|
759
|
+
onClick={() => setPage(p => p + 1)}
|
|
760
|
+
disabled={page >= meta.last_page}
|
|
761
|
+
>
|
|
762
|
+
Next
|
|
763
|
+
</button>
|
|
764
|
+
</div>
|
|
765
|
+
)}
|
|
766
|
+
</div>
|
|
677
767
|
);
|
|
678
768
|
}
|
|
679
769
|
|
|
680
|
-
//
|
|
681
|
-
function
|
|
682
|
-
const [
|
|
770
|
+
// 예약 폼
|
|
771
|
+
function ReservationForm() {
|
|
772
|
+
const [services, setServices] = useState([]);
|
|
773
|
+
const [selectedService, setSelectedService] = useState(null);
|
|
774
|
+
const [dates, setDates] = useState([]);
|
|
775
|
+
const [slots, setSlots] = useState([]);
|
|
683
776
|
|
|
684
777
|
useEffect(() => {
|
|
685
|
-
client.
|
|
686
|
-
.then(res => setProducts(res.data));
|
|
778
|
+
client.reservation.listServices().then(setServices);
|
|
687
779
|
}, []);
|
|
688
780
|
|
|
781
|
+
useEffect(() => {
|
|
782
|
+
if (selectedService) {
|
|
783
|
+
client.reservation.getAvailableDates({
|
|
784
|
+
service_id: selectedService,
|
|
785
|
+
}).then(setDates);
|
|
786
|
+
}
|
|
787
|
+
}, [selectedService]);
|
|
788
|
+
|
|
789
|
+
const handleDateSelect = async (date) => {
|
|
790
|
+
const availableSlots = await client.reservation.getAvailableSlots({
|
|
791
|
+
service_id: selectedService,
|
|
792
|
+
date,
|
|
793
|
+
});
|
|
794
|
+
setSlots(availableSlots);
|
|
795
|
+
};
|
|
796
|
+
|
|
689
797
|
return (
|
|
690
|
-
<div
|
|
691
|
-
{
|
|
692
|
-
<
|
|
693
|
-
|
|
694
|
-
<
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
798
|
+
<div>
|
|
799
|
+
<select onChange={e => setSelectedService(Number(e.target.value))}>
|
|
800
|
+
<option>서비스 선택</option>
|
|
801
|
+
{services.map(s => (
|
|
802
|
+
<option key={s.id} value={s.id}>{s.name}</option>
|
|
803
|
+
))}
|
|
804
|
+
</select>
|
|
805
|
+
|
|
806
|
+
<div>
|
|
807
|
+
{dates.map(date => (
|
|
808
|
+
<button key={date} onClick={() => handleDateSelect(date)}>
|
|
809
|
+
{date}
|
|
810
|
+
</button>
|
|
811
|
+
))}
|
|
812
|
+
</div>
|
|
813
|
+
|
|
814
|
+
<div>
|
|
815
|
+
{slots.filter(s => s.available).map(slot => (
|
|
816
|
+
<button key={slot.time}>{slot.time}</button>
|
|
817
|
+
))}
|
|
818
|
+
</div>
|
|
701
819
|
</div>
|
|
702
820
|
);
|
|
703
821
|
}
|
package/dist/index.js
CHANGED
|
@@ -971,14 +971,14 @@ var ReservationResource = class {
|
|
|
971
971
|
* @returns Reservation settings for the tenant
|
|
972
972
|
*/
|
|
973
973
|
async getSettings() {
|
|
974
|
-
return this.http.get("/public/
|
|
974
|
+
return this.http.get("/public/reservation/settings");
|
|
975
975
|
}
|
|
976
976
|
/**
|
|
977
977
|
* List available services
|
|
978
978
|
* @returns Array of services (always an array)
|
|
979
979
|
*/
|
|
980
980
|
async listServices() {
|
|
981
|
-
const response = await this.http.getList("/public/
|
|
981
|
+
const response = await this.http.getList("/public/reservation/services");
|
|
982
982
|
return response.data;
|
|
983
983
|
}
|
|
984
984
|
/**
|
|
@@ -988,7 +988,7 @@ var ReservationResource = class {
|
|
|
988
988
|
*/
|
|
989
989
|
async listStaff(serviceId) {
|
|
990
990
|
const params = serviceId ? { service_id: serviceId } : void 0;
|
|
991
|
-
const response = await this.http.getList("/public/
|
|
991
|
+
const response = await this.http.getList("/public/reservation/staffs", params);
|
|
992
992
|
return response.data;
|
|
993
993
|
}
|
|
994
994
|
/**
|
|
@@ -996,7 +996,7 @@ var ReservationResource = class {
|
|
|
996
996
|
* @returns Array of available date strings (YYYY-MM-DD)
|
|
997
997
|
*/
|
|
998
998
|
async getAvailableDates(params) {
|
|
999
|
-
const response = await this.http.get("/public/
|
|
999
|
+
const response = await this.http.get("/public/reservation/available-dates", params);
|
|
1000
1000
|
return Array.isArray(response) ? response : response?.data ?? [];
|
|
1001
1001
|
}
|
|
1002
1002
|
/**
|
|
@@ -1004,7 +1004,7 @@ var ReservationResource = class {
|
|
|
1004
1004
|
* @returns Array of available slots (always an array)
|
|
1005
1005
|
*/
|
|
1006
1006
|
async getAvailableSlots(params) {
|
|
1007
|
-
const response = await this.http.get("/public/
|
|
1007
|
+
const response = await this.http.get("/public/reservation/available-slots", params);
|
|
1008
1008
|
return Array.isArray(response) ? response : response?.data ?? [];
|
|
1009
1009
|
}
|
|
1010
1010
|
// ============================================
|
package/dist/index.mjs
CHANGED
|
@@ -943,14 +943,14 @@ var ReservationResource = class {
|
|
|
943
943
|
* @returns Reservation settings for the tenant
|
|
944
944
|
*/
|
|
945
945
|
async getSettings() {
|
|
946
|
-
return this.http.get("/public/
|
|
946
|
+
return this.http.get("/public/reservation/settings");
|
|
947
947
|
}
|
|
948
948
|
/**
|
|
949
949
|
* List available services
|
|
950
950
|
* @returns Array of services (always an array)
|
|
951
951
|
*/
|
|
952
952
|
async listServices() {
|
|
953
|
-
const response = await this.http.getList("/public/
|
|
953
|
+
const response = await this.http.getList("/public/reservation/services");
|
|
954
954
|
return response.data;
|
|
955
955
|
}
|
|
956
956
|
/**
|
|
@@ -960,7 +960,7 @@ var ReservationResource = class {
|
|
|
960
960
|
*/
|
|
961
961
|
async listStaff(serviceId) {
|
|
962
962
|
const params = serviceId ? { service_id: serviceId } : void 0;
|
|
963
|
-
const response = await this.http.getList("/public/
|
|
963
|
+
const response = await this.http.getList("/public/reservation/staffs", params);
|
|
964
964
|
return response.data;
|
|
965
965
|
}
|
|
966
966
|
/**
|
|
@@ -968,7 +968,7 @@ var ReservationResource = class {
|
|
|
968
968
|
* @returns Array of available date strings (YYYY-MM-DD)
|
|
969
969
|
*/
|
|
970
970
|
async getAvailableDates(params) {
|
|
971
|
-
const response = await this.http.get("/public/
|
|
971
|
+
const response = await this.http.get("/public/reservation/available-dates", params);
|
|
972
972
|
return Array.isArray(response) ? response : response?.data ?? [];
|
|
973
973
|
}
|
|
974
974
|
/**
|
|
@@ -976,7 +976,7 @@ var ReservationResource = class {
|
|
|
976
976
|
* @returns Array of available slots (always an array)
|
|
977
977
|
*/
|
|
978
978
|
async getAvailableSlots(params) {
|
|
979
|
-
const response = await this.http.get("/public/
|
|
979
|
+
const response = await this.http.get("/public/reservation/available-slots", params);
|
|
980
980
|
return Array.isArray(response) ? response : response?.data ?? [];
|
|
981
981
|
}
|
|
982
982
|
// ============================================
|