@ph-cms/client-sdk 0.1.36 → 0.1.38

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,4 +1,4 @@
1
- # @ph-cms/client-sdk 0.1.35
1
+ # @ph-cms/client-sdk 0.1.38
2
2
 
3
3
  PH-CMS 클라이언트 SDK — 브라우저 및 React 애플리케이션을 위한 통합 클라이언트.
4
4
 
@@ -458,7 +458,7 @@ function AuthComponent() {
458
458
  loginWithFirebase, // (data: FirebaseExchangeRequest) => Promise<AuthResponse>
459
459
  register, // (data: RegisterInput) => Promise<AuthResponse> ← method: 'email' | 'firebase'
460
460
  loginAnonymous, // (data?: AnonymousLoginRequest) => Promise<AuthResponse>
461
- upgradeAnonymous, // (data: { email, password, display_name?, username? }) => Promise<UserDto>
461
+ upgradeAnonymous, // (data: { email, password, display_name?, username?, phone_number? }) => Promise<UserDto>
462
462
  logout, // () => Promise<void>
463
463
 
464
464
  // 뮤테이션 상태 (isPending, error 등)
@@ -614,9 +614,9 @@ function FirebaseGuestButton() {
614
614
  function UpgradeForm() {
615
615
  const { upgradeAnonymous, upgradeAnonymousStatus, user } = useAuth();
616
616
 
617
- const handleUpgrade = async (email: string, password: string, displayName: string) => {
618
- await upgradeAnonymous({ email, password, display_name: displayName });
619
- // 성공 → role에서 'anonymous' 제거됨 → 기존 히스토리 유지
617
+ const handleUpgrade = async (email: string, password: string, displayName: string, phoneNumber?: string) => {
618
+ await upgradeAnonymous({ email, password, display_name: displayName, phone_number: phoneNumber });
619
+ // 성공 → role ['user']로 전환됨 → 기존 히스토리 유지
620
620
  };
621
621
 
622
622
  if (!user?.role.includes('anonymous')) return null;
@@ -629,11 +629,13 @@ function UpgradeForm() {
629
629
  fd.get('email') as string,
630
630
  fd.get('password') as string,
631
631
  fd.get('display_name') as string,
632
+ fd.get('phone_number') as string || undefined,
632
633
  );
633
634
  }}>
634
635
  <input name="email" type="email" placeholder="이메일" />
635
636
  <input name="password" type="password" placeholder="비밀번호" />
636
637
  <input name="display_name" placeholder="이름" />
638
+ <input name="phone_number" placeholder="전화번호 (선택)" />
637
639
  <button type="submit" disabled={upgradeAnonymousStatus.isPending}>
638
640
  {upgradeAnonymousStatus.isPending ? '전환 중...' : '계정 만들기'}
639
641
  </button>
@@ -762,6 +764,28 @@ function MyComponent() {
762
764
  }
763
765
  ```
764
766
 
767
+ ### Liked Contents (`useLikedContents`)
768
+
769
+ 특정 사용자가 좋아요를 누른 콘텐츠 목록을 조회합니다.
770
+
771
+ ```tsx
772
+ import { useLikedContents } from '@ph-cms/client-sdk';
773
+
774
+ function UserLikedContents({ userUid }) {
775
+ const { data, isLoading } = useLikedContents(userUid, { type: 'post', page: 1, limit: 10 });
776
+
777
+ if (isLoading) return <div>Loading...</div>;
778
+
779
+ return (
780
+ <ul>
781
+ {data?.content.map(item => (
782
+ <li key={item.uid}>{item.title}</li>
783
+ ))}
784
+ </ul>
785
+ );
786
+ }
787
+ ```
788
+
765
789
  ### Public Profile (`useUserProfile`)
766
790
 
767
791
  다른 사용자의 공개 프로필(이름, 아바타, 자기소개 등)을 조회할 때 사용하는 훅입니다.
@@ -783,6 +807,28 @@ function UserProfileCard({ userId }) {
783
807
  </div>
784
808
  );
785
809
  }
810
+
811
+ ### `useLikedStats` (Liked Statistics)
812
+
813
+ 특정 사용자가 좋아요를 누른 콘텐츠의 타입별 통계를 조회합니다.
814
+
815
+ ```tsx
816
+ import { useLikedStats } from '@ph-cms/client-sdk';
817
+
818
+ function UserLikedStats({ userUid }) {
819
+ const { data: stats, isLoading } = useLikedStats(userUid);
820
+
821
+ if (isLoading) return <div>Loading...</div>;
822
+
823
+ return (
824
+ <ul>
825
+ {stats?.map(item => (
826
+ <li key={item.type}>{item.type}: {item.count}</li>
827
+ ))}
828
+ </ul>
829
+ );
830
+ }
831
+ ```
786
832
  ```
787
833
 
788
834
  ### Profile Update (`useUpdateProfile`)
@@ -1099,6 +1145,10 @@ const likers = await client.content.getLikers('content-uid', { page: 1, limit: 1
1099
1145
  // 2. 특정 사용자가 좋아요를 누른 콘텐츠 목록 (타입 필터링 지원)
1100
1146
  const likedContents = await client.user.getLikedContents('user-uid', { type: 'post', page: 1 });
1101
1147
  // => PagedContentListResponse
1148
+
1149
+ // 3. 특정 사용자가 좋아요를 누른 콘텐츠 타입별 통계
1150
+ const likedStats = await client.user.getLikedStats('user-uid');
1151
+ // => [{ type: 'post', count: 5 }, { type: 'place', count: 2 }]
1102
1152
  ```
1103
1153
 
1104
1154
  ## Stamp Tour
@@ -1516,6 +1566,7 @@ const result = await content.list({ channelUid: 'my-channel' });
1516
1566
  | `getProfile(uid: string)` | 유저의 공개 프로필 정보 조회 → `UserProfileDto` |
1517
1567
  | `updateProfile(uid: string, data: UpdateUserProfileRequest)` | 유저의 프로필 정보 업데이트 → `UserDto` |
1518
1568
  | `getLikedContents(uid: string, params?: Partial<ListLikedContentQuery>)` | 사용자가 좋아요 누른 콘텐츠 목록 조회 → `PagedContentListResponse` |
1569
+ | `getLikedStats(uid: string)` | 사용자가 좋아요 누른 콘텐츠 타입별 통계 조회 → `LikedStatsByTypeResponse` |
1519
1570
 
1520
1571
  ### `AuthModule` (`client.auth`)
1521
1572
 
@@ -1525,6 +1576,8 @@ const result = await content.list({ channelUid: 'my-channel' });
1525
1576
  | `loginWithFirebase(data: FirebaseExchangeRequest)` | Firebase ID 토큰 교환 → `AuthResponse` |
1526
1577
  | `register(data: RegisterRequest)` | 이메일 회원가입 → `AuthResponse` (`channelUid` \| `channelSlug` 필수, `phone_number` 지원) |
1527
1578
  | `registerWithFirebase(data: FirebaseRegisterRequest)` | 서버 사이드 Firebase 회원가입 → `AuthResponse` (`channelUid` \| `channelSlug` 필수, `phone_number` 지원) |
1579
+ | `loginAnonymous(data?: AnonymousLoginRequest)` | 익명 계정 생성/로그인 → `AuthResponse` |
1580
+ | `upgradeAnonymous(data: { email, password, display_name?, username?, phone_number? })` | 익명 → 정식 이메일 계정 전환 → `UserDto` (role: `['user']`) |
1528
1581
  | `me(params?: { channelUid?: string })` | 현재 사용자 프로필 조회 → `UserDto` |
1529
1582
  | `refresh(refreshToken: string)` | 토큰 갱신 → `{ accessToken, refreshToken }` |
1530
1583
  | `logout()` | 로그아웃 (프로바이더 토큰 삭제 + 서버 세션 무효화) |
@@ -238,6 +238,7 @@ export declare const useAuth: () => {
238
238
  password: string;
239
239
  display_name?: string;
240
240
  username?: string;
241
+ phone_number?: string;
241
242
  }, unknown>;
242
243
  logout: import("@tanstack/react-query").UseMutateAsyncFunction<void, Error, void, unknown>;
243
244
  getToken: () => Promise<string | null>;
@@ -429,6 +430,7 @@ export declare const useAuth: () => {
429
430
  password: string;
430
431
  display_name?: string;
431
432
  username?: string;
433
+ phone_number?: string;
432
434
  }, unknown>;
433
435
  logoutStatus: import("@tanstack/react-query").UseMutationResult<void, Error, void, unknown>;
434
436
  };
@@ -546,5 +548,6 @@ export declare const useUpgradeAnonymous: () => import("@tanstack/react-query").
546
548
  password: string;
547
549
  display_name?: string;
548
550
  username?: string;
551
+ phone_number?: string;
549
552
  }, unknown>;
550
553
  export {};
@@ -1,4 +1,4 @@
1
- import { UpdateUserProfileRequest } from '@ph-cms/api-contract';
1
+ import { ListLikedContentQuery, UpdateUserProfileRequest } from '@ph-cms/api-contract';
2
2
  export declare const termsKeys: {
3
3
  all: readonly ["terms"];
4
4
  lists: () => readonly ["terms", "list"];
@@ -92,6 +92,26 @@ export declare const useUpdateProfile: () => import("@tanstack/react-query").Use
92
92
  uid: string;
93
93
  data: UpdateUserProfileRequest | Record<string, any>;
94
94
  }, unknown>;
95
+ /**
96
+ * Hook to fetch contents liked by a specific user.
97
+ */
98
+ export declare const useLikedContents: (uid: string, params?: Partial<ListLikedContentQuery>) => import("@tanstack/react-query").UseQueryResult<{
99
+ number: number;
100
+ totalPages: number;
101
+ content: import("@ph-cms/api-contract").ContentDto[];
102
+ size: number;
103
+ totalElements: number;
104
+ first: boolean;
105
+ last: boolean;
106
+ empty: boolean;
107
+ }, Error>;
108
+ /**
109
+ * Hook to fetch statistics of liked contents by type for a specific user.
110
+ */
111
+ export declare const useLikedStats: (uid: string) => import("@tanstack/react-query").UseQueryResult<{
112
+ type: string;
113
+ count: number;
114
+ }[], Error>;
95
115
  /**
96
116
  * List terms required/available for the current channel.
97
117
  */
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.useAgreeTerms = exports.useChannelTerms = exports.useUpdateProfile = exports.useUserProfile = exports.useUser = exports.termsKeys = void 0;
3
+ exports.useAgreeTerms = exports.useChannelTerms = exports.useLikedStats = exports.useLikedContents = exports.useUpdateProfile = exports.useUserProfile = exports.useUser = exports.termsKeys = void 0;
4
4
  const react_query_1 = require("@tanstack/react-query");
5
5
  const context_1 = require("../context");
6
6
  exports.termsKeys = {
@@ -43,6 +43,30 @@ const useUpdateProfile = () => {
43
43
  });
44
44
  };
45
45
  exports.useUpdateProfile = useUpdateProfile;
46
+ /**
47
+ * Hook to fetch contents liked by a specific user.
48
+ */
49
+ const useLikedContents = (uid, params = {}) => {
50
+ const client = (0, context_1.usePHCMS)();
51
+ return (0, react_query_1.useQuery)({
52
+ queryKey: ['user-liked-contents', uid, params],
53
+ queryFn: () => client.user.getLikedContents(uid, params),
54
+ enabled: !!uid,
55
+ });
56
+ };
57
+ exports.useLikedContents = useLikedContents;
58
+ /**
59
+ * Hook to fetch statistics of liked contents by type for a specific user.
60
+ */
61
+ const useLikedStats = (uid) => {
62
+ const client = (0, context_1.usePHCMS)();
63
+ return (0, react_query_1.useQuery)({
64
+ queryKey: ['user-liked-stats', uid],
65
+ queryFn: () => client.user.getLikedStats(uid),
66
+ enabled: !!uid,
67
+ });
68
+ };
69
+ exports.useLikedStats = useLikedStats;
46
70
  /**
47
71
  * List terms required/available for the current channel.
48
72
  */
@@ -36,6 +36,7 @@ export declare class AuthModule {
36
36
  password: string;
37
37
  display_name?: string;
38
38
  username?: string;
39
+ phone_number?: string;
39
40
  }): Promise<UserDto>;
40
41
  logout(): Promise<void>;
41
42
  }
@@ -1,4 +1,4 @@
1
- import { ListLikedContentQuery, PagedContentListResponse, UpdateUserProfileRequest, UserDto, UserProfileDto } from "@ph-cms/api-contract";
1
+ import { LikedStatsByTypeResponse, ListLikedContentQuery, PagedContentListResponse, UpdateUserProfileRequest, UserDto, UserProfileDto } from "@ph-cms/api-contract";
2
2
  import { AxiosInstance } from "axios";
3
3
  export declare class UserModule {
4
4
  private client;
@@ -28,4 +28,10 @@ export declare class UserModule {
28
28
  * @param params - Query parameters for filtering and pagination.
29
29
  */
30
30
  getLikedContents(uid: string, params?: Partial<ListLikedContentQuery>): Promise<PagedContentListResponse>;
31
+ /**
32
+ * Retrieves statistics of liked contents by type for a specific user.
33
+ *
34
+ * @param uid - The UID of the user.
35
+ */
36
+ getLikedStats(uid: string): Promise<LikedStatsByTypeResponse>;
31
37
  }
@@ -44,5 +44,15 @@ class UserModule {
44
44
  }
45
45
  return this.client.get(`${this.prefix}/users/${uid}/liked-contents`, { params });
46
46
  }
47
+ /**
48
+ * Retrieves statistics of liked contents by type for a specific user.
49
+ *
50
+ * @param uid - The UID of the user.
51
+ */
52
+ async getLikedStats(uid) {
53
+ if (!uid)
54
+ throw new errors_1.ValidationError("UID is required", []);
55
+ return this.client.get(`${this.prefix}/users/${uid}/liked-stats`);
56
+ }
47
57
  }
48
58
  exports.UserModule = UserModule;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ph-cms/client-sdk",
3
- "version": "0.1.36",
3
+ "version": "0.1.38",
4
4
  "description": "Unified PH-CMS Client SDK (React + Core)",
5
5
  "keywords": [],
6
6
  "license": "MIT",
@@ -30,7 +30,7 @@
30
30
  "LICENSE"
31
31
  ],
32
32
  "dependencies": {
33
- "@ph-cms/api-contract": "^0.1.14",
33
+ "@ph-cms/api-contract": "^0.1.15",
34
34
  "@tanstack/react-query": "^5.0.0",
35
35
  "axios": "^1.6.0",
36
36
  "zod": "^3.22.4"