Skip to content

Commit 34da40a

Browse files
authored
feat(clerk-js,shared): Introduce OrganizationDomain and domains within useOrganization (#1569)
* feat(clerk-js): Introduce OrganizationDomain * feat(shared): Fetch domains within useOrganization * chore(shared): Add changeset * chore(clerk-js): Move prepare and attempt verification to OrganizationDomain * test(clerk-js): Update Organization class snapshots * test(clerk-js): Create snapshot test for OrganizationDomain
1 parent da77928 commit 34da40a

File tree

14 files changed

+421
-10
lines changed

14 files changed

+421
-10
lines changed

.changeset/mighty-boxes-reply.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
'@clerk/clerk-js': patch
3+
'@clerk/shared': patch
4+
'@clerk/types': patch
5+
---
6+
7+
Introduces a new resource called OrganizationDomain
8+
9+
+ useOrganization has been updated in order to return a list of domain with the above type

packages/clerk-js/src/core/resources/Organization.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
import type {
22
AddMemberParams,
3+
ClerkPaginatedResponse,
34
ClerkResourceReloadParams,
45
CreateOrganizationParams,
6+
GetDomainsParams,
57
GetMembershipsParams,
68
GetPendingInvitationsParams,
79
InviteMemberParams,
810
InviteMembersParams,
11+
OrganizationDomainJSON,
12+
OrganizationDomainResource,
913
OrganizationInvitationJSON,
1014
OrganizationJSON,
1115
OrganizationMembershipJSON,
@@ -16,7 +20,9 @@ import type {
1620
} from '@clerk/types';
1721

1822
import { unixEpochToDate } from '../../utils/date';
23+
import { convertPageToOffset } from '../../utils/pagesToOffset';
1924
import { BaseResource, OrganizationInvitation, OrganizationMembership } from './internal';
25+
import { OrganizationDomain } from './OrganizationDomain';
2026

2127
export class Organization extends BaseResource implements OrganizationResource {
2228
pathRoot = '/organizations';
@@ -75,6 +81,43 @@ export class Organization extends BaseResource implements OrganizationResource {
7581
});
7682
};
7783

84+
getDomains = async (
85+
getDomainParams?: GetDomainsParams,
86+
): Promise<ClerkPaginatedResponse<OrganizationDomainResource>> => {
87+
return await BaseResource._fetch({
88+
path: `/organizations/${this.id}/domains`,
89+
method: 'GET',
90+
search: convertPageToOffset(getDomainParams) as any,
91+
})
92+
.then(res => {
93+
const { data: invites, total_count } =
94+
res?.response as unknown as ClerkPaginatedResponse<OrganizationDomainJSON>;
95+
96+
return {
97+
total_count,
98+
data: invites.map(domain => new OrganizationDomain(domain)),
99+
};
100+
})
101+
.catch(() => ({
102+
total_count: 0,
103+
data: [],
104+
}));
105+
};
106+
107+
getDomain = async ({ domainId }: { domainId: string }): Promise<OrganizationDomainResource> => {
108+
const json = (
109+
await BaseResource._fetch<OrganizationDomainJSON>({
110+
path: `/organizations/${this.id}/domains/${domainId}`,
111+
method: 'GET',
112+
})
113+
)?.response as unknown as OrganizationDomainJSON;
114+
return new OrganizationDomain(json);
115+
};
116+
117+
createDomain = async (name: string): Promise<OrganizationDomainResource> => {
118+
return OrganizationDomain.create(this.id, { name });
119+
};
120+
78121
getMemberships = async (getMemberhipsParams?: GetMembershipsParams): Promise<OrganizationMembership[]> => {
79122
return await BaseResource._fetch({
80123
path: `/organizations/${this.id}/memberships`,
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { OrganizationDomain } from './internal';
2+
3+
describe('OrganizationDomain', () => {
4+
it('has the same initial properties', () => {
5+
const organization = new OrganizationDomain({
6+
object: 'organization_domain',
7+
id: 'test_domain_id',
8+
name: 'clerk.dev',
9+
organization_id: 'test_org_id',
10+
enrollment_mode: 'manual_invitation',
11+
verification: {
12+
attempts: 1,
13+
expires_at: 12345,
14+
strategy: 'email_code',
15+
status: 'verified',
16+
},
17+
affiliation_email_address: 'some@clerk.dev',
18+
created_at: 12345,
19+
updated_at: 5678,
20+
});
21+
22+
expect(organization).toMatchSnapshot();
23+
});
24+
25+
it('has the same initial nullable properties', () => {
26+
const organization = new OrganizationDomain({
27+
object: 'organization_domain',
28+
id: 'test_domain_id',
29+
name: 'clerk.dev',
30+
organization_id: 'test_org_id',
31+
enrollment_mode: 'manual_invitation',
32+
verification: null,
33+
affiliation_email_address: null,
34+
created_at: 12345,
35+
updated_at: 5678,
36+
});
37+
38+
expect(organization).toMatchSnapshot();
39+
});
40+
});
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
import type {
2+
AttemptAffiliationVerificationParams,
3+
OrganizationDomainJSON,
4+
OrganizationDomainResource,
5+
OrganizationDomainVerification,
6+
OrganizationEnrollmentMode,
7+
PrepareAffiliationVerificationParams,
8+
UpdateOrganizationDomainParams,
9+
} from '@clerk/types';
10+
11+
import { unixEpochToDate } from '../../utils/date';
12+
import { BaseResource } from './Base';
13+
14+
export class OrganizationDomain extends BaseResource implements OrganizationDomainResource {
15+
id!: string;
16+
name!: string;
17+
organizationId!: string;
18+
enrollmentMode!: OrganizationEnrollmentMode;
19+
verification!: OrganizationDomainVerification | null;
20+
affiliationEmailAddress!: string | null;
21+
createdAt!: Date;
22+
updatedAt!: Date;
23+
24+
constructor(data: OrganizationDomainJSON) {
25+
super();
26+
this.fromJSON(data);
27+
}
28+
29+
static async create(organizationId: string, { name }: { name: string }): Promise<OrganizationDomainResource> {
30+
const json = (
31+
await BaseResource._fetch<OrganizationDomainJSON>({
32+
path: `/organizations/${organizationId}/domains`,
33+
method: 'POST',
34+
body: { name } as any,
35+
})
36+
)?.response as unknown as OrganizationDomainJSON;
37+
return new OrganizationDomain(json);
38+
}
39+
40+
prepareDomainAffiliationVerification = async (
41+
params: PrepareAffiliationVerificationParams,
42+
): Promise<OrganizationDomainResource> => {
43+
return this._basePost({
44+
path: `/organizations/${this.organizationId}/domains/${this.id}/prepare_affiliation_verification`,
45+
method: 'POST',
46+
body: params as any,
47+
});
48+
};
49+
50+
attemptAffiliationVerification = async (
51+
params: AttemptAffiliationVerificationParams,
52+
): Promise<OrganizationDomainResource> => {
53+
return this._basePost({
54+
path: `/organizations/${this.organizationId}/domains/${this.id}/attempt_affiliation_verification`,
55+
method: 'POST',
56+
body: params as any,
57+
});
58+
};
59+
60+
update = (params: UpdateOrganizationDomainParams): Promise<OrganizationDomainResource> => {
61+
return this._basePatch({
62+
method: 'PATCH',
63+
path: `/organizations/${this.organizationId}/domains/${this.id}`,
64+
body: params,
65+
});
66+
};
67+
68+
delete = (): Promise<void> => {
69+
return this._baseDelete({
70+
path: `/organizations/${this.organizationId}/domains/${this.id}`,
71+
});
72+
};
73+
74+
protected fromJSON(data: OrganizationDomainJSON | null): this {
75+
if (data) {
76+
this.id = data.id;
77+
this.name = data.name;
78+
this.organizationId = data.organization_id;
79+
this.enrollmentMode = data.enrollment_mode;
80+
this.affiliationEmailAddress = data.affiliation_email_address;
81+
if (data.verification) {
82+
this.verification = {
83+
status: data.verification.status,
84+
strategy: data.verification.strategy,
85+
attempts: data.verification.attempts,
86+
expiresAt: unixEpochToDate(data.verification.expires_at),
87+
};
88+
} else {
89+
this.verification = null;
90+
}
91+
}
92+
return this;
93+
}
94+
}

packages/clerk-js/src/core/resources/UserOrganizationInvitation.ts

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,7 @@ import { BaseResource } from './internal';
1414
export class UserOrganizationInvitation extends BaseResource implements UserOrganizationInvitationResource {
1515
id!: string;
1616
emailAddress!: string;
17-
publicOrganizationData!: {
18-
hasImage: boolean;
19-
imageUrl: string;
20-
name: string;
21-
id: string;
22-
slug: string;
23-
};
17+
publicOrganizationData!: UserOrganizationInvitationResource['publicOrganizationData'];
2418
publicMetadata: OrganizationInvitationPublicMetadata = {};
2519
status!: OrganizationInvitationStatus;
2620
role!: MembershipRole;

packages/clerk-js/src/core/resources/__snapshots__/Organization.test.ts.snap

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,11 @@ exports[`Organization has the same initial properties 1`] = `
44
Organization {
55
"addMember": [Function],
66
"adminDeleteEnabled": true,
7+
"createDomain": [Function],
78
"createdAt": 1970-01-01T00:00:12.345Z,
89
"destroy": [Function],
10+
"getDomain": [Function],
11+
"getDomains": [Function],
912
"getMemberships": [Function],
1013
"getPendingInvitations": [Function],
1114
"hasImage": true,
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`OrganizationDomain has the same initial nullable properties 1`] = `
4+
OrganizationDomain {
5+
"affiliationEmailAddress": null,
6+
"attemptAffiliationVerification": [Function],
7+
"delete": [Function],
8+
"enrollmentMode": "manual_invitation",
9+
"id": "test_domain_id",
10+
"name": "clerk.dev",
11+
"organizationId": "test_org_id",
12+
"pathRoot": "",
13+
"prepareDomainAffiliationVerification": [Function],
14+
"update": [Function],
15+
"verification": null,
16+
}
17+
`;
18+
19+
exports[`OrganizationDomain has the same initial properties 1`] = `
20+
OrganizationDomain {
21+
"affiliationEmailAddress": "some@clerk.dev",
22+
"attemptAffiliationVerification": [Function],
23+
"delete": [Function],
24+
"enrollmentMode": "manual_invitation",
25+
"id": "test_domain_id",
26+
"name": "clerk.dev",
27+
"organizationId": "test_org_id",
28+
"pathRoot": "",
29+
"prepareDomainAffiliationVerification": [Function],
30+
"update": [Function],
31+
"verification": {
32+
"attempts": 1,
33+
"expiresAt": 1970-01-01T00:00:12.345Z,
34+
"status": "verified",
35+
"strategy": "email_code",
36+
},
37+
}
38+
`;

packages/clerk-js/src/core/resources/__snapshots__/OrganizationMembership.test.ts.snap

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,11 @@ OrganizationMembership {
88
"organization": Organization {
99
"addMember": [Function],
1010
"adminDeleteEnabled": true,
11+
"createDomain": [Function],
1112
"createdAt": 1970-01-01T00:00:12.345Z,
1213
"destroy": [Function],
14+
"getDomain": [Function],
15+
"getDomains": [Function],
1316
"getMemberships": [Function],
1417
"getPendingInvitations": [Function],
1518
"hasImage": true,

packages/clerk-js/src/core/resources/internal.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ export * from './IdentificationLink';
1313
export * from './Image';
1414
export * from './PhoneNumber';
1515
export * from './Organization';
16+
export * from './OrganizationDomain';
1617
export * from './OrganizationInvitation';
1718
export * from './OrganizationMembership';
1819
export * from './SamlAccount';

0 commit comments

Comments
 (0)