Skip to content

Commit a27dcc7

Browse files
feat(frontend): surface signups-closed reason from loadUserProfile (#12621)
# Motivation Let `loadUserProfile` distinguish a closed-sign-ups failure from a generic one, so callers can react to it explicitly. # Changes - `loadUserProfile` returns `{ success: false, err: 'signups-closed' | 'unknown' }`. - On `SignupsClosedError`, skips the generic error toast. # Tests Added tests.
1 parent d205f56 commit a27dcc7

2 files changed

Lines changed: 27 additions & 4 deletions

File tree

src/frontend/src/lib/services/load-user-profile.services.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,13 +61,15 @@ export const loadCertifiedUserProfile = async ({
6161
}
6262
};
6363

64+
export type LoadUserProfileFailureReason = 'signups-closed' | 'unknown';
65+
6466
export const loadUserProfile = async ({
6567
identity,
6668
reload = true
6769
}: {
6870
identity: NullishIdentity;
6971
reload?: boolean;
70-
}): Promise<ResultSuccess> => {
72+
}): Promise<ResultSuccess<LoadUserProfileFailureReason>> => {
7173
// We just want to verify that the store is empty, without being interested in the data.
7274
// So we fetch it imperatively, instead of passing as parameter.
7375
// If it is not empty, and we don't want to reload, we can return early.
@@ -99,12 +101,16 @@ export const loadUserProfile = async ({
99101
loadCertifiedUserProfile({ identity });
100102
}
101103
} catch (err: unknown) {
104+
if (err instanceof SignupsClosedError) {
105+
return { success: false, err: 'signups-closed' };
106+
}
107+
102108
const { settings } = get(i18n);
103109
toastsError({
104110
msg: { text: settings.error.loading_profile },
105111
err
106112
});
107-
return { success: false };
113+
return { success: false, err: 'unknown' };
108114
}
109115

110116
return { success: true };

src/frontend/src/tests/lib/services/load-user-profile.spec.ts

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import type { UserProfile } from '$declarations/backend/backend.did';
22
import * as backendApi from '$lib/api/backend.api';
33
import { loadUserProfile } from '$lib/services/load-user-profile.services';
44
import { userProfileStore } from '$lib/stores/user-profile.store';
5+
import { SignupsClosedError } from '$lib/types/errors';
56
import en from '$tests/mocks/i18n.mock';
67
import { mockIdentity } from '$tests/mocks/identity.mock';
78
import { mockUserProfile } from '$tests/mocks/user-profile.mock';
@@ -122,7 +123,7 @@ describe('load-user-profile.services', () => {
122123

123124
const result = await loadUserProfile({ identity: mockIdentity });
124125

125-
expect(result).toEqual({ success: false });
126+
expect(result).toEqual({ success: false, err: 'unknown' });
126127
});
127128

128129
it('should handle unknown error from getUserProfile', async () => {
@@ -132,7 +133,23 @@ describe('load-user-profile.services', () => {
132133

133134
const result = await loadUserProfile({ identity: mockIdentity });
134135

135-
expect(result).toEqual({ success: false });
136+
expect(result).toEqual({ success: false, err: 'unknown' });
137+
});
138+
139+
it('should surface signups-closed when createUserProfile rejects with SignupsClosedError', async () => {
140+
vi.spyOn(backendApi, 'getUserProfile').mockResolvedValue({ Err: { NotFound: null } });
141+
const createUserProfileSpy = vi
142+
.spyOn(backendApi, 'createUserProfile')
143+
.mockRejectedValue(new SignupsClosedError());
144+
145+
const result = await loadUserProfile({ identity: mockIdentity });
146+
147+
expect(result).toEqual({ success: false, err: 'signups-closed' });
148+
expect(createUserProfileSpy).toHaveBeenCalledWith({
149+
identity: mockIdentity,
150+
nullishIdentityErrorMessage
151+
});
152+
expect(get(userProfileStore)).toBeNull();
136153
});
137154

138155
it('should handle certified profile load failure gracefully', async () => {

0 commit comments

Comments
 (0)