@ploykit/ui 0.2.0 → 0.4.1

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 (80) hide show
  1. package/README.md +201 -41
  2. package/dist/AppProviders.d.ts +15 -0
  3. package/dist/AppProviders.js +15 -0
  4. package/dist/components/ConfirmDialog.js +8 -2
  5. package/dist/components/DataTable.d.ts +12 -3
  6. package/dist/components/DataTable.js +6 -2
  7. package/dist/components/ErrorBoundary.js +1 -1
  8. package/dist/components/NotificationBell.js +4 -4
  9. package/dist/components/ReauthDialog.d.ts +15 -0
  10. package/dist/components/ReauthDialog.js +42 -0
  11. package/dist/components/SecretModal.d.ts +8 -1
  12. package/dist/components/SecretModal.js +5 -2
  13. package/dist/components/ui/{Badge.d.ts → badge.d.ts} +1 -1
  14. package/dist/components/ui/{Button.d.ts → button.d.ts} +1 -1
  15. package/dist/components/ui/dialog.d.ts +7 -1
  16. package/dist/components/ui/dialog.js +7 -2
  17. package/dist/components/ui/select.d.ts +20 -1
  18. package/dist/components/ui/select.js +22 -1
  19. package/dist/components/ui/sheet.d.ts +9 -1
  20. package/dist/components/ui/sheet.js +9 -2
  21. package/dist/components/ui/textarea.d.ts +9 -0
  22. package/dist/components/ui/textarea.js +12 -0
  23. package/dist/index.d.ts +5 -1
  24. package/dist/index.js +5 -1
  25. package/dist/pages/LandingPage.js +1 -1
  26. package/dist/pages/LoginPage.js +2 -2
  27. package/dist/pages/account/ProfileSettingsPage.js +1 -1
  28. package/dist/pages/account/SecuritySettingsPage.js +1 -1
  29. package/dist/pages/auth/InviteAcceptPage.js +1 -1
  30. package/dist/pages/auth/ResetPasswordPage.js +1 -1
  31. package/dist/pages/auth/VerifyEmailPage.js +1 -1
  32. package/dist/pages/workspace/RolePermissionsPage.d.ts +3 -0
  33. package/dist/pages/workspace/RolePermissionsPage.js +118 -0
  34. package/package.json +3 -3
  35. package/dist/components/ui/menu.d.ts +0 -29
  36. package/dist/components/ui/menu.js +0 -50
  37. package/dist/hooks/useApi.d.ts +0 -10
  38. package/dist/hooks/useApi.js +0 -11
  39. package/dist/hooks/useAudit.d.ts +0 -39
  40. package/dist/hooks/useAudit.js +0 -55
  41. package/dist/hooks/useAuth.d.ts +0 -1
  42. package/dist/hooks/useAuth.js +0 -4
  43. package/dist/hooks/useBilling.d.ts +0 -44
  44. package/dist/hooks/useBilling.js +0 -64
  45. package/dist/hooks/useLogin.d.ts +0 -10
  46. package/dist/hooks/useLogin.js +0 -39
  47. package/dist/hooks/useMembers.d.ts +0 -125
  48. package/dist/hooks/useMembers.js +0 -127
  49. package/dist/hooks/useNotificationPrefs.d.ts +0 -20
  50. package/dist/hooks/useNotificationPrefs.js +0 -42
  51. package/dist/hooks/usePasswordReset.d.ts +0 -5
  52. package/dist/hooks/usePasswordReset.js +0 -12
  53. package/dist/hooks/useSEO.d.ts +0 -6
  54. package/dist/hooks/useSEO.js +0 -14
  55. package/dist/hooks/useSessions.d.ts +0 -20
  56. package/dist/hooks/useSessions.js +0 -38
  57. package/dist/hooks/useSiteConfig.d.ts +0 -12
  58. package/dist/hooks/useSiteConfig.js +0 -11
  59. package/dist/hooks/useTokens.d.ts +0 -36
  60. package/dist/hooks/useTokens.js +0 -35
  61. package/dist/hooks/useUsage.d.ts +0 -20
  62. package/dist/hooks/useUsage.js +0 -21
  63. package/dist/hooks/useWorkspace.d.ts +0 -26
  64. package/dist/hooks/useWorkspace.js +0 -32
  65. package/dist/hooks/useZodForm.d.ts +0 -6
  66. package/dist/hooks/useZodForm.js +0 -6
  67. package/dist/hooks/ws.d.ts +0 -4
  68. package/dist/hooks/ws.js +0 -21
  69. package/dist/lib/perm.d.ts +0 -2
  70. package/dist/lib/perm.js +0 -7
  71. package/dist/lib/ws-query-bridge.d.ts +0 -7
  72. package/dist/lib/ws-query-bridge.js +0 -35
  73. package/dist/provider/PloykitProvider.d.ts +0 -50
  74. package/dist/provider/PloykitProvider.js +0 -240
  75. package/dist/realtime.d.ts +0 -3
  76. package/dist/realtime.js +0 -11
  77. /package/dist/components/ui/{Badge.js → badge.js} +0 -0
  78. /package/dist/components/ui/{Button.js → button.js} +0 -0
  79. /package/dist/components/ui/{Input.d.ts → input.d.ts} +0 -0
  80. /package/dist/components/ui/{Input.js → input.js} +0 -0
@@ -1,39 +0,0 @@
1
- import type { components } from '@ploykit/client';
2
- export type PKAuditEvent = components['schemas']['AuditEvent'];
3
- export interface AuditListResp {
4
- items: PKAuditEvent[];
5
- total: number;
6
- }
7
- export interface AuditFilters {
8
- action: string;
9
- actorId: string;
10
- resourceType: string;
11
- from: string;
12
- to: string;
13
- }
14
- export declare const EMPTY_AUDIT_FILTERS: AuditFilters;
15
- export declare function auditQueryString(f: AuditFilters, limit: number, offset: number): string;
16
- export declare function useAudit(filters: AuditFilters, limit?: number, offset?: number): {
17
- wsId: string;
18
- items: {
19
- id: string;
20
- workspace_id: string;
21
- actor_type: "user" | "pat" | "system";
22
- actor_id: string | null;
23
- actor_snapshot: {
24
- [key: string]: unknown;
25
- };
26
- action: string;
27
- resource_type: string;
28
- resource_id: string | null;
29
- metadata: {
30
- [key: string]: unknown;
31
- };
32
- created_at: string;
33
- }[];
34
- total: number;
35
- loading: boolean;
36
- error: Error | null;
37
- refetch: (options?: import("@tanstack/query-core").RefetchOptions) => Promise<import("@tanstack/query-core").QueryObserverResult<AuditListResp, Error>>;
38
- };
39
- export declare function exportAuditCsv(filters: AuditFilters): Promise<void>;
@@ -1,55 +0,0 @@
1
- import { useQuery } from '@tanstack/react-query';
2
- import { apiFetch } from '@ploykit/client';
3
- import { useApi } from './useApi';
4
- import { useWorkspace } from './useWorkspace';
5
- import { queryKeys } from '../provider/PloykitProvider';
6
- export const EMPTY_AUDIT_FILTERS = {
7
- action: '', actorId: '', resourceType: '', from: '', to: '',
8
- };
9
- export function auditQueryString(f, limit, offset) {
10
- const q = new URLSearchParams();
11
- if (f.action)
12
- q.set('action', f.action);
13
- if (f.actorId)
14
- q.set('actor_id', f.actorId);
15
- if (f.resourceType)
16
- q.set('resource_type', f.resourceType);
17
- if (f.from)
18
- q.set('from', f.from);
19
- if (f.to)
20
- q.set('to', f.to);
21
- q.set('limit', String(limit));
22
- q.set('offset', String(offset));
23
- return q.toString();
24
- }
25
- export function useAudit(filters, limit = 20, offset = 0) {
26
- const { current } = useWorkspace();
27
- const api = useApi();
28
- const wsId = current?.id ?? '';
29
- const qs = auditQueryString(filters, limit, offset);
30
- const q = useQuery({
31
- queryKey: queryKeys.audit(wsId, { ...filters, limit, offset }),
32
- queryFn: () => api.get(`/api/audit?${qs}`),
33
- enabled: !!wsId,
34
- });
35
- return {
36
- wsId,
37
- items: wsId ? (q.data?.items ?? []) : [],
38
- total: wsId ? (q.data?.total ?? 0) : 0,
39
- loading: !!wsId && q.isPending,
40
- error: q.error,
41
- refetch: q.refetch,
42
- };
43
- }
44
- export async function exportAuditCsv(filters) {
45
- const qs = auditQueryString(filters, 5000, 0);
46
- const blob = await apiFetch(`/api/audit/export.csv?${qs}`, { responseType: 'blob' });
47
- const url = URL.createObjectURL(blob);
48
- const a = document.createElement('a');
49
- a.href = url;
50
- a.download = `audit-${new Date().toISOString().slice(0, 10)}.csv`;
51
- document.body.appendChild(a);
52
- a.click();
53
- a.remove();
54
- URL.revokeObjectURL(url);
55
- }
@@ -1 +0,0 @@
1
- export declare function useAuth(): import("../provider/PloykitProvider").AuthContextValue;
@@ -1,4 +0,0 @@
1
- import { useAuthCtx } from '../provider/PloykitProvider';
2
- export function useAuth() {
3
- return useAuthCtx();
4
- }
@@ -1,44 +0,0 @@
1
- import { type ReactNode } from 'react';
2
- import { type components } from '@ploykit/client';
3
- export declare function useBilling(): {
4
- subscription: {
5
- plan_code: string;
6
- orders: components["schemas"]["Order"][];
7
- } | null;
8
- plans: {
9
- code: string;
10
- name: string;
11
- currency?: string;
12
- trial_days?: number;
13
- limits: {
14
- [key: string]: number;
15
- };
16
- sort_no: number;
17
- }[];
18
- checkout: (planCode: string, interval: string, channel: string) => Promise<{
19
- order_id: string;
20
- channel: "stripe" | "alipay" | "wechat";
21
- action_url: string;
22
- session_ref: string;
23
- expires_at: string;
24
- } | null>;
25
- checkoutError: Error | null;
26
- loading: boolean;
27
- refresh: () => Promise<void>;
28
- };
29
- export declare function PlanGate({ plan, denied, children, busy }: {
30
- plan: string;
31
- denied?: ReactNode;
32
- children: ReactNode;
33
- busy?: ReactNode;
34
- }): import("react").JSX.Element;
35
- export type UsagePreviewItem = components['schemas']['UsagePreviewItem'];
36
- export type UsagePreviewResp = components['schemas']['UsagePreview'];
37
- export declare function useUsagePreview(): {
38
- preview: {
39
- period: string;
40
- items: components["schemas"]["UsagePreviewItem"][];
41
- projected_total_cents: number;
42
- } | null;
43
- loading: boolean;
44
- };
@@ -1,64 +0,0 @@
1
- import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
2
- import { useCallback } from 'react';
3
- import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
4
- import { api } from '@ploykit/client';
5
- import { useWorkspaceCtx, queryKeys, } from '../provider/PloykitProvider';
6
- export function useBilling() {
7
- const { current } = useWorkspaceCtx();
8
- const qc = useQueryClient();
9
- const wsId = current?.id ?? '';
10
- const subQ = useQuery({
11
- queryKey: queryKeys.billingSubscription(wsId),
12
- queryFn: () => api.get('/api/billing/subscription'),
13
- enabled: !!current,
14
- });
15
- const planQ = useQuery({
16
- queryKey: queryKeys.billingPlans,
17
- queryFn: () => api.get('/api/billing/plans'),
18
- });
19
- const checkoutM = useMutation({
20
- mutationFn: (v) => api.post('/api/billing/checkout', {
21
- plan_code: v.planCode, interval: v.interval, channel: v.channel,
22
- }),
23
- onSuccess: () => qc.invalidateQueries({ queryKey: queryKeys.billing }),
24
- });
25
- const checkout = useCallback(async (planCode, interval, channel) => {
26
- if (!wsId)
27
- return null;
28
- return checkoutM.mutateAsync({ planCode, interval, channel }).catch(() => null);
29
- }, [wsId, checkoutM.mutateAsync]); // eslint-disable-line react-hooks/exhaustive-deps
30
- const refresh = useCallback(async () => {
31
- await qc.invalidateQueries({ queryKey: queryKeys.billing });
32
- }, [qc]);
33
- return {
34
- subscription: current ? (subQ.data ?? null) : null,
35
- plans: Array.isArray(planQ.data) ? planQ.data : [],
36
- checkout,
37
- checkoutError: checkoutM.error ?? null,
38
- loading: planQ.isPending || (!!current && subQ.isPending),
39
- refresh,
40
- };
41
- }
42
- export function PlanGate({ plan, denied, children, busy }) {
43
- const { subscription, plans, loading } = useBilling();
44
- if (loading)
45
- return _jsx(_Fragment, { children: busy ?? null });
46
- if (!subscription)
47
- return _jsx(_Fragment, { children: denied ?? null });
48
- const currentPlan = plans.find((p) => p.code === subscription.plan_code);
49
- const requiredPlan = plans.find((p) => p.code === plan);
50
- const entitled = currentPlan && requiredPlan && currentPlan.sort_no >= requiredPlan.sort_no;
51
- return _jsx(_Fragment, { children: entitled ? children : denied });
52
- }
53
- export function useUsagePreview() {
54
- const { current } = useWorkspaceCtx();
55
- const previewQ = useQuery({
56
- queryKey: ['billing', 'usage-preview', current?.id ?? ''],
57
- queryFn: () => api.get('/api/billing/usage-preview'),
58
- enabled: !!current,
59
- });
60
- return {
61
- preview: current ? (previewQ.data ?? null) : null,
62
- loading: !!current && previewQ.isPending,
63
- };
64
- }
@@ -1,10 +0,0 @@
1
- export interface UseLoginResult {
2
- sendCode(email: string): Promise<void>;
3
- submit(email: string, code: string): Promise<{
4
- ok: boolean;
5
- error?: string;
6
- }>;
7
- loading: boolean;
8
- error: string | null;
9
- }
10
- export declare function useLogin(): UseLoginResult;
@@ -1,39 +0,0 @@
1
- import { useCallback, useState } from 'react';
2
- import { api } from '@ploykit/client';
3
- import { useAuthCtx } from '../provider/PloykitProvider';
4
- export function useLogin() {
5
- const [loading, setLoading] = useState(false);
6
- const [error, setError] = useState(null);
7
- const { refresh } = useAuthCtx();
8
- const sendCode = useCallback(async (email) => {
9
- setError(null);
10
- setLoading(true);
11
- try {
12
- await api.post('/auth/send-code', { email });
13
- }
14
- catch (e) {
15
- setError(e instanceof Error ? e.message : '发送失败');
16
- }
17
- finally {
18
- setLoading(false);
19
- }
20
- }, []);
21
- const submit = useCallback(async (email, code) => {
22
- setError(null);
23
- setLoading(true);
24
- try {
25
- await api.post('/auth/verify-code', { email, code });
26
- await refresh();
27
- return { ok: true };
28
- }
29
- catch (e) {
30
- const msg = e instanceof Error ? e.message : '登录失败';
31
- setError(msg);
32
- return { ok: false, error: msg };
33
- }
34
- finally {
35
- setLoading(false);
36
- }
37
- }, [refresh]);
38
- return { sendCode, submit, loading, error };
39
- }
@@ -1,125 +0,0 @@
1
- import type { components } from '@ploykit/client';
2
- export type PKMember = components['schemas']['Member'];
3
- export type PKInvitation = components['schemas']['Invitation'];
4
- export type PKShareLink = components['schemas']['ShareLink'];
5
- export type PKInvitationWithWorkspace = components['schemas']['InvitationWithWorkspace'];
6
- export type PKMemberPage = components['schemas']['MemberPage'];
7
- export type PKInvitationPage = components['schemas']['InvitationPage'];
8
- export type PKShareLinkPage = components['schemas']['ShareLinkPage'];
9
- export interface ListQuery {
10
- page: number;
11
- pageSize?: number;
12
- }
13
- export interface ListPages {
14
- members: number;
15
- invitations: number;
16
- shareLinks: number;
17
- }
18
- export declare const LIST_PAGE_SIZE = 50;
19
- export interface CreateShareLinkResult {
20
- link: PKShareLink;
21
- code: string;
22
- }
23
- export declare const ASSIGNABLE_ROLES: readonly ["admin", "member"];
24
- export declare function useMembers(pages: ListPages): {
25
- wsId: string;
26
- myRole: "owner" | "admin" | "member" | null;
27
- members: {
28
- user_id: string;
29
- email: string;
30
- display_name: string;
31
- role: "owner" | "admin" | "member";
32
- created_at: string;
33
- }[];
34
- membersTotal: number;
35
- invitations: {
36
- id: string;
37
- workspace_id: string;
38
- email: string;
39
- role: "owner" | "admin" | "member";
40
- status: "pending" | "accepted" | "declined" | "revoked" | "expired";
41
- expires_at: string;
42
- created_at: string;
43
- }[];
44
- invitationsTotal: number;
45
- shareLinks: {
46
- id: string;
47
- code_prefix: string;
48
- role: "admin" | "member";
49
- max_uses: number;
50
- uses: number;
51
- expires_at: string;
52
- created_at: string;
53
- }[];
54
- shareLinksTotal: number;
55
- loading: boolean;
56
- membersError: Error | null;
57
- invitationsError: Error | null;
58
- shareLinksError: Error | null;
59
- refetchAll: () => Promise<void>;
60
- };
61
- export declare function useMemberMutations(): {
62
- invite: import("@tanstack/react-query").UseMutationResult<{
63
- id: string;
64
- workspace_id: string;
65
- email: string;
66
- role: "owner" | "admin" | "member";
67
- status: "pending" | "accepted" | "declined" | "revoked" | "expired";
68
- expires_at: string;
69
- created_at: string;
70
- }, Error, {
71
- email: string;
72
- role: string;
73
- }, unknown>;
74
- revokeInvitation: import("@tanstack/react-query").UseMutationResult<unknown, Error, string, unknown>;
75
- updateRole: import("@tanstack/react-query").UseMutationResult<unknown, Error, {
76
- userId: string;
77
- role: string;
78
- }, unknown>;
79
- removeMember: import("@tanstack/react-query").UseMutationResult<unknown, Error, string, unknown>;
80
- transferOwnership: import("@tanstack/react-query").UseMutationResult<unknown, Error, string, unknown>;
81
- createShareLink: import("@tanstack/react-query").UseMutationResult<CreateShareLinkResult, Error, {
82
- role: string;
83
- max_uses: number;
84
- ttl_hours: number;
85
- }, unknown>;
86
- revokeShareLink: import("@tanstack/react-query").UseMutationResult<unknown, Error, string, unknown>;
87
- };
88
- export declare function useMyInvitations(): {
89
- invitations: ({
90
- id: string;
91
- workspace_id: string;
92
- email: string;
93
- role: "owner" | "admin" | "member";
94
- status: "pending" | "accepted" | "declined" | "revoked" | "expired";
95
- expires_at: string;
96
- created_at: string;
97
- } & {
98
- workspace_name: string;
99
- workspace_slug: string;
100
- })[];
101
- loading: boolean;
102
- error: Error | null;
103
- refetch: (options?: import("@tanstack/query-core").RefetchOptions) => Promise<import("@tanstack/query-core").QueryObserverResult<({
104
- id: string;
105
- workspace_id: string;
106
- email: string;
107
- role: "owner" | "admin" | "member";
108
- status: "pending" | "accepted" | "declined" | "revoked" | "expired";
109
- expires_at: string;
110
- created_at: string;
111
- } & {
112
- workspace_name: string;
113
- workspace_slug: string;
114
- })[], Error>>;
115
- accept: import("@tanstack/react-query").UseMutationResult<{
116
- id: string;
117
- slug: string;
118
- name: string;
119
- plan_code: string;
120
- created_at: string;
121
- } & {
122
- role: "owner" | "admin" | "member";
123
- }, Error, string, unknown>;
124
- decline: import("@tanstack/react-query").UseMutationResult<unknown, Error, string, unknown>;
125
- };
@@ -1,127 +0,0 @@
1
- import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
2
- import { useApi } from './useApi';
3
- import { useWorkspace } from './useWorkspace';
4
- import { queryKeys } from '../provider/PloykitProvider';
5
- export const LIST_PAGE_SIZE = 50;
6
- const listQuery = (q) => `?page=${q.page}&page_size=${q.pageSize ?? LIST_PAGE_SIZE}`;
7
- export const ASSIGNABLE_ROLES = ['admin', 'member'];
8
- export function useMembers(pages) {
9
- const { current } = useWorkspace();
10
- const api = useApi();
11
- const wsId = current?.id ?? '';
12
- const membersQ = useQuery({
13
- queryKey: [...queryKeys.members(wsId), pages.members],
14
- queryFn: () => api.get(`/api/workspaces/${wsId}/members${listQuery({ page: pages.members })}`),
15
- enabled: !!wsId,
16
- });
17
- const invitationsQ = useQuery({
18
- queryKey: [...queryKeys.invitations(wsId), pages.invitations],
19
- queryFn: () => api.get(`/api/workspaces/${wsId}/invitations${listQuery({ page: pages.invitations })}`),
20
- enabled: !!wsId,
21
- });
22
- const shareLinksQ = useQuery({
23
- queryKey: [...queryKeys.shareLinks(wsId), pages.shareLinks],
24
- queryFn: () => api.get(`/api/workspaces/${wsId}/share-links${listQuery({ page: pages.shareLinks })}`),
25
- enabled: !!wsId,
26
- });
27
- return {
28
- wsId,
29
- myRole: current?.role ?? null,
30
- members: membersQ.data?.items ?? [],
31
- membersTotal: membersQ.data?.total ?? 0,
32
- invitations: invitationsQ.data?.items ?? [],
33
- invitationsTotal: invitationsQ.data?.total ?? 0,
34
- shareLinks: shareLinksQ.data?.items ?? [],
35
- shareLinksTotal: shareLinksQ.data?.total ?? 0,
36
- loading: !!wsId && (membersQ.isPending || invitationsQ.isPending || shareLinksQ.isPending),
37
- membersError: membersQ.error,
38
- invitationsError: invitationsQ.error,
39
- shareLinksError: shareLinksQ.error,
40
- refetchAll: async () => {
41
- await Promise.all([
42
- membersQ.refetch(),
43
- invitationsQ.refetch(),
44
- shareLinksQ.refetch(),
45
- ]);
46
- },
47
- };
48
- }
49
- export function useMemberMutations() {
50
- const { current } = useWorkspace();
51
- const api = useApi();
52
- const qc = useQueryClient();
53
- const wsId = current?.id ?? '';
54
- const base = `/api/workspaces/${wsId}`;
55
- const invalidateAll = async () => {
56
- await Promise.all([
57
- qc.invalidateQueries({ queryKey: queryKeys.members(wsId) }),
58
- qc.invalidateQueries({ queryKey: queryKeys.invitations(wsId) }),
59
- qc.invalidateQueries({ queryKey: queryKeys.shareLinks(wsId) }),
60
- ]);
61
- };
62
- const invite = useMutation({
63
- mutationFn: (v) => api.post(`${base}/invitations`, v),
64
- onSuccess: invalidateAll,
65
- });
66
- const revokeInvitation = useMutation({
67
- mutationFn: (invId) => api.delete(`${base}/invitations/${invId}`),
68
- onSuccess: invalidateAll,
69
- });
70
- const updateRole = useMutation({
71
- mutationFn: (v) => api.patch(`${base}/members/${v.userId}`, { role: v.role }),
72
- onSuccess: invalidateAll,
73
- });
74
- const removeMember = useMutation({
75
- mutationFn: (userId) => api.delete(`${base}/members/${userId}`),
76
- onSuccess: invalidateAll,
77
- });
78
- const transferOwnership = useMutation({
79
- mutationFn: (userId) => api.post(`${base}/transfer-ownership`, { user_id: userId }),
80
- onSuccess: async () => {
81
- await invalidateAll();
82
- await qc.invalidateQueries({ queryKey: queryKeys.workspace });
83
- },
84
- });
85
- const createShareLink = useMutation({
86
- mutationFn: (v) => api.post(`${base}/share-links`, v),
87
- onSuccess: invalidateAll,
88
- });
89
- const revokeShareLink = useMutation({
90
- mutationFn: (linkId) => api.delete(`${base}/share-links/${linkId}`),
91
- onSuccess: invalidateAll,
92
- });
93
- return {
94
- invite, revokeInvitation, updateRole, removeMember, transferOwnership,
95
- createShareLink, revokeShareLink,
96
- };
97
- }
98
- export function useMyInvitations() {
99
- const api = useApi();
100
- const qc = useQueryClient();
101
- const list = useQuery({
102
- queryKey: queryKeys.myInvitations,
103
- queryFn: () => api.get('/api/invitations/mine'),
104
- });
105
- const invalidate = () => qc.invalidateQueries({ queryKey: queryKeys.myInvitations });
106
- const accept = useMutation({
107
- mutationFn: (id) => api.post(`/api/invitations/${id}/accept`),
108
- onSuccess: async () => {
109
- await Promise.all([
110
- invalidate(),
111
- qc.invalidateQueries({ queryKey: queryKeys.workspace }),
112
- ]);
113
- },
114
- });
115
- const decline = useMutation({
116
- mutationFn: (id) => api.post(`/api/invitations/${id}/decline`),
117
- onSuccess: invalidate,
118
- });
119
- return {
120
- invitations: list.data ?? [],
121
- loading: list.isPending,
122
- error: list.error,
123
- refetch: list.refetch,
124
- accept,
125
- decline,
126
- };
127
- }
@@ -1,20 +0,0 @@
1
- export interface NotificationPreference {
2
- notification_type: string;
3
- email_enabled: boolean;
4
- in_app_enabled: boolean;
5
- updated_at: string;
6
- }
7
- export declare function useNotificationPrefs(): {
8
- prefs: NotificationPreference[];
9
- loading: boolean;
10
- error: Error | null;
11
- refetch: (options?: import("@tanstack/query-core").RefetchOptions) => Promise<import("@tanstack/query-core").QueryObserverResult<NotificationPreference[], Error>>;
12
- };
13
- export declare function useSetNotificationPref(): {
14
- setPref: (type: string, channels: {
15
- email_enabled?: boolean;
16
- in_app_enabled?: boolean;
17
- }) => Promise<NotificationPreference>;
18
- loading: boolean;
19
- error: Error | null;
20
- };
@@ -1,42 +0,0 @@
1
- import { useCallback } from 'react';
2
- import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
3
- import { api } from '@ploykit/client';
4
- import { queryKeys } from '../provider/PloykitProvider';
5
- export function useNotificationPrefs() {
6
- const q = useQuery({
7
- queryKey: queryKeys.notificationPrefs,
8
- queryFn: async () => {
9
- const data = await api.get('/api/notification-preferences');
10
- return data?.items ?? [];
11
- },
12
- });
13
- return { prefs: q.data ?? [], loading: q.isPending, error: q.error, refetch: q.refetch };
14
- }
15
- export function useSetNotificationPref() {
16
- const qc = useQueryClient();
17
- const m = useMutation({
18
- mutationFn: (v) => api.put(`/api/notification-preferences/${encodeURIComponent(v.type)}`, { email_enabled: v.email_enabled, in_app_enabled: v.in_app_enabled }),
19
- onMutate: async (v) => {
20
- await qc.cancelQueries({ queryKey: queryKeys.notificationPrefs });
21
- const prev = qc.getQueryData(queryKeys.notificationPrefs) ?? [];
22
- const existing = prev.find((p) => p.notification_type === v.type);
23
- const next = {
24
- notification_type: v.type,
25
- email_enabled: v.email_enabled ?? existing?.email_enabled ?? true,
26
- in_app_enabled: v.in_app_enabled ?? existing?.in_app_enabled ?? true,
27
- updated_at: new Date().toISOString(),
28
- };
29
- qc.setQueryData(queryKeys.notificationPrefs, existing
30
- ? prev.map((p) => (p.notification_type === v.type ? next : p))
31
- : [...prev, next]);
32
- return { prev };
33
- },
34
- onError: (_err, _v, ctx) => {
35
- if (ctx?.prev)
36
- qc.setQueryData(queryKeys.notificationPrefs, ctx.prev);
37
- },
38
- onSettled: () => qc.invalidateQueries({ queryKey: queryKeys.notificationPrefs }),
39
- });
40
- const setPref = useCallback((type, channels) => m.mutateAsync({ type, ...channels }), [m]);
41
- return { setPref, loading: m.isPending, error: m.error };
42
- }
@@ -1,5 +0,0 @@
1
- export interface UsePasswordResetResult {
2
- requestReset(email: string): Promise<void>;
3
- reset(email: string, token: string, newPassword: string): Promise<void>;
4
- }
5
- export declare function usePasswordReset(): UsePasswordResetResult;
@@ -1,12 +0,0 @@
1
- import { useCallback } from 'react';
2
- import { useApi } from './useApi';
3
- export function usePasswordReset() {
4
- const api = useApi();
5
- const requestReset = useCallback(async (email) => {
6
- await api.post('/auth/forgot-password', { email });
7
- }, [api]);
8
- const reset = useCallback(async (email, token, newPassword) => {
9
- await api.post('/auth/reset-password', { email, token, new_password: newPassword });
10
- }, [api]);
11
- return { requestReset, reset };
12
- }
@@ -1,6 +0,0 @@
1
- export interface SeoMeta {
2
- title?: string;
3
- description?: string;
4
- ogImage?: string;
5
- }
6
- export declare function useSEO(meta: SeoMeta): void;
@@ -1,14 +0,0 @@
1
- import { emitDirective } from '@ploykit/runtime';
2
- export function useSEO(meta) {
3
- const entries = [];
4
- if (meta.title)
5
- entries.push({ tag: 'title', children: meta.title });
6
- if (meta.description) {
7
- entries.push({ tag: 'meta', attrs: { name: 'description', content: meta.description } });
8
- }
9
- if (meta.ogImage) {
10
- entries.push({ tag: 'meta', attrs: { property: 'og:image', content: meta.ogImage } });
11
- entries.push({ tag: 'meta', attrs: { name: 'twitter:card', content: 'summary_large_image' } });
12
- }
13
- emitDirective('head', entries);
14
- }
@@ -1,20 +0,0 @@
1
- import type { components } from '@ploykit/client';
2
- export type SessionInfo = components['schemas']['SessionInfo'] & {
3
- current?: boolean;
4
- };
5
- export declare function useSessions(): {
6
- sessions: SessionInfo[];
7
- loading: boolean;
8
- error: Error | null;
9
- refetch: (options?: import("@tanstack/query-core").RefetchOptions) => Promise<import("@tanstack/query-core").QueryObserverResult<SessionInfo[], Error>>;
10
- };
11
- export declare function useRevokeSession(): {
12
- revoke: (id: string) => Promise<void>;
13
- loading: boolean;
14
- error: Error | null;
15
- };
16
- export declare function useRevokeAllSessions(): {
17
- revokeAll: () => Promise<void>;
18
- loading: boolean;
19
- error: Error | null;
20
- };