mirror of
https://github.com/bitwarden/browser.git
synced 2024-11-24 12:06:15 +01:00
AC-2401 Migrate sponsored families component (#8874)
* AC-2401 Migrate sponsored families component * AC-2401 Removed unused method
This commit is contained in:
parent
091c8ccd46
commit
4e9db9057b
@ -3,103 +3,86 @@
|
||||
<bit-container>
|
||||
<ng-container *ngIf="loading">
|
||||
<i class="bwi bwi-spinner bwi-spin text-muted" title="{{ 'loading' | i18n }}"></i>
|
||||
<span class="sr-only">{{ "loading" | i18n }}</span>
|
||||
<span class="tw-sr-only">{{ "loading" | i18n }}</span>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="!loading">
|
||||
<p>
|
||||
<p bitTypography="body1">
|
||||
{{ "sponsoredFamiliesEligible" | i18n }}
|
||||
</p>
|
||||
<div>
|
||||
<div bitTypography="body1">
|
||||
{{ "sponsoredFamiliesInclude" | i18n }}:
|
||||
<ul class="inset-list">
|
||||
<ul class="tw-list-outside">
|
||||
<li>{{ "sponsoredFamiliesPremiumAccess" | i18n }}</li>
|
||||
<li>{{ "sponsoredFamiliesSharedCollections" | i18n }}</li>
|
||||
</ul>
|
||||
</div>
|
||||
<form
|
||||
#form
|
||||
(ngSubmit)="submit()"
|
||||
[appApiAction]="formPromise"
|
||||
[formGroup]="sponsorshipForm"
|
||||
ngNativeValidate
|
||||
*ngIf="anyOrgsAvailable$ | async"
|
||||
>
|
||||
<div class="form-group col-7">
|
||||
<label for="availableSponsorshipOrg">{{ "familiesSponsoringOrgSelect" | i18n }}</label>
|
||||
<select
|
||||
id="availableSponsorshipOrg"
|
||||
name="Available Sponsorship Organization"
|
||||
formControlName="selectedSponsorshipOrgId"
|
||||
class="form-control"
|
||||
required
|
||||
>
|
||||
<option disabled="true" value="">-- {{ "select" | i18n }} --</option>
|
||||
<option *ngFor="let o of availableSponsorshipOrgs$ | async" [ngValue]="o.id">
|
||||
{{ o.name }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group col-7">
|
||||
<label for="sponsorshipEmail">{{ "sponsoredFamiliesEmail" | i18n }}:</label>
|
||||
<input
|
||||
id="sponsorshipEmail"
|
||||
class="form-control"
|
||||
inputmode="email"
|
||||
formControlName="sponsorshipEmail"
|
||||
name="sponsorshipEmail"
|
||||
required
|
||||
[attr.aria-invalid]="sponsorshipEmailControl.invalid"
|
||||
/>
|
||||
<small
|
||||
aria-errormessage="sponsorshipEmail"
|
||||
*ngIf="sponsorshipEmailControl.errors?.notAllowedValue"
|
||||
class="error-inline"
|
||||
role="alert"
|
||||
>
|
||||
<i class="bwi bwi-error" aria-hidden="true"></i>
|
||||
{{ "cannotSponsorSelf" | i18n }}
|
||||
</small>
|
||||
<small
|
||||
aria-errormessage="sponsorshipEmail"
|
||||
*ngIf="sponsorshipEmailControl.errors?.email"
|
||||
class="error-inline"
|
||||
role="alert"
|
||||
>
|
||||
<i class="bwi bwi-error" aria-hidden="true"></i>
|
||||
{{ "invalidEmail" | i18n }}
|
||||
</small>
|
||||
</div>
|
||||
<div class="form-group col-7">
|
||||
<button class="btn btn-primary btn-submit mt-2" type="submit" [disabled]="form.loading">
|
||||
<i class="bwi bwi-spinner bwi-spin" title="{{ 'loading' | i18n }}" aria-hidden="true"></i>
|
||||
<span>{{ "redeem" | i18n }}</span>
|
||||
</button>
|
||||
<form [formGroup]="sponsorshipForm" [bitSubmit]="submit" *ngIf="anyOrgsAvailable$ | async">
|
||||
<div class="tw-grid tw-grid-cols-12 tw-gap-4">
|
||||
<div class="tw-col-span-7">
|
||||
<bit-form-field>
|
||||
<bit-label>{{ "familiesSponsoringOrgSelect" | i18n }}</bit-label>
|
||||
<bit-select
|
||||
id="availableSponsorshipOrg"
|
||||
name="Available Sponsorship Organization"
|
||||
formControlName="selectedSponsorshipOrgId"
|
||||
>
|
||||
<bit-option
|
||||
[disabled]="true"
|
||||
[value]=""
|
||||
[label]="'--' + ('select' | i18n) + '--'"
|
||||
></bit-option>
|
||||
<bit-option
|
||||
*ngFor="let o of availableSponsorshipOrgs$ | async"
|
||||
[value]="o.id"
|
||||
[label]="o.name"
|
||||
></bit-option>
|
||||
</bit-select>
|
||||
</bit-form-field>
|
||||
</div>
|
||||
<div class="tw-col-span-7">
|
||||
<bit-form-field>
|
||||
<bit-label>{{ "sponsoredFamiliesEmail" | i18n }}:</bit-label>
|
||||
<input
|
||||
bitInput
|
||||
inputmode="email"
|
||||
formControlName="sponsorshipEmail"
|
||||
[attr.aria-invalid]="sponsorshipEmailControl.invalid"
|
||||
/>
|
||||
</bit-form-field>
|
||||
</div>
|
||||
<div class="tw-col-span-7">
|
||||
<button bitButton bitFormButton buttonType="primary" type="submit">
|
||||
{{ "redeem" | i18n }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<ng-container *ngIf="anyActiveSponsorships$ | async">
|
||||
<div class="border-bottom">
|
||||
<table class="table table-hover table-list">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ "recipient" | i18n }}</th>
|
||||
<th>{{ "sponsoringOrg" | i18n }}</th>
|
||||
<th>{{ "status" | i18n }}</th>
|
||||
<th></th>
|
||||
<bit-table>
|
||||
<ng-container header>
|
||||
<tr>
|
||||
<th bitCell>{{ "recipient" | i18n }}</th>
|
||||
<th bitCell>{{ "sponsoringOrg" | i18n }}</th>
|
||||
<th bitCell>{{ "status" | i18n }}</th>
|
||||
<th bitCell></th>
|
||||
</tr>
|
||||
</ng-container>
|
||||
<ng-template body alignContent="middle">
|
||||
<ng-container *ngFor="let o of activeSponsorshipOrgs$ | async">
|
||||
<tr
|
||||
bitRow
|
||||
sponsoring-org-row
|
||||
[sponsoringOrg]="o"
|
||||
[isSelfHosted]="isSelfHosted"
|
||||
(sponsorshipRemoved)="forceReload()"
|
||||
>
|
||||
<hr />
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<ng-container *ngFor="let o of activeSponsorshipOrgs$ | async">
|
||||
<tr
|
||||
sponsoring-org-row
|
||||
[sponsoringOrg]="o"
|
||||
[isSelfHosted]="isSelfHosted"
|
||||
(sponsorshipRemoved)="forceReload()"
|
||||
></tr>
|
||||
</ng-container>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<small>{{ "sponsoredFamiliesLeaveCopy" | i18n }}</small>
|
||||
</ng-container>
|
||||
</ng-template>
|
||||
</bit-table>
|
||||
<hr />
|
||||
<p bitTypography="body2">{{ "sponsoredFamiliesLeaveCopy" | i18n }}</p>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
</bit-container>
|
||||
|
@ -1,8 +1,15 @@
|
||||
import { Component, OnDestroy, OnInit } from "@angular/core";
|
||||
import { FormBuilder, FormControl, FormGroup, Validators } from "@angular/forms";
|
||||
import {
|
||||
FormBuilder,
|
||||
FormControl,
|
||||
FormGroup,
|
||||
Validators,
|
||||
AbstractControl,
|
||||
AsyncValidatorFn,
|
||||
ValidationErrors,
|
||||
} from "@angular/forms";
|
||||
import { firstValueFrom, map, Observable, Subject, takeUntil } from "rxjs";
|
||||
|
||||
import { notAllowedValueAsync } from "@bitwarden/angular/admin-console/validators/not-allowed-value-async.validator";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||
@ -50,9 +57,9 @@ export class SponsoredFamiliesComponent implements OnInit, OnDestroy {
|
||||
validators: [Validators.required],
|
||||
}),
|
||||
sponsorshipEmail: new FormControl("", {
|
||||
validators: [Validators.email],
|
||||
validators: [Validators.email, Validators.required],
|
||||
asyncValidators: [
|
||||
notAllowedValueAsync(
|
||||
this.notAllowedValueAsync(
|
||||
() => firstValueFrom(this.accountService.activeAccount$.pipe(map((a) => a?.email))),
|
||||
true,
|
||||
),
|
||||
@ -84,6 +91,15 @@ export class SponsoredFamiliesComponent implements OnInit, OnDestroy {
|
||||
this.anyActiveSponsorships$ = this.activeSponsorshipOrgs$.pipe(map((orgs) => orgs.length > 0));
|
||||
|
||||
this.loading = false;
|
||||
|
||||
this.sponsorshipForm
|
||||
.get("sponsorshipEmail")
|
||||
.valueChanges.pipe(takeUntil(this._destroy))
|
||||
.subscribe((val) => {
|
||||
if (this.sponsorshipEmailControl.hasError("email")) {
|
||||
this.sponsorshipEmailControl.setErrors([{ message: this.i18nService.t("invalidEmail") }]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
@ -91,7 +107,7 @@ export class SponsoredFamiliesComponent implements OnInit, OnDestroy {
|
||||
this._destroy.complete();
|
||||
}
|
||||
|
||||
async submit() {
|
||||
submit = async () => {
|
||||
this.formPromise = this.apiService.postCreateSponsorship(
|
||||
this.sponsorshipForm.value.selectedSponsorshipOrgId,
|
||||
{
|
||||
@ -108,7 +124,7 @@ export class SponsoredFamiliesComponent implements OnInit, OnDestroy {
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
this.resetForm();
|
||||
await this.forceReload();
|
||||
}
|
||||
};
|
||||
|
||||
async forceReload() {
|
||||
this.loading = true;
|
||||
@ -127,4 +143,26 @@ export class SponsoredFamiliesComponent implements OnInit, OnDestroy {
|
||||
get isSelfHosted(): boolean {
|
||||
return this.platformUtilsService.isSelfHost();
|
||||
}
|
||||
|
||||
notAllowedValueAsync(
|
||||
valueGetter: () => Promise<string>,
|
||||
caseInsensitive = false,
|
||||
): AsyncValidatorFn {
|
||||
return async (control: AbstractControl): Promise<ValidationErrors | null> => {
|
||||
let notAllowedValue = await valueGetter();
|
||||
let controlValue = control.value;
|
||||
if (caseInsensitive) {
|
||||
notAllowedValue = notAllowedValue.toLowerCase();
|
||||
controlValue = controlValue.toLowerCase();
|
||||
}
|
||||
|
||||
if (controlValue === notAllowedValue) {
|
||||
return {
|
||||
errors: {
|
||||
message: this.i18nService.t("cannotSponsorSelf"),
|
||||
},
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user