@crimson-education/sdk 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +377 -0
- package/dist/core/account.d.ts +14 -0
- package/dist/core/account.js +30 -0
- package/dist/core/auth/index.d.ts +11 -0
- package/dist/core/auth/index.js +25 -0
- package/dist/core/auth/oauth-adapter.d.ts +78 -0
- package/dist/core/auth/oauth-adapter.js +341 -0
- package/dist/core/auth/pkce.d.ts +20 -0
- package/dist/core/auth/pkce.js +112 -0
- package/dist/core/auth/token-manager.d.ts +68 -0
- package/dist/core/auth/token-manager.js +294 -0
- package/dist/core/auth/token-storage.d.ts +46 -0
- package/dist/core/auth/token-storage.js +155 -0
- package/dist/core/auth/types.d.ts +148 -0
- package/dist/core/auth/types.js +15 -0
- package/dist/core/client.d.ts +84 -0
- package/dist/core/client.js +229 -0
- package/dist/core/index.d.ts +11 -0
- package/dist/core/index.js +47 -0
- package/dist/core/missionLibrary.d.ts +68 -0
- package/dist/core/missionLibrary.js +143 -0
- package/dist/core/missions.d.ts +45 -0
- package/dist/core/missions.js +140 -0
- package/dist/core/roadmap.d.ts +8 -0
- package/dist/core/roadmap.js +18 -0
- package/dist/core/studentProfile.d.ts +21 -0
- package/dist/core/studentProfile.js +41 -0
- package/dist/core/tasks.d.ts +117 -0
- package/dist/core/tasks.js +288 -0
- package/dist/core/types.d.ts +402 -0
- package/dist/core/types.js +2 -0
- package/dist/core/users.d.ts +21 -0
- package/dist/core/users.js +46 -0
- package/dist/iframe/auth-state.d.ts +7 -0
- package/dist/iframe/auth-state.js +125 -0
- package/dist/iframe/constants.d.ts +8 -0
- package/dist/iframe/constants.js +29 -0
- package/dist/iframe/index.d.ts +5 -0
- package/dist/iframe/index.js +17 -0
- package/dist/iframe/listener.d.ts +2 -0
- package/dist/iframe/listener.js +57 -0
- package/dist/iframe/types.d.ts +18 -0
- package/dist/iframe/types.js +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +22 -0
- package/dist/react/hooks/index.d.ts +10 -0
- package/dist/react/hooks/index.js +48 -0
- package/dist/react/hooks/useAccount.d.ts +13 -0
- package/dist/react/hooks/useAccount.js +39 -0
- package/dist/react/hooks/useAuthState.d.ts +2 -0
- package/dist/react/hooks/useAuthState.js +18 -0
- package/dist/react/hooks/useMissionLibrary.d.ts +31 -0
- package/dist/react/hooks/useMissionLibrary.js +183 -0
- package/dist/react/hooks/useMissions.d.ts +24 -0
- package/dist/react/hooks/useMissions.js +104 -0
- package/dist/react/hooks/useOAuth.d.ts +94 -0
- package/dist/react/hooks/useOAuth.js +211 -0
- package/dist/react/hooks/useRoadmapContext.d.ts +2 -0
- package/dist/react/hooks/useRoadmapContext.js +29 -0
- package/dist/react/hooks/useStudentProfile.d.ts +24 -0
- package/dist/react/hooks/useStudentProfile.js +65 -0
- package/dist/react/hooks/useTasks.d.ts +26 -0
- package/dist/react/hooks/useTasks.js +137 -0
- package/dist/react/hooks/useUsers.d.ts +9 -0
- package/dist/react/hooks/useUsers.js +50 -0
- package/dist/react/index.d.ts +3 -0
- package/dist/react/index.js +21 -0
- package/dist/react/provider.d.ts +16 -0
- package/dist/react/provider.js +41 -0
- package/package.json +61 -0
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import type { OAuthAdapter } from "../../core/auth/oauth-adapter";
|
|
2
|
+
import type { OAuthTokens, AuthorizeOptions, CallbackParams, OAuthError } from "../../core/auth/types";
|
|
3
|
+
/**
|
|
4
|
+
* OAuth hook return type
|
|
5
|
+
*/
|
|
6
|
+
export interface UseOAuthResult {
|
|
7
|
+
/** Whether the user is authenticated */
|
|
8
|
+
isAuthenticated: boolean;
|
|
9
|
+
/** Whether authentication state is loading */
|
|
10
|
+
isLoading: boolean;
|
|
11
|
+
/** Current tokens (if authenticated) */
|
|
12
|
+
tokens: OAuthTokens | null;
|
|
13
|
+
/** Last error (if any) */
|
|
14
|
+
error: Error | OAuthError | null;
|
|
15
|
+
/** Start OAuth authorization flow */
|
|
16
|
+
authorize: (options?: AuthorizeOptions) => Promise<void>;
|
|
17
|
+
/** Get authorization URL without redirecting */
|
|
18
|
+
getAuthorizeUrl: (options?: AuthorizeOptions) => Promise<string>;
|
|
19
|
+
/** Handle OAuth callback */
|
|
20
|
+
handleCallback: (params: CallbackParams) => Promise<OAuthTokens>;
|
|
21
|
+
/** Logout and revoke tokens */
|
|
22
|
+
logout: () => Promise<void>;
|
|
23
|
+
/** Manually refresh token */
|
|
24
|
+
refreshToken: () => Promise<OAuthTokens | null>;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* React hook for OAuth authentication
|
|
28
|
+
*
|
|
29
|
+
* @param adapter - OAuth adapter instance from CrimsonClient
|
|
30
|
+
* @returns OAuth state and methods
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```tsx
|
|
34
|
+
* const client = createCrimsonClient({
|
|
35
|
+
* apiUrl: 'https://api.example.com',
|
|
36
|
+
* oauth: {
|
|
37
|
+
* clientId: 'my-app',
|
|
38
|
+
* redirectUri: 'https://myapp.com/callback',
|
|
39
|
+
* },
|
|
40
|
+
* });
|
|
41
|
+
*
|
|
42
|
+
* function App() {
|
|
43
|
+
* const oauth = useOAuth(client.getOAuthAdapter());
|
|
44
|
+
*
|
|
45
|
+
* if (oauth.isLoading) return <div>Loading...</div>;
|
|
46
|
+
*
|
|
47
|
+
* if (!oauth.isAuthenticated) {
|
|
48
|
+
* return <button onClick={() => oauth.authorize()}>Login</button>;
|
|
49
|
+
* }
|
|
50
|
+
*
|
|
51
|
+
* return (
|
|
52
|
+
* <div>
|
|
53
|
+
* <p>Authenticated!</p>
|
|
54
|
+
* <button onClick={() => oauth.logout()}>Logout</button>
|
|
55
|
+
* </div>
|
|
56
|
+
* );
|
|
57
|
+
* }
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
export declare function useOAuth(adapter: OAuthAdapter | undefined): UseOAuthResult;
|
|
61
|
+
/**
|
|
62
|
+
* Hook for handling OAuth callback page
|
|
63
|
+
*
|
|
64
|
+
* @param adapter - OAuth adapter instance
|
|
65
|
+
* @param params - URL parameters from OAuth callback
|
|
66
|
+
* @returns Callback handling state
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* ```tsx
|
|
70
|
+
* function CallbackPage() {
|
|
71
|
+
* const params = new URLSearchParams(window.location.search);
|
|
72
|
+
* const { isProcessing, error, success } = useOAuthCallback(
|
|
73
|
+
* client.getOAuthAdapter(),
|
|
74
|
+
* {
|
|
75
|
+
* code: params.get('code') ?? undefined,
|
|
76
|
+
* state: params.get('state') ?? undefined,
|
|
77
|
+
* error: params.get('error') ?? undefined,
|
|
78
|
+
* errorDescription: params.get('error_description') ?? undefined,
|
|
79
|
+
* }
|
|
80
|
+
* );
|
|
81
|
+
*
|
|
82
|
+
* if (isProcessing) return <div>Processing...</div>;
|
|
83
|
+
* if (error) return <div>Error: {error.message}</div>;
|
|
84
|
+
* if (success) return <Navigate to="/" />;
|
|
85
|
+
*
|
|
86
|
+
* return null;
|
|
87
|
+
* }
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
export declare function useOAuthCallback(adapter: OAuthAdapter | undefined, params: CallbackParams): {
|
|
91
|
+
isProcessing: boolean;
|
|
92
|
+
error: Error | OAuthError | null;
|
|
93
|
+
success: boolean;
|
|
94
|
+
};
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
"use client";
|
|
3
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
4
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
5
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
6
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
7
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
8
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
9
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
10
|
+
});
|
|
11
|
+
};
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.useOAuth = useOAuth;
|
|
14
|
+
exports.useOAuthCallback = useOAuthCallback;
|
|
15
|
+
const react_1 = require("react");
|
|
16
|
+
const emptyState = {
|
|
17
|
+
isAuthenticated: false,
|
|
18
|
+
isLoading: true,
|
|
19
|
+
tokens: null,
|
|
20
|
+
error: null,
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* React hook for OAuth authentication
|
|
24
|
+
*
|
|
25
|
+
* @param adapter - OAuth adapter instance from CrimsonClient
|
|
26
|
+
* @returns OAuth state and methods
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```tsx
|
|
30
|
+
* const client = createCrimsonClient({
|
|
31
|
+
* apiUrl: 'https://api.example.com',
|
|
32
|
+
* oauth: {
|
|
33
|
+
* clientId: 'my-app',
|
|
34
|
+
* redirectUri: 'https://myapp.com/callback',
|
|
35
|
+
* },
|
|
36
|
+
* });
|
|
37
|
+
*
|
|
38
|
+
* function App() {
|
|
39
|
+
* const oauth = useOAuth(client.getOAuthAdapter());
|
|
40
|
+
*
|
|
41
|
+
* if (oauth.isLoading) return <div>Loading...</div>;
|
|
42
|
+
*
|
|
43
|
+
* if (!oauth.isAuthenticated) {
|
|
44
|
+
* return <button onClick={() => oauth.authorize()}>Login</button>;
|
|
45
|
+
* }
|
|
46
|
+
*
|
|
47
|
+
* return (
|
|
48
|
+
* <div>
|
|
49
|
+
* <p>Authenticated!</p>
|
|
50
|
+
* <button onClick={() => oauth.logout()}>Logout</button>
|
|
51
|
+
* </div>
|
|
52
|
+
* );
|
|
53
|
+
* }
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
function useOAuth(adapter) {
|
|
57
|
+
const [state, setState] = (0, react_1.useState)(emptyState);
|
|
58
|
+
// Subscribe to auth state changes
|
|
59
|
+
(0, react_1.useEffect)(() => {
|
|
60
|
+
if (!adapter) {
|
|
61
|
+
setState({
|
|
62
|
+
isAuthenticated: false,
|
|
63
|
+
isLoading: false,
|
|
64
|
+
tokens: null,
|
|
65
|
+
error: new Error("OAuth adapter not provided"),
|
|
66
|
+
});
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
// Initialize adapter
|
|
70
|
+
adapter.initialize().catch((error) => {
|
|
71
|
+
setState((prev) => (Object.assign(Object.assign({}, prev), { isLoading: false, error: error instanceof Error ? error : new Error(String(error)) })));
|
|
72
|
+
});
|
|
73
|
+
// Subscribe to state changes
|
|
74
|
+
const unsubscribe = adapter.subscribe((newState) => {
|
|
75
|
+
setState(newState);
|
|
76
|
+
});
|
|
77
|
+
return () => {
|
|
78
|
+
unsubscribe();
|
|
79
|
+
};
|
|
80
|
+
}, [adapter]);
|
|
81
|
+
// Memoized methods
|
|
82
|
+
const authorize = (0, react_1.useCallback)((options) => __awaiter(this, void 0, void 0, function* () {
|
|
83
|
+
if (!adapter) {
|
|
84
|
+
throw new Error("OAuth adapter not provided");
|
|
85
|
+
}
|
|
86
|
+
yield adapter.authorize(options);
|
|
87
|
+
}), [adapter]);
|
|
88
|
+
const getAuthorizeUrl = (0, react_1.useCallback)((options) => __awaiter(this, void 0, void 0, function* () {
|
|
89
|
+
if (!adapter) {
|
|
90
|
+
throw new Error("OAuth adapter not provided");
|
|
91
|
+
}
|
|
92
|
+
return adapter.getAuthorizeUrl(options);
|
|
93
|
+
}), [adapter]);
|
|
94
|
+
const handleCallback = (0, react_1.useCallback)((params) => __awaiter(this, void 0, void 0, function* () {
|
|
95
|
+
if (!adapter) {
|
|
96
|
+
throw new Error("OAuth adapter not provided");
|
|
97
|
+
}
|
|
98
|
+
return adapter.handleCallback(params);
|
|
99
|
+
}), [adapter]);
|
|
100
|
+
const logout = (0, react_1.useCallback)(() => __awaiter(this, void 0, void 0, function* () {
|
|
101
|
+
if (!adapter) {
|
|
102
|
+
throw new Error("OAuth adapter not provided");
|
|
103
|
+
}
|
|
104
|
+
yield adapter.logout();
|
|
105
|
+
}), [adapter]);
|
|
106
|
+
const refreshToken = (0, react_1.useCallback)(() => __awaiter(this, void 0, void 0, function* () {
|
|
107
|
+
if (!adapter) {
|
|
108
|
+
throw new Error("OAuth adapter not provided");
|
|
109
|
+
}
|
|
110
|
+
return adapter.refreshToken();
|
|
111
|
+
}), [adapter]);
|
|
112
|
+
// Return memoized result
|
|
113
|
+
return (0, react_1.useMemo)(() => ({
|
|
114
|
+
isAuthenticated: state.isAuthenticated,
|
|
115
|
+
isLoading: state.isLoading,
|
|
116
|
+
tokens: state.tokens,
|
|
117
|
+
error: state.error,
|
|
118
|
+
authorize,
|
|
119
|
+
getAuthorizeUrl,
|
|
120
|
+
handleCallback,
|
|
121
|
+
logout,
|
|
122
|
+
refreshToken,
|
|
123
|
+
}), [
|
|
124
|
+
state.isAuthenticated,
|
|
125
|
+
state.isLoading,
|
|
126
|
+
state.tokens,
|
|
127
|
+
state.error,
|
|
128
|
+
authorize,
|
|
129
|
+
getAuthorizeUrl,
|
|
130
|
+
handleCallback,
|
|
131
|
+
logout,
|
|
132
|
+
refreshToken,
|
|
133
|
+
]);
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Hook for handling OAuth callback page
|
|
137
|
+
*
|
|
138
|
+
* @param adapter - OAuth adapter instance
|
|
139
|
+
* @param params - URL parameters from OAuth callback
|
|
140
|
+
* @returns Callback handling state
|
|
141
|
+
*
|
|
142
|
+
* @example
|
|
143
|
+
* ```tsx
|
|
144
|
+
* function CallbackPage() {
|
|
145
|
+
* const params = new URLSearchParams(window.location.search);
|
|
146
|
+
* const { isProcessing, error, success } = useOAuthCallback(
|
|
147
|
+
* client.getOAuthAdapter(),
|
|
148
|
+
* {
|
|
149
|
+
* code: params.get('code') ?? undefined,
|
|
150
|
+
* state: params.get('state') ?? undefined,
|
|
151
|
+
* error: params.get('error') ?? undefined,
|
|
152
|
+
* errorDescription: params.get('error_description') ?? undefined,
|
|
153
|
+
* }
|
|
154
|
+
* );
|
|
155
|
+
*
|
|
156
|
+
* if (isProcessing) return <div>Processing...</div>;
|
|
157
|
+
* if (error) return <div>Error: {error.message}</div>;
|
|
158
|
+
* if (success) return <Navigate to="/" />;
|
|
159
|
+
*
|
|
160
|
+
* return null;
|
|
161
|
+
* }
|
|
162
|
+
* ```
|
|
163
|
+
*/
|
|
164
|
+
function useOAuthCallback(adapter, params) {
|
|
165
|
+
const [isProcessing, setIsProcessing] = (0, react_1.useState)(true);
|
|
166
|
+
const [error, setError] = (0, react_1.useState)(null);
|
|
167
|
+
const [success, setSuccess] = (0, react_1.useState)(false);
|
|
168
|
+
(0, react_1.useEffect)(() => {
|
|
169
|
+
if (!adapter) {
|
|
170
|
+
setError(new Error("OAuth adapter not provided"));
|
|
171
|
+
setIsProcessing(false);
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
// Check for error in params
|
|
175
|
+
if (params.error) {
|
|
176
|
+
setError({
|
|
177
|
+
error: params.error,
|
|
178
|
+
errorDescription: params.errorDescription,
|
|
179
|
+
});
|
|
180
|
+
setIsProcessing(false);
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
// Process callback
|
|
184
|
+
if (params.code && params.state) {
|
|
185
|
+
adapter
|
|
186
|
+
.handleCallback(params)
|
|
187
|
+
.then(() => {
|
|
188
|
+
setSuccess(true);
|
|
189
|
+
setIsProcessing(false);
|
|
190
|
+
})
|
|
191
|
+
.catch((err) => {
|
|
192
|
+
setError(err instanceof Error ? err : { error: String(err) });
|
|
193
|
+
setIsProcessing(false);
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
else {
|
|
197
|
+
setError({
|
|
198
|
+
error: "invalid_request",
|
|
199
|
+
errorDescription: "Missing code or state parameter",
|
|
200
|
+
});
|
|
201
|
+
setIsProcessing(false);
|
|
202
|
+
}
|
|
203
|
+
}, [
|
|
204
|
+
adapter,
|
|
205
|
+
params.code,
|
|
206
|
+
params.state,
|
|
207
|
+
params.error,
|
|
208
|
+
params.errorDescription,
|
|
209
|
+
]);
|
|
210
|
+
return { isProcessing, error, success };
|
|
211
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
"use client";
|
|
3
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
4
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
5
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
6
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
7
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
8
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
9
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
10
|
+
});
|
|
11
|
+
};
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.useRoadmapContext = useRoadmapContext;
|
|
14
|
+
const react_query_1 = require("@tanstack/react-query");
|
|
15
|
+
const provider_1 = require("../provider");
|
|
16
|
+
function useRoadmapContext(userId, enabled) {
|
|
17
|
+
const client = (0, provider_1.useCrimsonClient)();
|
|
18
|
+
return (0, react_query_1.useQuery)({
|
|
19
|
+
queryKey: ["roadmap-context", userId],
|
|
20
|
+
enabled: !!userId && enabled,
|
|
21
|
+
queryFn: () => __awaiter(this, void 0, void 0, function* () {
|
|
22
|
+
if (!userId) {
|
|
23
|
+
throw new Error("Missing userId");
|
|
24
|
+
}
|
|
25
|
+
return client.roadmap.context(userId);
|
|
26
|
+
}),
|
|
27
|
+
staleTime: 60 * 1000,
|
|
28
|
+
});
|
|
29
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { StudentProfile, StudentPrefilledInfo } from "../../core/types";
|
|
2
|
+
export declare const studentProfileKeys: {
|
|
3
|
+
all: readonly ["studentProfile"];
|
|
4
|
+
profiles: () => readonly ["studentProfile", "profile"];
|
|
5
|
+
profile: (studentId: string) => readonly ["studentProfile", "profile", string];
|
|
6
|
+
prefilledInfos: () => readonly ["studentProfile", "prefilledInfo"];
|
|
7
|
+
prefilledInfo: (studentId: string) => readonly ["studentProfile", "prefilledInfo", string];
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* Hook to fetch student profile by student ID
|
|
11
|
+
*
|
|
12
|
+
* @param studentId - The student's user ID
|
|
13
|
+
* @param enabled - Whether to enable the query (default: true)
|
|
14
|
+
* @returns Query result with student profile data
|
|
15
|
+
*/
|
|
16
|
+
export declare function useStudentProfile(studentId: string | null, enabled?: boolean): import("@tanstack/react-query").UseQueryResult<StudentProfile | undefined, Error>;
|
|
17
|
+
/**
|
|
18
|
+
* Hook to fetch student prefilled information (application cycle, grade, school, etc.)
|
|
19
|
+
*
|
|
20
|
+
* @param studentId - The student's user ID
|
|
21
|
+
* @param enabled - Whether to enable the query (default: true)
|
|
22
|
+
* @returns Query result with prefilled info including applicationCycle, currentGrade, etc.
|
|
23
|
+
*/
|
|
24
|
+
export declare function useStudentPrefilledInfo(studentId: string | null, enabled?: boolean): import("@tanstack/react-query").UseQueryResult<StudentPrefilledInfo | undefined, Error>;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
"use client";
|
|
3
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
4
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
5
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
6
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
7
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
8
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
9
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
10
|
+
});
|
|
11
|
+
};
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.studentProfileKeys = void 0;
|
|
14
|
+
exports.useStudentProfile = useStudentProfile;
|
|
15
|
+
exports.useStudentPrefilledInfo = useStudentPrefilledInfo;
|
|
16
|
+
const react_query_1 = require("@tanstack/react-query");
|
|
17
|
+
const provider_1 = require("../provider");
|
|
18
|
+
// Query keys
|
|
19
|
+
exports.studentProfileKeys = {
|
|
20
|
+
all: ["studentProfile"],
|
|
21
|
+
profiles: () => [...exports.studentProfileKeys.all, "profile"],
|
|
22
|
+
profile: (studentId) => [...exports.studentProfileKeys.profiles(), studentId],
|
|
23
|
+
prefilledInfos: () => [...exports.studentProfileKeys.all, "prefilledInfo"],
|
|
24
|
+
prefilledInfo: (studentId) => [...exports.studentProfileKeys.prefilledInfos(), studentId],
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Hook to fetch student profile by student ID
|
|
28
|
+
*
|
|
29
|
+
* @param studentId - The student's user ID
|
|
30
|
+
* @param enabled - Whether to enable the query (default: true)
|
|
31
|
+
* @returns Query result with student profile data
|
|
32
|
+
*/
|
|
33
|
+
function useStudentProfile(studentId, enabled = true) {
|
|
34
|
+
const client = (0, provider_1.useCrimsonClient)();
|
|
35
|
+
return (0, react_query_1.useQuery)({
|
|
36
|
+
queryKey: exports.studentProfileKeys.profile(studentId || ""),
|
|
37
|
+
queryFn: () => __awaiter(this, void 0, void 0, function* () {
|
|
38
|
+
if (!studentId) {
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
return client.studentProfile.getProfile(studentId);
|
|
42
|
+
}),
|
|
43
|
+
enabled: enabled && !!studentId,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Hook to fetch student prefilled information (application cycle, grade, school, etc.)
|
|
48
|
+
*
|
|
49
|
+
* @param studentId - The student's user ID
|
|
50
|
+
* @param enabled - Whether to enable the query (default: true)
|
|
51
|
+
* @returns Query result with prefilled info including applicationCycle, currentGrade, etc.
|
|
52
|
+
*/
|
|
53
|
+
function useStudentPrefilledInfo(studentId, enabled = true) {
|
|
54
|
+
const client = (0, provider_1.useCrimsonClient)();
|
|
55
|
+
return (0, react_query_1.useQuery)({
|
|
56
|
+
queryKey: exports.studentProfileKeys.prefilledInfo(studentId || ""),
|
|
57
|
+
queryFn: () => __awaiter(this, void 0, void 0, function* () {
|
|
58
|
+
if (!studentId) {
|
|
59
|
+
return undefined;
|
|
60
|
+
}
|
|
61
|
+
return client.studentProfile.getPrefilledInfo(studentId);
|
|
62
|
+
}),
|
|
63
|
+
enabled: enabled && !!studentId,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { Task, PaginatedResult } from "../../core/types";
|
|
2
|
+
import type { TaskFilters } from "../../core/tasks";
|
|
3
|
+
export declare const taskKeys: {
|
|
4
|
+
all: readonly ["tasks"];
|
|
5
|
+
lists: () => readonly ["tasks", "list"];
|
|
6
|
+
list: (missionId: string) => readonly ["tasks", "list", string];
|
|
7
|
+
infinite: (roadmapId: string, userId: string, filters?: Omit<TaskFilters, "start" | "limit">) => readonly ["tasks", "infinite", string, string, Omit<TaskFilters, "start" | "limit"> | undefined];
|
|
8
|
+
details: () => readonly ["tasks", "detail"];
|
|
9
|
+
detail: (id: string) => readonly ["tasks", "detail", string];
|
|
10
|
+
};
|
|
11
|
+
export declare function useTasks(missionId: string | null, enabled: boolean): import("@tanstack/react-query").UseQueryResult<Task[], Error>;
|
|
12
|
+
export declare function useAllUserTasks(missionLinkIds: string[], enabled: boolean): import("@tanstack/react-query").UseQueryResult<Task[], Error>;
|
|
13
|
+
export declare function useTasksByRoadmapId(roadmapId: string | null, userId: string | null, enabled: boolean): import("@tanstack/react-query").UseQueryResult<Task[], Error>;
|
|
14
|
+
/**
|
|
15
|
+
* Infinite query hook for paginated task loading (requires roadmapId)
|
|
16
|
+
*/
|
|
17
|
+
export declare function useTasksInfinite(roadmapId: string | null, userId: string | null, filters?: Omit<TaskFilters, "start" | "limit">, options?: {
|
|
18
|
+
enabled?: boolean;
|
|
19
|
+
pageSize?: number;
|
|
20
|
+
}): import("@tanstack/react-query").UseInfiniteQueryResult<import("@tanstack/react-query").InfiniteData<PaginatedResult<Task>, unknown>, Error>;
|
|
21
|
+
export declare function useCreateTask(): import("@tanstack/react-query").UseMutationResult<Task, Error, Partial<Task>, unknown>;
|
|
22
|
+
export declare function useUpdateTask(): import("@tanstack/react-query").UseMutationResult<Task, Error, {
|
|
23
|
+
id: string;
|
|
24
|
+
data: Partial<Task>;
|
|
25
|
+
}, unknown>;
|
|
26
|
+
export declare function useDeleteTask(): import("@tanstack/react-query").UseMutationResult<void, Error, string, unknown>;
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
"use client";
|
|
3
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
4
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
5
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
6
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
7
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
8
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
9
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
10
|
+
});
|
|
11
|
+
};
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.taskKeys = void 0;
|
|
14
|
+
exports.useTasks = useTasks;
|
|
15
|
+
exports.useAllUserTasks = useAllUserTasks;
|
|
16
|
+
exports.useTasksByRoadmapId = useTasksByRoadmapId;
|
|
17
|
+
exports.useTasksInfinite = useTasksInfinite;
|
|
18
|
+
exports.useCreateTask = useCreateTask;
|
|
19
|
+
exports.useUpdateTask = useUpdateTask;
|
|
20
|
+
exports.useDeleteTask = useDeleteTask;
|
|
21
|
+
const react_query_1 = require("@tanstack/react-query");
|
|
22
|
+
const provider_1 = require("../provider");
|
|
23
|
+
// Query keys
|
|
24
|
+
exports.taskKeys = {
|
|
25
|
+
all: ["tasks"],
|
|
26
|
+
lists: () => [...exports.taskKeys.all, "list"],
|
|
27
|
+
list: (missionId) => [...exports.taskKeys.lists(), missionId],
|
|
28
|
+
infinite: (roadmapId, userId, filters) => [...exports.taskKeys.all, "infinite", roadmapId, userId, filters],
|
|
29
|
+
details: () => [...exports.taskKeys.all, "detail"],
|
|
30
|
+
detail: (id) => [...exports.taskKeys.details(), id],
|
|
31
|
+
};
|
|
32
|
+
function useTasks(missionId, enabled) {
|
|
33
|
+
const client = (0, provider_1.useCrimsonClient)();
|
|
34
|
+
return (0, react_query_1.useQuery)({
|
|
35
|
+
queryKey: exports.taskKeys.list(missionId || ""),
|
|
36
|
+
queryFn: () => __awaiter(this, void 0, void 0, function* () {
|
|
37
|
+
if (!missionId) {
|
|
38
|
+
throw new Error("Missing missionId");
|
|
39
|
+
}
|
|
40
|
+
// Without pagination params, list() returns Task[]
|
|
41
|
+
return (yield client.tasks.list({ missionId }));
|
|
42
|
+
}),
|
|
43
|
+
enabled: !!missionId && enabled,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
function useAllUserTasks(missionLinkIds, enabled) {
|
|
47
|
+
const client = (0, provider_1.useCrimsonClient)();
|
|
48
|
+
return (0, react_query_1.useQuery)({
|
|
49
|
+
queryKey: [
|
|
50
|
+
...exports.taskKeys.all,
|
|
51
|
+
"missionLinks",
|
|
52
|
+
missionLinkIds.sort().join(","),
|
|
53
|
+
],
|
|
54
|
+
queryFn: () => __awaiter(this, void 0, void 0, function* () {
|
|
55
|
+
if (!missionLinkIds || missionLinkIds.length === 0) {
|
|
56
|
+
return [];
|
|
57
|
+
}
|
|
58
|
+
// Without pagination params, list() returns Task[]
|
|
59
|
+
return (yield client.tasks.list({ missionLinkIds }));
|
|
60
|
+
}),
|
|
61
|
+
enabled: enabled && missionLinkIds.length > 0,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
function useTasksByRoadmapId(roadmapId, userId, enabled) {
|
|
65
|
+
const client = (0, provider_1.useCrimsonClient)();
|
|
66
|
+
return (0, react_query_1.useQuery)({
|
|
67
|
+
queryKey: [...exports.taskKeys.all, "roadmap", roadmapId, userId],
|
|
68
|
+
queryFn: () => __awaiter(this, void 0, void 0, function* () {
|
|
69
|
+
if (!roadmapId || !userId) {
|
|
70
|
+
return [];
|
|
71
|
+
}
|
|
72
|
+
// Without pagination params, list() returns Task[]
|
|
73
|
+
return (yield client.tasks.list({ roadmapId, userId }));
|
|
74
|
+
}),
|
|
75
|
+
enabled: !!roadmapId && !!userId && enabled,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Infinite query hook for paginated task loading (requires roadmapId)
|
|
80
|
+
*/
|
|
81
|
+
function useTasksInfinite(roadmapId, userId, filters, options) {
|
|
82
|
+
var _a, _b;
|
|
83
|
+
const client = (0, provider_1.useCrimsonClient)();
|
|
84
|
+
const enabled = (_a = options === null || options === void 0 ? void 0 : options.enabled) !== null && _a !== void 0 ? _a : true;
|
|
85
|
+
const pageSize = (_b = options === null || options === void 0 ? void 0 : options.pageSize) !== null && _b !== void 0 ? _b : 20;
|
|
86
|
+
return (0, react_query_1.useInfiniteQuery)({
|
|
87
|
+
queryKey: exports.taskKeys.infinite(roadmapId || "", userId || "", filters),
|
|
88
|
+
queryFn: (_a) => __awaiter(this, [_a], void 0, function* ({ pageParam = 0 }) {
|
|
89
|
+
if (!roadmapId || !userId) {
|
|
90
|
+
throw new Error("Missing roadmapId or userId");
|
|
91
|
+
}
|
|
92
|
+
return client.tasks.listPaginated(roadmapId, userId, filters, {
|
|
93
|
+
start: pageParam,
|
|
94
|
+
limit: pageSize,
|
|
95
|
+
});
|
|
96
|
+
}),
|
|
97
|
+
initialPageParam: 0,
|
|
98
|
+
getNextPageParam: (lastPage) => {
|
|
99
|
+
if (!(lastPage === null || lastPage === void 0 ? void 0 : lastPage.pagination))
|
|
100
|
+
return undefined;
|
|
101
|
+
return lastPage.pagination.hasMore
|
|
102
|
+
? lastPage.pagination.start + lastPage.pagination.limit
|
|
103
|
+
: undefined;
|
|
104
|
+
},
|
|
105
|
+
enabled: !!roadmapId && !!userId && enabled,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
function useCreateTask() {
|
|
109
|
+
const client = (0, provider_1.useCrimsonClient)();
|
|
110
|
+
const queryClient = (0, react_query_1.useQueryClient)();
|
|
111
|
+
return (0, react_query_1.useMutation)({
|
|
112
|
+
mutationFn: (data) => client.tasks.create(data),
|
|
113
|
+
onSuccess: () => {
|
|
114
|
+
queryClient.invalidateQueries({ queryKey: exports.taskKeys.all });
|
|
115
|
+
},
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
function useUpdateTask() {
|
|
119
|
+
const client = (0, provider_1.useCrimsonClient)();
|
|
120
|
+
const queryClient = (0, react_query_1.useQueryClient)();
|
|
121
|
+
return (0, react_query_1.useMutation)({
|
|
122
|
+
mutationFn: ({ id, data }) => client.tasks.update(id, data),
|
|
123
|
+
onSuccess: () => {
|
|
124
|
+
queryClient.invalidateQueries({ queryKey: exports.taskKeys.all });
|
|
125
|
+
},
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
function useDeleteTask() {
|
|
129
|
+
const client = (0, provider_1.useCrimsonClient)();
|
|
130
|
+
const queryClient = (0, react_query_1.useQueryClient)();
|
|
131
|
+
return (0, react_query_1.useMutation)({
|
|
132
|
+
mutationFn: (id) => client.tasks.delete(id),
|
|
133
|
+
onSuccess: () => {
|
|
134
|
+
queryClient.invalidateQueries({ queryKey: exports.taskKeys.all });
|
|
135
|
+
},
|
|
136
|
+
});
|
|
137
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { User } from "../../core/types";
|
|
2
|
+
export declare const userKeys: {
|
|
3
|
+
all: readonly ["users"];
|
|
4
|
+
details: () => readonly ["users", "detail"];
|
|
5
|
+
detail: (id: string) => readonly ["users", "detail", string];
|
|
6
|
+
list: (ids: string[]) => readonly ["users", "list", string];
|
|
7
|
+
};
|
|
8
|
+
export declare function useUsers(userIds: string[], enabled?: boolean): import("@tanstack/react-query").UseQueryResult<User[], Error>;
|
|
9
|
+
export declare function useUser(userId: string | null, enabled?: boolean): import("@tanstack/react-query").UseQueryResult<User | undefined, Error>;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
"use client";
|
|
3
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
4
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
5
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
6
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
7
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
8
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
9
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
10
|
+
});
|
|
11
|
+
};
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.userKeys = void 0;
|
|
14
|
+
exports.useUsers = useUsers;
|
|
15
|
+
exports.useUser = useUser;
|
|
16
|
+
const react_query_1 = require("@tanstack/react-query");
|
|
17
|
+
const provider_1 = require("../provider");
|
|
18
|
+
// Query keys
|
|
19
|
+
exports.userKeys = {
|
|
20
|
+
all: ["users"],
|
|
21
|
+
details: () => [...exports.userKeys.all, "detail"],
|
|
22
|
+
detail: (id) => [...exports.userKeys.details(), id],
|
|
23
|
+
list: (ids) => [...exports.userKeys.all, "list", ids.sort().join(",")],
|
|
24
|
+
};
|
|
25
|
+
function useUsers(userIds, enabled = true) {
|
|
26
|
+
const client = (0, provider_1.useCrimsonClient)();
|
|
27
|
+
return (0, react_query_1.useQuery)({
|
|
28
|
+
queryKey: exports.userKeys.list(userIds),
|
|
29
|
+
queryFn: () => __awaiter(this, void 0, void 0, function* () {
|
|
30
|
+
if (!userIds || userIds.length === 0) {
|
|
31
|
+
return [];
|
|
32
|
+
}
|
|
33
|
+
return client.users.getByIds(userIds);
|
|
34
|
+
}),
|
|
35
|
+
enabled: enabled && userIds.length > 0,
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
function useUser(userId, enabled = true) {
|
|
39
|
+
const client = (0, provider_1.useCrimsonClient)();
|
|
40
|
+
return (0, react_query_1.useQuery)({
|
|
41
|
+
queryKey: exports.userKeys.detail(userId || ""),
|
|
42
|
+
queryFn: () => __awaiter(this, void 0, void 0, function* () {
|
|
43
|
+
if (!userId) {
|
|
44
|
+
return undefined;
|
|
45
|
+
}
|
|
46
|
+
return client.users.getById(userId);
|
|
47
|
+
}),
|
|
48
|
+
enabled: enabled && !!userId,
|
|
49
|
+
});
|
|
50
|
+
}
|