1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-11 22:03:36 +00:00

[PM-21109] Resend invitation button not responsive when clicked (#14603)

* Resolve the resend email bug

* Resolve the resend invite option for Active sponsorship

* Resolve the lint error

* Rename the o variable  properly
This commit is contained in:
cyprain-okeke
2025-05-05 16:19:11 +01:00
committed by GitHub
parent af40ff26a2
commit 28f00e5533
7 changed files with 38 additions and 19 deletions

View File

@@ -39,12 +39,14 @@
</tr> </tr>
</ng-container> </ng-container>
<ng-template body alignContent="middle"> <ng-template body alignContent="middle">
@for (o of sponsoredFamilies; let i = $index; track i) { @for (sponsoredFamily of sponsoredFamilies; let i = $index; track i) {
<ng-container> <ng-container>
<tr bitRow> <tr bitRow>
<td bitCell>{{ o.friendlyName }}</td> <td bitCell>{{ sponsoredFamily.friendlyName }}</td>
<td bitCell [class]="o.statusClass">{{ o.statusMessage }}</td> <td bitCell [class]="sponsoredFamily.statusClass">
<td bitCell>{{ o.notes }}</td> {{ sponsoredFamily.statusMessage }}
</td>
<td bitCell>{{ sponsoredFamily.notes }}</td>
<td bitCell> <td bitCell>
<button <button
type="button" type="button"
@@ -58,7 +60,8 @@
type="button" type="button"
bitMenuItem bitMenuItem
[attr.aria-label]="'resendEmailLabel' | i18n" [attr.aria-label]="'resendEmailLabel' | i18n"
(click)="resendEmail(o)" *ngIf="!isSelfHosted && !sponsoredFamily.validUntil"
(click)="resendEmail(sponsoredFamily)"
> >
<i aria-hidden="true" class="bwi bwi-envelope"></i> <i aria-hidden="true" class="bwi bwi-envelope"></i>
{{ "resendInvitation" | i18n }} {{ "resendInvitation" | i18n }}
@@ -70,7 +73,7 @@
type="button" type="button"
bitMenuItem bitMenuItem
[attr.aria-label]="'revokeAccountMessage' | i18n" [attr.aria-label]="'revokeAccountMessage' | i18n"
(click)="removeSponsorship(o)" (click)="removeSponsorship(sponsoredFamily)"
> >
<i aria-hidden="true" class="bwi bwi-close tw-text-danger"></i> <i aria-hidden="true" class="bwi bwi-close tw-text-danger"></i>
<span class="tw-text-danger pl-1">{{ "remove" | i18n }}</span> <span class="tw-text-danger pl-1">{{ "remove" | i18n }}</span>

View File

@@ -145,7 +145,10 @@ export class FreeBitwardenFamiliesComponent implements OnInit {
} }
async resendEmail(sponsorship: OrganizationSponsorshipInvitesResponse) { async resendEmail(sponsorship: OrganizationSponsorshipInvitesResponse) {
await this.apiService.postResendSponsorshipOffer(sponsorship.sponsoringOrganizationUserId); await this.organizationSponsorshipApiService.postResendSponsorshipOffer(
this.organizationId,
sponsorship.friendlyName,
);
this.toastService.showToast({ this.toastService.showToast({
variant: "success", variant: "success",
title: undefined, title: undefined,

View File

@@ -10,6 +10,7 @@ import { PolicyType } from "@bitwarden/common/admin-console/enums";
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { getUserId } from "@bitwarden/common/auth/services/account.service"; import { getUserId } from "@bitwarden/common/auth/services/account.service";
import { OrganizationSponsorshipApiServiceAbstraction } from "@bitwarden/common/billing/abstractions/organizations/organization-sponsorship-api.service.abstraction";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
import { DialogService, ToastService } from "@bitwarden/components"; import { DialogService, ToastService } from "@bitwarden/components";
@@ -37,6 +38,7 @@ export class SponsoringOrgRowComponent implements OnInit {
private toastService: ToastService, private toastService: ToastService,
private policyService: PolicyService, private policyService: PolicyService,
private accountService: AccountService, private accountService: AccountService,
private organizationSponsorshipApiService: OrganizationSponsorshipApiServiceAbstraction,
) {} ) {}
async ngOnInit() { async ngOnInit() {
@@ -73,7 +75,10 @@ export class SponsoringOrgRowComponent implements OnInit {
} }
async resendEmail() { async resendEmail() {
await this.apiService.postResendSponsorshipOffer(this.sponsoringOrg.id); await this.organizationSponsorshipApiService.postResendSponsorshipOffer(
this.sponsoringOrg.id,
this.sponsoringOrg.familySponsorshipFriendlyName,
);
this.toastService.showToast({ this.toastService.showToast({
variant: "success", variant: "success",
title: null, title: null,

View File

@@ -490,7 +490,6 @@ export abstract class ApiService {
sponsorshipToken: string, sponsorshipToken: string,
request: OrganizationSponsorshipRedeemRequest, request: OrganizationSponsorshipRedeemRequest,
) => Promise<void>; ) => Promise<void>;
postResendSponsorshipOffer: (sponsoringOrgId: string) => Promise<void>;
getMasterKeyFromKeyConnector: (keyConnectorUrl: string) => Promise<KeyConnectorUserKeyResponse>; getMasterKeyFromKeyConnector: (keyConnectorUrl: string) => Promise<KeyConnectorUserKeyResponse>;
postUserKeyToKeyConnector: ( postUserKeyToKeyConnector: (

View File

@@ -5,4 +5,9 @@ export abstract class OrganizationSponsorshipApiServiceAbstraction {
abstract getOrganizationSponsorship( abstract getOrganizationSponsorship(
sponsoredOrgId: string, sponsoredOrgId: string,
): Promise<ListResponse<OrganizationSponsorshipInvitesResponse>>; ): Promise<ListResponse<OrganizationSponsorshipInvitesResponse>>;
abstract postResendSponsorshipOffer(
sponsoringOrgId: string,
friendlyName?: string,
): Promise<void>;
} }

View File

@@ -19,4 +19,18 @@ export class OrganizationSponsorshipApiService
); );
return new ListResponse(r, OrganizationSponsorshipInvitesResponse); return new ListResponse(r, OrganizationSponsorshipInvitesResponse);
} }
async postResendSponsorshipOffer(
sponsoringOrgId: string,
sponsoredFriendlyName?: string,
): Promise<void> {
let url = "/organization/sponsorship/" + sponsoringOrgId + "/families-for-enterprise/resend";
// Add the query parameter if sponsoredOrgUserId is provided
if (sponsoredFriendlyName) {
url += `?sponsoredFriendlyName=${encodeURIComponent(sponsoredFriendlyName)}`;
}
return await this.apiService.send("POST", url, null, true, false);
}
} }

View File

@@ -1682,16 +1682,6 @@ export class ApiService implements ApiServiceAbstraction {
); );
} }
async postResendSponsorshipOffer(sponsoringOrgId: string): Promise<void> {
return await this.send(
"POST",
"/organization/sponsorship/" + sponsoringOrgId + "/families-for-enterprise/resend",
null,
true,
false,
);
}
// Keep the running refreshTokenPromise to prevent parallel calls. // Keep the running refreshTokenPromise to prevent parallel calls.
protected refreshToken(): Promise<string> { protected refreshToken(): Promise<string> {
if (this.refreshTokenPromise === undefined) { if (this.refreshTokenPromise === undefined) {