@ph-cms/client-sdk 0.1.50 → 0.1.51

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
@@ -106,9 +106,22 @@ import type {
106
106
  // Common
107
107
  PagedResponse,
108
108
  UserProfileDto,
109
+ UserSearchResultDto,
109
110
  IntegratedPlace,
110
111
  PlaceSearchQuery,
111
112
  PlaceSearchResponse,
113
+
114
+ // User Group
115
+ UserGroupDto,
116
+ UserGroupMembershipDto,
117
+ UserGroupInviteDto,
118
+ UserGroupInviteStatus,
119
+ ListUserGroupQuery,
120
+ GetMyUserGroupMembershipResponse,
121
+ PagedMyGroupInviteListResponse,
122
+ JoinUserGroupResponse,
123
+ LeaveUserGroupResponse,
124
+ RespondInviteResponse,
112
125
  } from '@ph-cms/client-sdk';
113
126
  ```
114
127
 
@@ -1837,7 +1850,7 @@ const result = await content.list({ channelUid: 'my-channel' });
1837
1850
  | 카테고리 | export 항목 |
1838
1851
  |---|---|
1839
1852
  | 클라이언트 | `PHCMSClient` |
1840
- | 모듈 | `ContentModule`, `AuthModule`, `UserModule`, `ChannelModule`, `MediaModule`, `TermsModule` |
1853
+ | 모듈 | `ContentModule`, `AuthModule`, `UserModule`, `ChannelModule`, `MediaModule`, `TermsModule`, `UserGroupModule` |
1841
1854
  | Auth 프로바이더 | `BaseAuthProvider`, `LocalAuthProvider`, `JwtUtils` |
1842
1855
  | 타입/에러 | `PHCMSClientError`, 각종 DTO/Request 타입 |
1843
1856
 
@@ -1848,6 +1861,7 @@ const result = await content.list({ channelUid: 'my-channel' });
1848
1861
  | 메서드 | 설명 |
1849
1862
  |---|---|
1850
1863
  | `getProfile(uid: string)` | 유저의 공개 프로필 정보 조회 → `UserProfileDto` |
1864
+ | `search(query, params?)` | 이름/아이디/이메일 키워드로 사용자 검색 → `UserSearchResultDto[]` |
1851
1865
  | `getFollowStatus(uid: string)` | 현재 로그인 사용자의 대상 유저 팔로우 상태 조회 → `FollowStatusResponse` |
1852
1866
  | `follow(uid: string)` | 특정 사용자 팔로우 → `FollowUserResponse` |
1853
1867
  | `unfollow(uid: string)` | 특정 사용자 언팔로우 → `FollowUserResponse` |
@@ -1862,6 +1876,18 @@ const result = await content.list({ channelUid: 'my-channel' });
1862
1876
  | `suspend(uid: string, data?: SuspendUserRequest)` | 유저 활동 정지 (글로벌 밴) → `SuspendUserResponse` |
1863
1877
  | `unsuspend(uid: string)` | 유저 활동 정지 해제 → `SuspendUserResponse` |
1864
1878
 
1879
+ 예시:
1880
+
1881
+ ```ts
1882
+ const users = await client.user.search('hong', { limit: 10 });
1883
+ ```
1884
+
1885
+ React hook 예시:
1886
+
1887
+ ```ts
1888
+ const { data: users } = useUserSearch('hong', { limit: 10 });
1889
+ ```
1890
+
1865
1891
  ### `AuthModule` (`client.auth`)
1866
1892
 
1867
1893
  | 메서드 | 설명 |
@@ -1930,6 +1956,46 @@ await client.content.get('cnt_123', { withParent: true, withDetail: true });
1930
1956
  | `agree(data: { termCodes: string[]; channelUid?: string })` | 약관 동의 제출 |
1931
1957
  | `listByChannel(channelUid: string)` | 채널별 약관 목록 조회 |
1932
1958
 
1959
+ ### `UserGroupModule` (`client.userGroup`)
1960
+
1961
+ | 메서드 | 설명 |
1962
+ |---|---|
1963
+ | `listByBaseContent(baseContentUid, params?)` | 기준 콘텐츠에 연결된 공개 그룹 목록 조회 → `PagedUserGroupListResponse` |
1964
+ | `getMyMembership(baseContentUid, groupUid)` | 현재 사용자의 특정 그룹 가입 여부 조회 → `GetMyUserGroupMembershipResponse` |
1965
+ | `join(baseContentUid, groupUid)` | 그룹 self join → `JoinUserGroupResponse` |
1966
+ | `leave(baseContentUid, groupUid)` | 그룹 탈퇴 → `LeaveUserGroupResponse` |
1967
+ | `listMine(params?)` | 현재 사용자가 가입한 그룹 목록 조회 → `PagedMyUserGroupMembershipListResponse` |
1968
+ | `listMyInvites(params?)` | 현재 사용자의 그룹 초대 목록 조회 → `PagedMyGroupInviteListResponse` |
1969
+ | `acceptInvite(inviteUid)` | 그룹 초대 수락 → `RespondInviteResponse` |
1970
+ | `declineInvite(inviteUid)` | 그룹 초대 거절 → `RespondInviteResponse` |
1971
+
1972
+ 예시:
1973
+
1974
+ ```ts
1975
+ const groups = await client.userGroup.listByBaseContent(baseContentUid, {
1976
+ limit: 20,
1977
+ offset: 0,
1978
+ });
1979
+
1980
+ const joined = await client.userGroup.join(baseContentUid, groupUid);
1981
+
1982
+ const invites = await client.userGroup.listMyInvites({ limit: 20, offset: 0 });
1983
+
1984
+ await client.userGroup.acceptInvite('invite_123');
1985
+ await client.userGroup.declineInvite('invite_123');
1986
+ ```
1987
+
1988
+ React hook 예시:
1989
+
1990
+ ```ts
1991
+ const { data: myInvites } = useMyUserGroupInvites({ limit: 20 });
1992
+ const acceptInvite = useAcceptUserGroupInvite();
1993
+ const declineInvite = useDeclineUserGroupInvite();
1994
+
1995
+ await acceptInvite.mutateAsync({ inviteUid: 'inv_123' });
1996
+ await declineInvite.mutateAsync({ inviteUid: 'inv_123' });
1997
+ ```
1998
+
1933
1999
  ### JWT Utilities
1934
2000
 
1935
2001
  클라이언트에서 토큰 상태를 확인할 수 있는 유틸리티입니다 (서명 검증은 하지 않음).
package/dist/client.d.ts CHANGED
@@ -6,6 +6,7 @@ import { ContentModule } from './modules/content';
6
6
  import { MediaModule } from './modules/media';
7
7
  import { PlaceModule } from './modules/place';
8
8
  import { TermsModule } from './modules/terms';
9
+ import { UserGroupModule } from './modules/user-group';
9
10
  import { UserModule } from './modules/user';
10
11
  export interface PHCMSClientConfig {
11
12
  baseURL: string;
@@ -28,6 +29,7 @@ export declare class PHCMSClient {
28
29
  readonly media: MediaModule;
29
30
  readonly place: PlaceModule;
30
31
  readonly user: UserModule;
32
+ readonly userGroup: UserGroupModule;
31
33
  /**
32
34
  * Whether a token refresh is currently in flight (used by the 401
33
35
  * interceptor to de-duplicate concurrent refresh attempts).
package/dist/client.js CHANGED
@@ -13,6 +13,7 @@ const content_1 = require("./modules/content");
13
13
  const media_1 = require("./modules/media");
14
14
  const place_1 = require("./modules/place");
15
15
  const terms_1 = require("./modules/terms");
16
+ const user_group_1 = require("./modules/user-group");
16
17
  const user_1 = require("./modules/user");
17
18
  class PHCMSClient {
18
19
  /** Exposes the auth provider so UI layers can check token state synchronously. */
@@ -71,6 +72,7 @@ class PHCMSClient {
71
72
  this.media = new media_1.MediaModule(this.axiosInstance, normalizedApiPrefix);
72
73
  this.place = new place_1.PlaceModule(this.axiosInstance, normalizedApiPrefix);
73
74
  this.user = new user_1.UserModule(this.axiosInstance, normalizedApiPrefix);
75
+ this.userGroup = new user_group_1.UserGroupModule(this.axiosInstance, normalizedApiPrefix);
74
76
  // Wire the refresh function into the auth provider so it can
75
77
  // proactively refresh tokens inside `getToken()` without needing
76
78
  // a direct reference to the AuthModule / axios instance.
package/dist/core.d.ts CHANGED
@@ -10,5 +10,6 @@ export * from './modules/content';
10
10
  export * from './modules/media';
11
11
  export * from './modules/place';
12
12
  export * from './modules/terms';
13
+ export * from './modules/user-group';
13
14
  export * from './modules/user';
14
15
  export * from './types';
package/dist/core.js CHANGED
@@ -29,5 +29,6 @@ __exportStar(require("./modules/content"), exports);
29
29
  __exportStar(require("./modules/media"), exports);
30
30
  __exportStar(require("./modules/place"), exports);
31
31
  __exportStar(require("./modules/terms"), exports);
32
+ __exportStar(require("./modules/user-group"), exports);
32
33
  __exportStar(require("./modules/user"), exports);
33
34
  __exportStar(require("./types"), exports);
@@ -1,4 +1,5 @@
1
1
  import { ListLikedContentQuery, ListUserFollowQuery, UpdateUserProfileRequest, BlockUserRequest, SuspendUserRequest } from '@ph-cms/api-contract';
2
+ import { UserSearchResultDto } from '../types';
2
3
  export declare const termsKeys: {
3
4
  all: readonly ["terms"];
4
5
  lists: () => readonly ["terms", "list"];
@@ -15,6 +16,11 @@ export declare const userKeys: {
15
16
  page: number;
16
17
  limit: number;
17
18
  }>];
19
+ search: (query: string, params: {
20
+ limit?: number;
21
+ }) => readonly ["users", "search", string, {
22
+ limit?: number;
23
+ }];
18
24
  };
19
25
  /**
20
26
  * Access the current user profile and status.
@@ -108,6 +114,12 @@ export declare const useFollowings: (uid: string, params?: Partial<ListUserFollo
108
114
  limit: number;
109
115
  totalPages: number;
110
116
  }>, Error>;
117
+ /**
118
+ * Hook to search users by keyword.
119
+ */
120
+ export declare const useUserSearch: (query: string, params?: {
121
+ limit?: number;
122
+ }, enabled?: boolean) => import("@tanstack/react-query").UseQueryResult<NoInfer<UserSearchResultDto[]>, Error>;
111
123
  /**
112
124
  * Hook to update a user's profile.
113
125
  * Typically used by a user to update their own profile.
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.useUnsuspendUser = exports.useSuspendUser = exports.useBlockedUsers = exports.useUnblockUser = exports.useBlockUser = exports.useAgreeTerms = exports.useChannelTerms = exports.useLikedStats = exports.useLikedContents = exports.useUnfollowUser = exports.useFollowUser = exports.useUpdateProfile = exports.useFollowings = exports.useFollowers = exports.useFollowStatus = exports.useUserProfile = exports.useUser = exports.userKeys = exports.termsKeys = void 0;
3
+ exports.useUnsuspendUser = exports.useSuspendUser = exports.useBlockedUsers = exports.useUnblockUser = exports.useBlockUser = exports.useAgreeTerms = exports.useChannelTerms = exports.useLikedStats = exports.useLikedContents = exports.useUnfollowUser = exports.useFollowUser = exports.useUpdateProfile = exports.useUserSearch = exports.useFollowings = exports.useFollowers = exports.useFollowStatus = exports.useUserProfile = exports.useUser = exports.userKeys = 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 = {
@@ -13,6 +13,7 @@ exports.userKeys = {
13
13
  followStatus: (uid) => [...exports.userKeys.all, 'follow-status', uid],
14
14
  followers: (uid, params) => [...exports.userKeys.all, 'followers', uid, params],
15
15
  followings: (uid, params) => [...exports.userKeys.all, 'followings', uid, params],
16
+ search: (query, params) => [...exports.userKeys.all, 'search', query, params],
16
17
  };
17
18
  /**
18
19
  * Access the current user profile and status.
@@ -70,6 +71,19 @@ const useFollowings = (uid, params = {}, enabled = true) => {
70
71
  });
71
72
  };
72
73
  exports.useFollowings = useFollowings;
74
+ /**
75
+ * Hook to search users by keyword.
76
+ */
77
+ const useUserSearch = (query, params = {}, enabled = true) => {
78
+ const client = (0, context_1.usePHCMS)();
79
+ const normalizedQuery = query.trim();
80
+ return (0, react_query_1.useQuery)({
81
+ queryKey: exports.userKeys.search(normalizedQuery, params),
82
+ queryFn: () => client.user.search(normalizedQuery, params),
83
+ enabled: !!normalizedQuery && enabled,
84
+ });
85
+ };
86
+ exports.useUserSearch = useUserSearch;
73
87
  /**
74
88
  * Hook to update a user's profile.
75
89
  * Typically used by a user to update their own profile.
@@ -0,0 +1,122 @@
1
+ import { ListUserGroupQuery } from "@ph-cms/api-contract";
2
+ export declare const userGroupKeys: {
3
+ all: readonly ["user-groups"];
4
+ publicLists: () => readonly ["user-groups", "public", "list"];
5
+ publicListPrefix: (baseContentUid: string) => readonly ["user-groups", "public", "list", string];
6
+ publicList: (baseContentUid: string, params?: ListUserGroupQuery) => readonly ["user-groups", "public", "list", string, {
7
+ limit?: number | undefined;
8
+ offset?: number | undefined;
9
+ }];
10
+ myMembership: (baseContentUid: string, groupUid: string) => readonly ["user-groups", "me", string, string];
11
+ myGroups: (params?: ListUserGroupQuery) => readonly ["user-groups", "my-groups", {
12
+ limit?: number | undefined;
13
+ offset?: number | undefined;
14
+ }];
15
+ myInvites: (params?: ListUserGroupQuery) => readonly ["user-groups", "my-invites", {
16
+ limit?: number | undefined;
17
+ offset?: number | undefined;
18
+ }];
19
+ };
20
+ export declare const useBaseContentUserGroups: (baseContentUid: string, params?: ListUserGroupQuery, enabled?: boolean) => import("@tanstack/react-query").UseQueryResult<NoInfer<{
21
+ items: {
22
+ isActive: boolean;
23
+ createdAt: string;
24
+ uid: string;
25
+ channelUid: string;
26
+ name: string;
27
+ description: string | null;
28
+ baseContentUid: string;
29
+ groupCode: string;
30
+ joinMode: "open" | "invite_only" | "approval";
31
+ updatedAt: string;
32
+ joined?: boolean | undefined;
33
+ }[];
34
+ total: number;
35
+ page: number;
36
+ limit: number;
37
+ totalPages: number;
38
+ }>, Error>;
39
+ export declare const useMyUserGroupMembership: (baseContentUid: string, groupUid: string, enabled?: boolean) => import("@tanstack/react-query").UseQueryResult<NoInfer<{
40
+ isJoined: boolean;
41
+ membership: {
42
+ baseContentUid: string;
43
+ groupCode: string;
44
+ membershipUid: string;
45
+ groupUid: string;
46
+ groupName: string;
47
+ baseContentType: string;
48
+ baseContentTitle: string;
49
+ baseContentImage: string | null;
50
+ baseContentSlug: string | null;
51
+ joinedAt: string;
52
+ } | null;
53
+ }>, Error>;
54
+ export declare const useMyUserGroups: (params?: ListUserGroupQuery, enabled?: boolean) => import("@tanstack/react-query").UseQueryResult<NoInfer<{
55
+ items: {
56
+ baseContentUid: string;
57
+ groupCode: string;
58
+ membershipUid: string;
59
+ groupUid: string;
60
+ groupName: string;
61
+ baseContentType: string;
62
+ baseContentTitle: string;
63
+ baseContentImage: string | null;
64
+ baseContentSlug: string | null;
65
+ joinedAt: string;
66
+ }[];
67
+ total: number;
68
+ page: number;
69
+ limit: number;
70
+ totalPages: number;
71
+ }>, Error>;
72
+ export declare const useMyUserGroupInvites: (params?: ListUserGroupQuery, enabled?: boolean) => import("@tanstack/react-query").UseQueryResult<NoInfer<{
73
+ items: {
74
+ status: "pending" | "accepted" | "declined";
75
+ createdAt: string;
76
+ uid: string;
77
+ baseContentUid: string;
78
+ groupCode: string;
79
+ updatedAt: string;
80
+ groupUid: string;
81
+ groupName: string;
82
+ inviterUid: string;
83
+ }[];
84
+ total: number;
85
+ page: number;
86
+ limit: number;
87
+ totalPages: number;
88
+ }>, Error>;
89
+ export declare const useJoinUserGroup: () => import("@tanstack/react-query").UseMutationResult<{
90
+ joined: boolean;
91
+ membership: {
92
+ baseContentUid: string;
93
+ groupCode: string;
94
+ membershipUid: string;
95
+ groupUid: string;
96
+ groupName: string;
97
+ baseContentType: string;
98
+ baseContentTitle: string;
99
+ baseContentImage: string | null;
100
+ baseContentSlug: string | null;
101
+ joinedAt: string;
102
+ };
103
+ }, Error, {
104
+ baseContentUid: string;
105
+ groupUid: string;
106
+ }, unknown>;
107
+ export declare const useLeaveUserGroup: () => import("@tanstack/react-query").UseMutationResult<{
108
+ left: boolean;
109
+ }, Error, {
110
+ baseContentUid: string;
111
+ groupUid: string;
112
+ }, unknown>;
113
+ export declare const useAcceptUserGroupInvite: () => import("@tanstack/react-query").UseMutationResult<{
114
+ success: boolean;
115
+ }, Error, {
116
+ inviteUid: string;
117
+ }, unknown>;
118
+ export declare const useDeclineUserGroupInvite: () => import("@tanstack/react-query").UseMutationResult<{
119
+ success: boolean;
120
+ }, Error, {
121
+ inviteUid: string;
122
+ }, unknown>;
@@ -0,0 +1,126 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useDeclineUserGroupInvite = exports.useAcceptUserGroupInvite = exports.useLeaveUserGroup = exports.useJoinUserGroup = exports.useMyUserGroupInvites = exports.useMyUserGroups = exports.useMyUserGroupMembership = exports.useBaseContentUserGroups = exports.userGroupKeys = void 0;
4
+ const react_query_1 = require("@tanstack/react-query");
5
+ const context_1 = require("../context");
6
+ exports.userGroupKeys = {
7
+ all: ["user-groups"],
8
+ publicLists: () => [...exports.userGroupKeys.all, "public", "list"],
9
+ publicListPrefix: (baseContentUid) => [...exports.userGroupKeys.publicLists(), baseContentUid],
10
+ publicList: (baseContentUid, params = {}) => [...exports.userGroupKeys.publicLists(), baseContentUid, params],
11
+ myMembership: (baseContentUid, groupUid) => [...exports.userGroupKeys.all, "me", baseContentUid, groupUid],
12
+ myGroups: (params = {}) => [...exports.userGroupKeys.all, "my-groups", params],
13
+ myInvites: (params = {}) => [...exports.userGroupKeys.all, "my-invites", params],
14
+ };
15
+ const useBaseContentUserGroups = (baseContentUid, params = {}, enabled = true) => {
16
+ const client = (0, context_1.usePHCMS)();
17
+ return (0, react_query_1.useQuery)({
18
+ queryKey: exports.userGroupKeys.publicList(baseContentUid, params),
19
+ queryFn: () => client.userGroup.listByBaseContent(baseContentUid, params),
20
+ enabled: !!baseContentUid && enabled,
21
+ });
22
+ };
23
+ exports.useBaseContentUserGroups = useBaseContentUserGroups;
24
+ const useMyUserGroupMembership = (baseContentUid, groupUid, enabled = true) => {
25
+ const client = (0, context_1.usePHCMS)();
26
+ return (0, react_query_1.useQuery)({
27
+ queryKey: exports.userGroupKeys.myMembership(baseContentUid, groupUid),
28
+ queryFn: () => client.userGroup.getMyMembership(baseContentUid, groupUid),
29
+ enabled: !!baseContentUid && !!groupUid && enabled,
30
+ });
31
+ };
32
+ exports.useMyUserGroupMembership = useMyUserGroupMembership;
33
+ const useMyUserGroups = (params = {}, enabled = true) => {
34
+ const client = (0, context_1.usePHCMS)();
35
+ return (0, react_query_1.useQuery)({
36
+ queryKey: exports.userGroupKeys.myGroups(params),
37
+ queryFn: () => client.userGroup.listMine(params),
38
+ enabled,
39
+ });
40
+ };
41
+ exports.useMyUserGroups = useMyUserGroups;
42
+ const useMyUserGroupInvites = (params = {}, enabled = true) => {
43
+ const client = (0, context_1.usePHCMS)();
44
+ return (0, react_query_1.useQuery)({
45
+ queryKey: exports.userGroupKeys.myInvites(params),
46
+ queryFn: () => client.userGroup.listMyInvites(params),
47
+ enabled,
48
+ });
49
+ };
50
+ exports.useMyUserGroupInvites = useMyUserGroupInvites;
51
+ const useJoinUserGroup = () => {
52
+ const client = (0, context_1.usePHCMS)();
53
+ const queryClient = (0, react_query_1.useQueryClient)();
54
+ return (0, react_query_1.useMutation)({
55
+ mutationFn: ({ baseContentUid, groupUid }) => client.userGroup.join(baseContentUid, groupUid),
56
+ onSuccess: (_data, variables) => {
57
+ queryClient.invalidateQueries({
58
+ queryKey: exports.userGroupKeys.publicListPrefix(variables.baseContentUid),
59
+ });
60
+ queryClient.invalidateQueries({
61
+ queryKey: exports.userGroupKeys.myMembership(variables.baseContentUid, variables.groupUid),
62
+ });
63
+ queryClient.invalidateQueries({
64
+ queryKey: [...exports.userGroupKeys.all, "my-groups"],
65
+ });
66
+ },
67
+ });
68
+ };
69
+ exports.useJoinUserGroup = useJoinUserGroup;
70
+ const useLeaveUserGroup = () => {
71
+ const client = (0, context_1.usePHCMS)();
72
+ const queryClient = (0, react_query_1.useQueryClient)();
73
+ return (0, react_query_1.useMutation)({
74
+ mutationFn: ({ baseContentUid, groupUid }) => client.userGroup.leave(baseContentUid, groupUid),
75
+ onSuccess: (_data, variables) => {
76
+ queryClient.invalidateQueries({
77
+ queryKey: exports.userGroupKeys.publicListPrefix(variables.baseContentUid),
78
+ });
79
+ queryClient.invalidateQueries({
80
+ queryKey: exports.userGroupKeys.myMembership(variables.baseContentUid, variables.groupUid),
81
+ });
82
+ queryClient.invalidateQueries({
83
+ queryKey: [...exports.userGroupKeys.all, "my-groups"],
84
+ });
85
+ },
86
+ });
87
+ };
88
+ exports.useLeaveUserGroup = useLeaveUserGroup;
89
+ const useAcceptUserGroupInvite = () => {
90
+ const client = (0, context_1.usePHCMS)();
91
+ const queryClient = (0, react_query_1.useQueryClient)();
92
+ return (0, react_query_1.useMutation)({
93
+ mutationFn: ({ inviteUid }) => client.userGroup.acceptInvite(inviteUid),
94
+ onSuccess: () => {
95
+ queryClient.invalidateQueries({
96
+ queryKey: [...exports.userGroupKeys.all, "my-invites"],
97
+ });
98
+ queryClient.invalidateQueries({
99
+ queryKey: [...exports.userGroupKeys.all, "my-groups"],
100
+ });
101
+ queryClient.invalidateQueries({
102
+ queryKey: [...exports.userGroupKeys.all, "public", "list"],
103
+ });
104
+ queryClient.invalidateQueries({
105
+ queryKey: [...exports.userGroupKeys.all, "me"],
106
+ });
107
+ },
108
+ });
109
+ };
110
+ exports.useAcceptUserGroupInvite = useAcceptUserGroupInvite;
111
+ const useDeclineUserGroupInvite = () => {
112
+ const client = (0, context_1.usePHCMS)();
113
+ const queryClient = (0, react_query_1.useQueryClient)();
114
+ return (0, react_query_1.useMutation)({
115
+ mutationFn: ({ inviteUid }) => client.userGroup.declineInvite(inviteUid),
116
+ onSuccess: () => {
117
+ queryClient.invalidateQueries({
118
+ queryKey: [...exports.userGroupKeys.all, "my-invites"],
119
+ });
120
+ queryClient.invalidateQueries({
121
+ queryKey: [...exports.userGroupKeys.all, "me"],
122
+ });
123
+ },
124
+ });
125
+ };
126
+ exports.useDeclineUserGroupInvite = useDeclineUserGroupInvite;
package/dist/index.d.ts CHANGED
@@ -12,6 +12,7 @@ export * from './modules/content';
12
12
  export * from './modules/media';
13
13
  export * from './modules/place';
14
14
  export * from './modules/terms';
15
+ export * from './modules/user-group';
15
16
  export * from './modules/user';
16
17
  export * from './context';
17
18
  export * from './hooks/useAuth';
@@ -20,5 +21,6 @@ export * from './hooks/useStampTour';
20
21
  export * from './hooks/useFirebaseAuthSync';
21
22
  export * from './hooks/useMedia';
22
23
  export * from './hooks/usePlace';
24
+ export * from './hooks/useUserGroup';
23
25
  export * from './hooks/useUser';
24
26
  export * from './types';
package/dist/index.js CHANGED
@@ -28,6 +28,7 @@ __exportStar(require("./modules/content"), exports);
28
28
  __exportStar(require("./modules/media"), exports);
29
29
  __exportStar(require("./modules/place"), exports);
30
30
  __exportStar(require("./modules/terms"), exports);
31
+ __exportStar(require("./modules/user-group"), exports);
31
32
  __exportStar(require("./modules/user"), exports);
32
33
  __exportStar(require("./context"), exports);
33
34
  __exportStar(require("./hooks/useAuth"), exports);
@@ -36,5 +37,6 @@ __exportStar(require("./hooks/useStampTour"), exports);
36
37
  __exportStar(require("./hooks/useFirebaseAuthSync"), exports);
37
38
  __exportStar(require("./hooks/useMedia"), exports);
38
39
  __exportStar(require("./hooks/usePlace"), exports);
40
+ __exportStar(require("./hooks/useUserGroup"), exports);
39
41
  __exportStar(require("./hooks/useUser"), exports);
40
42
  __exportStar(require("./types"), exports);
@@ -0,0 +1,15 @@
1
+ import { GetMyUserGroupMembershipResponse, JoinUserGroupResponse, LeaveUserGroupResponse, ListUserGroupQuery, PagedMyGroupInviteListResponse, PagedMyUserGroupMembershipListResponse, PagedUserGroupListResponse, RespondInviteResponse } from "@ph-cms/api-contract";
2
+ import { AxiosInstance } from "axios";
3
+ export declare class UserGroupModule {
4
+ private client;
5
+ private prefix;
6
+ constructor(client: AxiosInstance, prefix?: string);
7
+ listByBaseContent(baseContentUid: string, params?: ListUserGroupQuery): Promise<PagedUserGroupListResponse>;
8
+ getMyMembership(baseContentUid: string, groupUid: string): Promise<GetMyUserGroupMembershipResponse>;
9
+ join(baseContentUid: string, groupUid: string): Promise<JoinUserGroupResponse>;
10
+ leave(baseContentUid: string, groupUid: string): Promise<LeaveUserGroupResponse>;
11
+ listMine(params?: ListUserGroupQuery): Promise<PagedMyUserGroupMembershipListResponse>;
12
+ listMyInvites(params?: ListUserGroupQuery): Promise<PagedMyGroupInviteListResponse>;
13
+ acceptInvite(inviteUid: string): Promise<RespondInviteResponse>;
14
+ declineInvite(inviteUid: string): Promise<RespondInviteResponse>;
15
+ }
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.UserGroupModule = void 0;
4
+ const api_contract_1 = require("@ph-cms/api-contract");
5
+ const errors_1 = require("../errors");
6
+ class UserGroupModule {
7
+ constructor(client, prefix = "/api") {
8
+ this.client = client;
9
+ this.prefix = prefix;
10
+ }
11
+ async listByBaseContent(baseContentUid, params = {}) {
12
+ if (!baseContentUid)
13
+ throw new errors_1.ValidationError("Base content UID is required", []);
14
+ const validation = api_contract_1.ListUserGroupQuerySchema.safeParse(params);
15
+ if (!validation.success) {
16
+ throw new errors_1.ValidationError("Invalid user group list params", validation.error.errors);
17
+ }
18
+ return this.client.get(`${this.prefix}/contents/${baseContentUid}/user-groups`, { params: validation.data });
19
+ }
20
+ async getMyMembership(baseContentUid, groupUid) {
21
+ if (!baseContentUid)
22
+ throw new errors_1.ValidationError("Base content UID is required", []);
23
+ if (!groupUid)
24
+ throw new errors_1.ValidationError("Group UID is required", []);
25
+ return this.client.get(`${this.prefix}/contents/${baseContentUid}/user-groups/${groupUid}/me`);
26
+ }
27
+ async join(baseContentUid, groupUid) {
28
+ if (!baseContentUid)
29
+ throw new errors_1.ValidationError("Base content UID is required", []);
30
+ if (!groupUid)
31
+ throw new errors_1.ValidationError("Group UID is required", []);
32
+ return this.client.post(`${this.prefix}/contents/${baseContentUid}/user-groups/${groupUid}/join`);
33
+ }
34
+ async leave(baseContentUid, groupUid) {
35
+ if (!baseContentUid)
36
+ throw new errors_1.ValidationError("Base content UID is required", []);
37
+ if (!groupUid)
38
+ throw new errors_1.ValidationError("Group UID is required", []);
39
+ return this.client.delete(`${this.prefix}/contents/${baseContentUid}/user-groups/${groupUid}/join`);
40
+ }
41
+ async listMine(params = {}) {
42
+ const validation = api_contract_1.ListUserGroupQuerySchema.safeParse(params);
43
+ if (!validation.success) {
44
+ throw new errors_1.ValidationError("Invalid my user group list params", validation.error.errors);
45
+ }
46
+ return this.client.get(`${this.prefix}/me/user-groups`, { params: validation.data });
47
+ }
48
+ async listMyInvites(params = {}) {
49
+ const validation = api_contract_1.ListUserGroupQuerySchema.safeParse(params);
50
+ if (!validation.success) {
51
+ throw new errors_1.ValidationError("Invalid my user group invite list params", validation.error.errors);
52
+ }
53
+ return this.client.get(`${this.prefix}/me/group-invites`, { params: validation.data });
54
+ }
55
+ async acceptInvite(inviteUid) {
56
+ if (!inviteUid)
57
+ throw new errors_1.ValidationError("Invite UID is required", []);
58
+ return this.client.post(`${this.prefix}/me/group-invites/${inviteUid}/accept`);
59
+ }
60
+ async declineInvite(inviteUid) {
61
+ if (!inviteUid)
62
+ throw new errors_1.ValidationError("Invite UID is required", []);
63
+ return this.client.post(`${this.prefix}/me/group-invites/${inviteUid}/decline`);
64
+ }
65
+ }
66
+ exports.UserGroupModule = UserGroupModule;
@@ -1,5 +1,6 @@
1
1
  import { LikedStatsByTypeResponse, ListLikedContentQuery, ListUserFollowQuery, PagedContentListResponse, PagedUserProfileListResponse, UpdateUserProfileRequest, UserDto, UserProfileDto, FollowStatusResponse, FollowUserResponse, BlockUserRequest, BlockUserResponse, PagedBlockedUserListResponse, SuspendUserRequest, SuspendUserResponse } from "@ph-cms/api-contract";
2
2
  import { AxiosInstance } from "axios";
3
+ import { UserSearchResultDto } from "../types";
3
4
  export declare class UserModule {
4
5
  private client;
5
6
  private prefix;
@@ -42,6 +43,15 @@ export declare class UserModule {
42
43
  * @param params - Paging parameters.
43
44
  */
44
45
  getFollowings(uid: string, params?: Partial<ListUserFollowQuery>): Promise<PagedUserProfileListResponse>;
46
+ /**
47
+ * Searches users by name, username, or email keyword.
48
+ *
49
+ * @param query - Search keyword.
50
+ * @param params - Optional search limits.
51
+ */
52
+ search(query: string, params?: {
53
+ limit?: number;
54
+ }): Promise<UserSearchResultDto[]>;
45
55
  /**
46
56
  * Updates a user's profile.
47
57
  *
@@ -2,7 +2,11 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.UserModule = void 0;
4
4
  const api_contract_1 = require("@ph-cms/api-contract");
5
+ const zod_1 = require("zod");
5
6
  const errors_1 = require("../errors");
7
+ const UserSearchQuerySchema = zod_1.z.object({
8
+ limit: zod_1.z.coerce.number().int().min(1).max(10).optional(),
9
+ });
6
10
  class UserModule {
7
11
  constructor(client, prefix = '/api') {
8
12
  this.client = client;
@@ -76,6 +80,27 @@ class UserModule {
76
80
  }
77
81
  return this.client.get(`${this.prefix}/users/${uid}/followings`, { params: validation.data });
78
82
  }
83
+ /**
84
+ * Searches users by name, username, or email keyword.
85
+ *
86
+ * @param query - Search keyword.
87
+ * @param params - Optional search limits.
88
+ */
89
+ async search(query, params = {}) {
90
+ const keyword = query.trim();
91
+ if (!keyword)
92
+ throw new errors_1.ValidationError("Query is required", []);
93
+ const validation = UserSearchQuerySchema.safeParse(params);
94
+ if (!validation.success) {
95
+ throw new errors_1.ValidationError("Invalid user search params", validation.error.errors);
96
+ }
97
+ return this.client.get(`${this.prefix}/users/search`, {
98
+ params: {
99
+ q: keyword,
100
+ ...validation.data,
101
+ },
102
+ });
103
+ }
79
104
  /**
80
105
  * Updates a user's profile.
81
106
  *
package/dist/types.d.ts CHANGED
@@ -2,6 +2,12 @@ export type { AuthProvider } from './auth/interfaces';
2
2
  export type { JwtPayload } from './auth/jwt-utils';
3
3
  export type { PHCMSClientConfig } from './client';
4
4
  export type { AuthStatus, PHCMSContextType, PHCMSProviderProps } from './context';
5
+ export type UserSearchResultDto = {
6
+ uid: string;
7
+ username: string | null;
8
+ display_name: string;
9
+ avatar_url: string | null;
10
+ };
5
11
  export type { FirebaseAuthSyncProps, UseFirebaseAuthSyncOptions, UseFirebaseAuthSyncReturn } from './hooks/useFirebaseAuthSync';
6
12
  export type { StampAvailability, CheckStampAvailabilityParams } from './hooks/useStampTour';
7
13
  export type { AnonymousLoginRequest, AuthResponse, FirebaseExchangeRequest, FirebaseRegisterRequest, LoginRequest, RefreshTokenRequest, RegisterRequest, } from '@ph-cms/api-contract';
@@ -14,4 +20,5 @@ export type { TermDto } from '@ph-cms/api-contract';
14
20
  export type { GeoJSON } from '@ph-cms/api-contract';
15
21
  export type { MediaUploadTicketBatchRequest, MediaUploadTicketBatchResponse, MediaUploadTicketRequest, MediaUploadTicketResponse } from '@ph-cms/api-contract';
16
22
  export type { IntegratedPlace, PlaceSearchQuery, PlaceSearchResponse, } from '@ph-cms/api-contract';
23
+ export type { GetMyUserGroupMembershipResponse, JoinUserGroupResponse, LeaveUserGroupResponse, ListUserGroupQuery, PagedMyGroupInviteListResponse, PagedMyUserGroupMembershipListResponse, PagedUserGroupListResponse, RespondInviteResponse, UserGroupDto, UserGroupJoinMode, UserGroupInviteDto, UserGroupInviteStatus, UserGroupMembershipDto, } from '@ph-cms/api-contract';
17
24
  export type { PagedResponse } from '@ph-cms/api-contract';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ph-cms/client-sdk",
3
- "version": "0.1.50",
3
+ "version": "0.1.51",
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.28",
33
+ "@ph-cms/api-contract": "0.1.29",
34
34
  "@tanstack/react-query": "^5.0.0",
35
35
  "axios": "^1.6.0",
36
36
  "zod": "^3.22.4"