Skip to content

Commit af057d3

Browse files
feat(frontend): expose newUserSignupsAllowed and throw SignupsClosedError from createUserProfile
Adds a `newUserSignupsAllowed` query wrapper and lets the canister-level `createUserProfile` throw a typed `SignupsClosedError` when the backend reports that new sign-ups are closed, so callers can react to that case explicitly.
1 parent fc64c29 commit af057d3

4 files changed

Lines changed: 69 additions & 2 deletions

File tree

src/frontend/src/lib/api/backend.api.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,15 @@ export const getUserProfile = async ({
9898
return getUserProfile({ certified });
9999
};
100100

101+
export const newUserSignupsAllowed = async ({
102+
identity,
103+
certified
104+
}: CanisterApiFunctionParams<QueryParams>): Promise<boolean> => {
105+
const { newUserSignupsAllowed } = await backendCanister({ identity });
106+
107+
return newUserSignupsAllowed({ certified });
108+
};
109+
101110
export const addPendingBtcTransaction = async ({
102111
identity,
103112
...params

src/frontend/src/lib/canisters/backend.canister.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ import type {
4343
UpdateUserTransactionFilterSettings
4444
} from '$lib/types/api';
4545
import type { CreateCanisterOptions } from '$lib/types/canister';
46+
import { SignupsClosedError } from '$lib/types/errors';
4647
import type { BackendExchangeRate } from '$lib/types/exchange';
4748
import { mapBackendUserAgreements } from '$lib/utils/agreements.utils';
4849
import { mapBackendProviderAgreements } from '$lib/utils/provider-agreements.utils';
@@ -101,10 +102,16 @@ export class BackendCanister extends Canister<BackendService> {
101102
return remove_custom_token(token);
102103
};
103104

104-
createUserProfile = (): Promise<CreateUserProfileResponse> => {
105+
createUserProfile = async (): Promise<CreateUserProfileResponse> => {
105106
const { create_user_profile } = this.caller({ certified: true });
106107

107-
return create_user_profile();
108+
const response = await create_user_profile();
109+
110+
if ('Err' in response && 'SignupsClosed' in response.Err) {
111+
throw new SignupsClosedError();
112+
}
113+
114+
return response;
108115
};
109116

110117
getUserProfile = ({ certified }: QueryParams): Promise<GetUserProfileResponse> => {
@@ -113,6 +120,12 @@ export class BackendCanister extends Canister<BackendService> {
113120
return get_user_profile();
114121
};
115122

123+
newUserSignupsAllowed = ({ certified }: QueryParams): Promise<boolean> => {
124+
const { new_user_signups_allowed } = this.caller({ certified });
125+
126+
return new_user_signups_allowed();
127+
};
128+
116129
btcAddPendingTransaction = async ({
117130
txId,
118131
iiDelegationChain,

src/frontend/src/tests/lib/api/backend.api.spec.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
getUserProfile,
1111
getUserTransactions,
1212
listCustomTokens,
13+
newUserSignupsAllowed,
1314
removeCustomToken,
1415
saveUserTransactions,
1516
setCustomToken,
@@ -277,6 +278,38 @@ describe('backend.api', () => {
277278
});
278279
});
279280

281+
describe('newUserSignupsAllowed', () => {
282+
const mockParams: CanisterApiFunctionParams<QueryParams> = {
283+
...baseParams,
284+
certified
285+
};
286+
287+
beforeEach(() => {
288+
backendCanisterMock.newUserSignupsAllowed.mockResolvedValue(true);
289+
});
290+
291+
it('should successfully call newUserSignupsAllowed endpoint', async () => {
292+
const result = await newUserSignupsAllowed(mockParams);
293+
294+
expect(result).toBeTruthy();
295+
expect(backendCanisterMock.newUserSignupsAllowed).toHaveBeenCalledExactlyOnceWith({
296+
certified
297+
});
298+
});
299+
300+
it('should return false when signups are closed', async () => {
301+
backendCanisterMock.newUserSignupsAllowed.mockResolvedValue(false);
302+
303+
const result = await newUserSignupsAllowed(mockParams);
304+
305+
expect(result).toBeFalsy();
306+
});
307+
308+
it('should throw an error if identity is undefined', async () => {
309+
await expect(newUserSignupsAllowed({ ...mockParams, identity: undefined })).rejects.toThrow();
310+
});
311+
});
312+
280313
describe('addPendingBtcTransaction', () => {
281314
const mockParams: CanisterApiFunctionParams<BtcAddPendingTransactionParams> = {
282315
...baseParams,

src/frontend/src/tests/lib/canisters/backend.canister.spec.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,18 @@ describe('backend.canister', () => {
231231
expect(res).toEqual(response);
232232
});
233233

234+
it('should throw SignupsClosedError when backend returns SignupsClosed', async () => {
235+
service.create_user_profile.mockResolvedValue({ Err: { SignupsClosed: null } });
236+
237+
const { createUserProfile } = await createBackendCanister({
238+
serviceOverride: service
239+
});
240+
241+
const { SignupsClosedError } = await import('$lib/types/errors');
242+
243+
await expect(createUserProfile()).rejects.toThrow(SignupsClosedError);
244+
});
245+
234246
it('should throw an error if create_user_profile throws', async () => {
235247
service.create_user_profile.mockImplementation(async () => {
236248
await Promise.resolve();

0 commit comments

Comments
 (0)